Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file crypto.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201openMirage_cryptoopenCiphersuitelet(<+>)=Utils.Cs.(<+>)(* on-the-wire dh_params <-> (group, pub_message) *)letdh_params_pack{Mirage_crypto_pk.Dh.p;gg;_}message=letcs_of_z=Mirage_crypto_pk.Z_extra.to_cstruct_be?size:Nonein{Core.dh_p=cs_of_zp;dh_g=cs_of_zgg;dh_Ys=message}anddh_params_unpack{Core.dh_p;dh_g;dh_Ys}=letz_of_cs=Mirage_crypto_pk.Z_extra.of_cstruct_be?bits:NoneinmatchMirage_crypto_pk.Dh.group~p:(z_of_csdh_p)~gg:(z_of_csdh_g)()with|Okdh->Ok(dh,dh_Ys)|Error_ase->emoduleCiphers=struct(* I'm not sure how to get rid of this type, but would welcome a solution *)(* only used as result of get_block, which is called by get_cipher below *)typekeyed=|K_CBC:'kState.cbc_cipher*(Cstruct.t->'k)->keyedletget_block=function|TRIPLE_DES_EDE_CBC->letopenCipher_block.DESinK_CBC((moduleCBC:Cipher_block.S.CBCwithtypekey=CBC.key),CBC.of_secret)|AES_128_CBC->letopenCipher_block.AESinK_CBC((moduleCBC:Cipher_block.S.CBCwithtypekey=CBC.key),CBC.of_secret)|AES_256_CBC->letopenCipher_block.AESinK_CBC((moduleCBC:Cipher_block.S.CBCwithtypekey=CBC.key),CBC.of_secret)letget_aead~secret~nonce=letopenCipher_block.AESinfunction|AES_128_CCM|AES_256_CCM->letcipher=(moduleCCM:Cipher_block.S.CCMwithtypekey=CCM.key)in(* TODO the 16 should either be input or extracted from ciphersuite name *)letcipher_secret=CCM.of_secret~maclen:16secretinState.(AEAD{cipher=CCMcipher;cipher_secret;nonce})|AES_128_GCM|AES_256_GCM->letcipher=(moduleGCM:Cipher_block.S.GCMwithtypekey=GCM.key)inletcipher_secret=GCM.of_secretsecretinState.(AEAD{cipher=GCMcipher;cipher_secret;nonce})|CHACHA20_POLY1305->letcipher=(moduleChacha20:AEADwithtypekey=Chacha20.key)inletcipher_secret=Chacha20.of_secretsecretinState.(AEAD{cipher=ChaCha20_Poly1305cipher;cipher_secret;nonce})letget_cipher~secret~hmac_secret~iv_mode~nonce=function|`Block(cipher,hmac)->(matchget_blockcipherwith|K_CBC(cipher,sec)->letcipher_secret=secsecretinState.(CBC{cipher;cipher_secret;iv_mode;hmac;hmac_secret}))|`AEADcipher->get_aead~secret~noncecipherendletdigest_eqfn~targetcs=Utils.Cs.equaltarget(Hash.digestfncs)letsequence_bufseq=letopenCstructinletbuf=create8inBE.set_uint64buf0seq;bufletaead_noncenonceseq=lets=letl=Cstruct.lennonceinlets=sequence_bufseqinletpad=Cstruct.create(l-8)inpad<+>sinUncommon.Cs.xornoncesletadata_1_3len=(* additional data in TLS 1.3 is using the header (RFC 8446 Section 5.2):
- APPLICATION_TYPE
- 0x03 0x03 (for TLS version 1.2 -- binary representation is 0x03 0x03)
- <length in 16 bit>
*)letbuf=Cstruct.create5inCstruct.set_uint8buf0(Packet.content_type_to_intPacket.APPLICATION_DATA);Cstruct.set_uint8buf13;Cstruct.set_uint8buf23;Cstruct.BE.set_uint16buf3len;bufletpseudo_headerseqty(v_major,v_minor)length=letopenCstructinletprefix=create5inset_uint8prefix0(Packet.content_type_to_intty);set_uint8prefix1v_major;set_uint8prefix2v_minor;BE.set_uint16prefix3length;sequence_bufseq<+>prefix(* MAC used in TLS *)letmachashkeypseudo_hdrdata=Hash.machash~key(pseudo_hdr<+>data)letcbc_block(typea)cipher=letmoduleC=(valcipher:Cipher_block.S.CBCwithtypekey=a)inC.block_size(* crazy CBC padding and unpadding for TLS *)letcbc_padblockdata=letopenCstructin(* 1 is the padding length, encoded as 8 bit at the end of the fragment *)letlen=1+lendatain(* we might want to add additional blocks of padding *)letpadding_length=block-(lenmodblock)in(* 1 is again padding length field *)letcstruct_len=padding_length+1inletpad=create_unsafecstruct_leninmemsetpadpadding_length;padletcbc_unpaddata=letopenCstructinletlen=lendatainletpadlen=get_uint8data(predlen)inlet(res,pad)=splitdata(len-padlen-1)inletreccheck=function|iwheni>padlen->true|i->(get_uint8padi=padlen)&&check(succi)intryifcheck0thenSomereselseNonewithInvalid_argument_->Nonelettag_len(typea)=function|State.CCMcipher->letmoduleC=(valcipher:Cipher_block.S.CCMwithtypekey=a)in(* TODO this is wrong (but works since "16" is always passed in above,
which indeed is the AES128/256 block size). There should be a
C.tag_size (in CCM this needs to depend on the key though (due to
different possible mac sizes), in contrast to GCM where we always have
a static one) - maybe mirage-crypto CCM should take mac len as functor
argument? *)C.block_size|State.GCMcipher->letmoduleC=(valcipher:Cipher_block.S.GCMwithtypekey=a)inC.tag_size|State.ChaCha20_Poly1305_->Poly1305.mac_sizeletencrypt_aead(typea)~cipher~key~nonce?adatadata=matchcipherwith|State.CCMcipher->letmoduleC=(valcipher:Cipher_block.S.CCMwithtypekey=a)inC.authenticate_encrypt~key~nonce?adatadata|State.GCMcipher->letmoduleC=(valcipher:Cipher_block.S.GCMwithtypekey=a)inC.authenticate_encrypt~key~nonce?adatadata|State.ChaCha20_Poly1305cipher->letmoduleC=(valcipher:AEADwithtypekey=a)inC.authenticate_encrypt~key~nonce?adatadataletdecrypt_aead(typea)~cipher~key~nonce?adatadata=matchcipherwith|State.CCMcipher->letmoduleC=(valcipher:Cipher_block.S.CCMwithtypekey=a)inC.authenticate_decrypt~key~nonce?adatadata|State.GCMcipher->letmoduleC=(valcipher:Cipher_block.S.GCMwithtypekey=a)inC.authenticate_decrypt~key~nonce?adatadata|State.ChaCha20_Poly1305cipher->letmoduleC=(valcipher:AEADwithtypekey=a)inC.authenticate_decrypt~key~nonce?adatadataletencrypt_cbc(typea)~cipher~key~ivdata=letmoduleC=(valcipher:Cipher_block.S.CBCwithtypekey=a)inletmessage=C.encrypt~key~iv(data<+>cbc_padC.block_sizedata)in(message,C.next_iv~ivmessage)letdecrypt_cbc(typea)~cipher~key~ivdata=letmoduleC=(valcipher:Cipher_block.S.CBCwithtypekey=a)intryletmessage=C.decrypt~key~ivdatainmatchcbc_unpadmessagewith|Someres->Some(res,C.next_iv~ivdata)|None->Nonewith(* This bails out immediately on mis-alignment, making it very timeable.
* However, decryption belongs to the outermost level and this operation's
* timing does not leak information ala padding oracle and friends. *)|Invalid_argument_->None