Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
crypto.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
open Mirage_crypto open Ciphersuite (* on-the-wire dh_params <-> (group, pub_message) *) let dh_params_pack { Mirage_crypto_pk.Dh.p; gg ; _ } message = let cs_of_z = Mirage_crypto_pk.Z_extra.to_octets_be ?size:None in { Core.dh_p = cs_of_z p ; dh_g = cs_of_z gg ; dh_Ys = message } and dh_params_unpack { Core.dh_p ; dh_g ; dh_Ys } = let z_of_cs = Mirage_crypto_pk.Z_extra.of_octets_be ?bits:None in match Mirage_crypto_pk.Dh.group ~p:(z_of_cs dh_p) ~gg:(z_of_cs dh_g) () with | Ok dh -> Ok (dh, dh_Ys) | Error _ as e -> e module Ciphers = 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 *) type keyed = | K_CBC : 'k State.cbc_cipher * (string -> 'k) -> keyed let get_block = function | TRIPLE_DES_EDE_CBC -> K_CBC ( (module DES.CBC : Block.CBC with type key = DES.CBC.key), DES.CBC.of_secret ) | AES_128_CBC -> K_CBC ( (module AES.CBC : Block.CBC with type key = AES.CBC.key), AES.CBC.of_secret ) | AES_256_CBC -> K_CBC ( (module AES.CBC : Block.CBC with type key = AES.CBC.key), AES.CBC.of_secret ) type aead_keyed = | K_AEAD : 'k State.aead_cipher * (string -> 'k) * bool -> aead_keyed let get_aead = function | AES_128_CCM | AES_256_CCM -> K_AEAD ((module AES.CCM16 : AEAD with type key = AES.CCM16.key), AES.CCM16.of_secret, true) | AES_128_GCM | AES_256_GCM -> K_AEAD ((module AES.GCM : AEAD with type key = AES.GCM.key), AES.GCM.of_secret, true) | CHACHA20_POLY1305 -> K_AEAD ((module Chacha20 : AEAD with type key = Chacha20.key), Chacha20.of_secret, false) let get_aead_cipher ~secret ~nonce aead_cipher = match get_aead aead_cipher with | K_AEAD (cipher, sec, explicit_nonce) -> let cipher_secret = sec secret in State.(AEAD { cipher ; cipher_secret ; nonce ; explicit_nonce }) let get_cipher ~secret ~hmac_secret ~iv_mode ~nonce = function | `Block (cipher, hmac) -> ( match get_block cipher with | K_CBC (cipher, sec) -> let cipher_secret = sec secret in State.(CBC { cipher ; cipher_secret ; iv_mode ; hmac ; hmac_secret }) ) | `AEAD cipher -> get_aead_cipher ~secret ~nonce cipher end let sequence_buf seq = let buf = Bytes.create 8 in Bytes.set_int64_be buf 0 seq ; Bytes.unsafe_to_string buf let aead_nonce nonce seq = let s = let l = String.length nonce in let buf = Bytes.make l '\x00' in Bytes.set_int64_be buf (l - 8) seq; Bytes.unsafe_to_string buf in Uncommon.xor nonce s let adata_1_3 len = (* 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> *) let buf = Bytes.create 5 in Bytes.set_uint8 buf 0 (Packet.content_type_to_int Packet.APPLICATION_DATA) ; Bytes.set_uint8 buf 1 3; Bytes.set_uint8 buf 2 3; Bytes.set_uint16_be buf 3 len ; Bytes.unsafe_to_string buf let pseudo_header seq ty (v_major, v_minor) v_length = let buf = Bytes.create 13 in Bytes.set_int64_be buf 0 seq; Bytes.set_uint8 buf 8 (Packet.content_type_to_int ty); Bytes.set_uint8 buf 9 v_major; Bytes.set_uint8 buf 10 v_minor; Bytes.set_uint16_be buf 11 v_length; Bytes.unsafe_to_string buf (* MAC used in TLS *) let mac hash key pseudo_hdr data = let module H = (val Digestif.module_of_hash' hash) in H.(to_raw_string (hmacv_string ~key [ pseudo_hdr ; data ])) let cbc_block (type a) cipher = let module C = (val cipher : Block.CBC with type key = a) in C.block_size (* crazy CBC padding and unpadding for TLS *) let cbc_pad block data = (* 1 is the padding length, encoded as 8 bit at the end of the fragment *) let len = 1 + String.length data in (* we might want to add additional blocks of padding *) let padding_length = block - (len mod block) in (* 1 is again padding length field *) let cstruct_len = padding_length + 1 in String.make cstruct_len (Char.unsafe_chr padding_length) let cbc_unpad data = let len = String.length data in let padlen = String.get_uint8 data (pred len) in let rec check = function | i when i > padlen -> true | i -> (String.get_uint8 data (len - padlen - 1 + i) = padlen) && check (succ i) in try if check 0 then Some (String.sub data 0 (len - padlen - 1)) else None with Invalid_argument _ -> None let tag_len (type a) cipher = let module C = (val cipher : AEAD with type key = a) in C.tag_size let encrypt_aead (type a) ~cipher ~key ~nonce ?adata data = let module C = (val cipher : AEAD with type key = a) in C.authenticate_encrypt ~key ~nonce ?adata data let decrypt_aead (type a) ~cipher ~key ~nonce ?adata data = let module C = (val cipher : AEAD with type key = a) in C.authenticate_decrypt ~key ~nonce ?adata data let encrypt_cbc (type a) ~cipher ~key ~iv data = let module C = (val cipher : Block.CBC with type key = a) in let message = C.encrypt ~key ~iv (data ^ cbc_pad C.block_size data) in (message, C.next_iv ~iv message) let decrypt_cbc (type a) ~cipher ~key ~iv data = let module C = (val cipher : Block.CBC with type key = a) in try let message = C.decrypt ~key ~iv data in match cbc_unpad message with | Some res -> Some (res, C.next_iv ~iv data) | None -> None with (* 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