123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159(*
* Copyright (c) 2017 Christiano F. Haesbaert <haesbaert@haesbaert.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openMirage_crypto.Cipher_block.AEStypet=|Plaintext|Aes128_ctr|Aes192_ctr|Aes256_ctr|Aes128_cbc|Aes192_cbc|Aes256_cbc|Chacha20_poly1305letaead=function|Chacha20_poly1305->true|_->falsetypecipher_key=|Plaintext_key|Aes_ctr_keyof(CTR.key*CTR.ctr)|Aes_cbc_keyof(CBC.key*Cstruct.t)|Chacha20_poly1305_keyof(Mirage_crypto.Chacha20.key*Mirage_crypto.Chacha20.key)typekey={cipher:t;cipher_key:cipher_key;}letto_string=function|Plaintext->"none"|Aes128_ctr->"aes128-ctr"|Aes192_ctr->"aes192-ctr"|Aes256_ctr->"aes256-ctr"|Aes128_cbc->"aes128-cbc"|Aes192_cbc->"aes192-cbc"|Aes256_cbc->"aes256-cbc"|Chacha20_poly1305->"chacha20-poly1305@openssh.com"letof_string=function|"none"->OkPlaintext|"aes128-ctr"->OkAes128_ctr|"aes192-ctr"->OkAes192_ctr|"aes256-ctr"->OkAes256_ctr|"aes128-cbc"->OkAes128_cbc|"aes192-cbc"->OkAes192_cbc|"aes256-cbc"->OkAes256_cbc|"chacha20-poly1305@openssh.com"->OkChacha20_poly1305|s->Error("Unknown cipher "^s)letkey_len=function|Plaintext->0|Aes128_ctr->16|Aes192_ctr->24|Aes256_ctr->32|Aes128_cbc->16|Aes192_cbc->24|Aes256_cbc->32|Chacha20_poly1305->64letiv_len=function|Plaintext->0|Aes128_ctr|Aes192_ctr|Aes256_ctr->CTR.block_size|Aes128_cbc|Aes192_cbc|Aes256_cbc->CBC.block_size|Chacha20_poly1305->0letblock_len=function|Plaintext->8|Aes128_ctr|Aes192_ctr|Aes256_ctr->CTR.block_size|Aes128_cbc|Aes192_cbc|Aes256_cbc->CBC.block_size|Chacha20_poly1305->8letmac_len=function|Chacha20_poly1305->Mirage_crypto.Poly1305.mac_size|_->0letknowns=Result.is_ok(of_strings)(* For some reason Nocrypto CTR modifies ctr in place, CBC returns next *)letenc_decenc~lenseqcipherbuf=letopenMirage_crypto.Cipher_blockinmatchcipher.cipher_keywith|Plaintext_key->Ok(buf,cipher)|Aes_ctr_key(key,iv)->letf=ifencthenAES.CTR.encryptelseAES.CTR.decryptinletbuf=f~key~ctr:ivbufinletnext_iv=AES.CTR.next_ctr~ctr:ivbufinletcipher_key=Aes_ctr_key(key,next_iv)inletkey={cipherwithcipher_key}inOk(buf,key)|Aes_cbc_key(key,iv)->letf=ifencthenAES.CBC.encryptelseAES.CBC.decryptinletbuf=f~key~ivbufinletnext_iv=AES.CBC.next_iv~ivbufinletcipher_key=Aes_cbc_key(key,next_iv)inletcipher={cipherwithcipher_key}inOk(buf,cipher)|Chacha20_poly1305_key(len_key,key)->letnonce=letb=Cstruct.create8inCstruct.BE.set_uint64b0(Int64.of_int32seq);binletc_lenb=Mirage_crypto.Chacha20.crypt~key:len_key~noncebinletc_datab=Mirage_crypto.Chacha20.crypt~key~ctr:1L~noncebinletmacdata=letkey=Mirage_crypto.Chacha20.crypt~key~nonce(Cstruct.create32)inMirage_crypto.Poly1305.mac~keydatainifencthenletlbuf,msg=Cstruct.splitbuf4inletenc_len=c_lenlbufinletenc_msg=c_datamsginletout=Cstruct.appendenc_lenenc_msginlettag=macoutinOk(Cstruct.appendouttag,cipher)elsebeginiflenthenOk(c_lenbuf,cipher)elseletc,tag=letoff=Cstruct.lengthbuf-Mirage_crypto.Poly1305.mac_sizeinCstruct.splitbufoffinletctag=maccinletenc_len,enc_msg=Cstruct.splitc4inletdec_len=c_lenenc_lenanddec_msg=c_dataenc_msginifCstruct.equalctagtagthenOk(Cstruct.appenddec_lendec_msg,cipher)elseError"tag verification failed"endletencrypt~lenseqcipherbuf=matchenc_dectrue~lenseqcipherbufwith|Oka->a|Error_->assertfalseletdecrypt=enc_decfalseletpreferred=[Chacha20_poly1305;Aes128_ctr;Aes192_ctr;Aes256_ctr;Aes128_cbc;Aes192_cbc;Aes256_cbc;]