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
160
161
162
163
164
165
166
167
168
169
170
171
172
open Mirage_crypto
open Ciphersuite
let (<+>) = Cstruct.append
let dh_params_pack { Mirage_crypto_pk.Dh.p; gg ; _ } message =
let cs_of_z = Mirage_crypto_pk.Z_extra.to_cstruct_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_cstruct_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
type keyed = | K_CBC : 'k State.cbc_cipher * (Cstruct.t -> 'k) -> keyed
let get_block = function
| TRIPLE_DES_EDE_CBC ->
let open Cipher_block.DES in
K_CBC ( (module CBC : Cipher_block.S.CBC with type key = CBC.key),
CBC.of_secret )
| AES_128_CBC ->
let open Cipher_block.AES in
K_CBC ( (module CBC : Cipher_block.S.CBC with type key = CBC.key),
CBC.of_secret )
| AES_256_CBC ->
let open Cipher_block.AES in
K_CBC ( (module CBC : Cipher_block.S.CBC with type key = CBC.key),
CBC.of_secret )
type aead_keyed = | K_AEAD : 'k State.aead_cipher * (Cstruct.t -> 'k) * bool -> aead_keyed
let get_aead =
let open Cipher_block.AES in
function
| AES_128_CCM | AES_256_CCM ->
K_AEAD ((module CCM16 : AEAD with type key = CCM16.key),
CCM16.of_secret, true)
| AES_128_GCM | AES_256_GCM ->
K_AEAD ((module GCM : AEAD with type key = GCM.key),
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 open Cstruct in
let buf = create 8 in
BE.set_uint64 buf 0 seq ;
buf
let aead_nonce nonce seq =
let s =
let l = Cstruct.length nonce in
let s = sequence_buf seq in
let pad = Cstruct.create (l - 8) in
pad <+> s
in
Uncommon.Cs.xor nonce s
let adata_1_3 len =
let buf = Cstruct.create 5 in
Cstruct.set_uint8 buf 0 (Packet.content_type_to_int Packet.APPLICATION_DATA) ;
Cstruct.set_uint8 buf 1 3;
Cstruct.set_uint8 buf 2 3;
Cstruct.BE.set_uint16 buf 3 len ;
buf
let seq ty (v_major, v_minor) v_length =
let open Cstruct in
let prefix = create 5 in
set_uint8 prefix 0 (Packet.content_type_to_int ty);
set_uint8 prefix 1 v_major;
set_uint8 prefix 2 v_minor;
BE.set_uint16 prefix 3 v_length;
sequence_buf seq <+> prefix
let mac hash key pseudo_hdr data =
Hash.mac hash ~key (pseudo_hdr <+> data)
let cbc_block (type a) cipher =
let module C = (val cipher : Cipher_block.S.CBC with type key = a) in C.block_size
let cbc_pad block data =
let open Cstruct in
let len = 1 + length data in
let padding_length = block - (len mod block) in
let cstruct_len = padding_length + 1 in
let pad = create_unsafe cstruct_len in
memset pad padding_length;
pad
let cbc_unpad data =
let open Cstruct in
let len = length data in
let padlen = get_uint8 data (pred len) in
let (res, pad) = split data (len - padlen - 1) in
let rec check = function
| i when i > padlen -> true
| i -> (get_uint8 pad i = padlen) && check (succ i) in
try
if check 0 then Some res 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 : Cipher_block.S.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 : Cipher_block.S.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
| Invalid_argument _ -> None