Source file SharedDefs.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
open Unsigned

(* We keep the API abstract over the type of buffer used in order to keep the
 * possibility of swapping this implementation in the future or offering
 * multiple such implementations. A past version of the library was
 * built using Bigstring instead of Bytes. *)
module type Buffer = sig
  type t
  type buf
  val empty: bytes
  val size_uint32 : bytes -> uint32
  val ctypes_buf : bytes -> buf
  val ctypes_buf_with_offset : bytes -> int -> buf
  val size : bytes -> int
  val equal : bytes -> bytes -> bool
  val make : int -> bytes
  val disjoint : bytes -> bytes -> bool
  val sub : bytes -> int -> int -> bytes
  val z_compare : bytes -> Z.t -> int
end
(** Abstract representation of buffers *)

module CBytes : Buffer with type t = Bytes.t and type buf = Bytes.t Ctypes.ocaml = struct
  open Ctypes
  type t = Bytes.t
  type buf = Bytes.t Ctypes.ocaml
  let empty = Bytes.empty
  let size_uint32 b = Unsigned.UInt32.of_int (Bytes.length b)
  let ctypes_buf = ocaml_bytes_start
  let ctypes_buf_with_offset bytes offset =
    let buf = ocaml_bytes_start bytes in
    buf +@ offset
  let size = Bytes.length
  let equal = Bytes.equal
  let make l = Bytes.make l '\x00'
  let disjoint b1 b2 = b1 != b2
  let sub = Bytes.sub
  let z_compare b z = Z.compare (Z.of_bits (Bytes.to_string b)) z
end
(** Representation of [Bytes.t] buffers *)

module Hacl_Hash = struct
  include Hacl_Hash_Base_bindings.Bindings(Hacl_Hash_Base_stubs)
  include Hacl_Hash_MD5_bindings.Bindings(Hacl_Hash_MD5_stubs)
  include Hacl_Hash_SHA1_bindings.Bindings(Hacl_Hash_SHA1_stubs)
  include Hacl_Hash_SHA2_bindings.Bindings(Hacl_Hash_SHA2_stubs)
  include Hacl_Hash_Blake2_bindings.Bindings(Hacl_Hash_Blake2_stubs)
end
module Hacl_Spec = Hacl_Spec_bindings.Bindings(Hacl_Spec_stubs)

let max_uint32 = Z.((shift_left ~$1 32) - ~$1)
let max_uint64 = Z.((shift_left ~$1 64) - ~$1)
let pow2_31 = Z.(shift_left ~$1 31)

(* Note: we check most input buffers to have a length that fits inside
 * a uint32_t because that is the type of buffer length accepted by the
 * C interface. In their specs, some functions accept longer buffers.
 * We could revise these checks in the future if the C interface will use
 * larger types for the size of a buffer. *)
let check_max_buffer_len len =
  assert Z.(of_int len <= max_uint32)

module AEADDefs = struct
  open Hacl_Spec
  type alg =
    | AES128_GCM
    | AES256_GCM
    | CHACHA20_POLY1305
  let alg_definition = function
    | AES128_GCM -> spec_Agile_AEAD_alg_Spec_Agile_AEAD_AES128_GCM
    | AES256_GCM -> spec_Agile_AEAD_alg_Spec_Agile_AEAD_AES256_GCM
    | CHACHA20_POLY1305 -> spec_Agile_AEAD_alg_Spec_Agile_AEAD_CHACHA20_POLY1305
  let key_length = function
    (* specs/Spec.Agile.AEAD.key_length *)
    | AES128_GCM -> 16
    | AES256_GCM -> 32
    | CHACHA20_POLY1305 -> 32
  let tag_length = function
    (* specs/Spec.Agile.AEAD.tag_length *)
    | AES128_GCM
    | AES256_GCM
    | CHACHA20_POLY1305 -> 16
  let check_iv_length len = function
    (* specs/Spec.Agile.AEAD.iv_length *)
    | AES128_GCM
    | AES256_GCM -> len > 0 && Z.(of_int len <= max_uint32)
    | CHACHA20_POLY1305 -> len = 12
  let check_max_pt_length len = function
    (* specs/Spec.Agile.AEAD.max_length *)
    | AES128_GCM
    | AES256_GCM -> Z.(of_int len <= max_uint32)
    | CHACHA20_POLY1305 ->  Z.(of_int len <= max_uint32 - ~$16)
  let check_sizes ~alg ~iv_len ~tag_len ~ad_len ~pt_len ~ct_len =
    (* providers/EverCrypt.AEAD.encrypt_st *)
    assert (check_iv_length iv_len alg);
    assert (tag_len = tag_length alg);
    assert (check_max_pt_length pt_len alg);
    assert Z.(of_int ad_len <= pow2_31);
    assert (pt_len = ct_len)
end

module HashDefs = struct
  open Hacl_Spec
  type deprecated_alg =
    | SHA1
    | MD5 [@@deprecated]
  type alg =
    | SHA2_224
    | SHA2_256
    | SHA2_384
    | SHA2_512
    | BLAKE2b
    | BLAKE2s
    | Legacy of deprecated_alg
  let alg_definition = function
    | SHA2_224 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_SHA2_224
    | SHA2_256 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_SHA2_256
    | SHA2_384 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_SHA2_384
    | SHA2_512 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_SHA2_512
    | BLAKE2b -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_Blake2B
    | BLAKE2s -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_Blake2S
    | Legacy SHA1 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_SHA1
    | Legacy MD5 -> spec_Hash_Definitions_hash_alg_Spec_Hash_Definitions_MD5
  let digest_len alg =
    UInt32.to_int (Hacl_Hash.hacl_Hash_Definitions_hash_len (alg_definition alg))
  let check_digest_len alg len =
    assert (len = digest_len alg)
end

module type Chacha20_Poly1305_generic = sig
  type bytes
  val encrypt: key:bytes -> iv:bytes -> ad:bytes -> pt:bytes -> bytes * bytes
  (** [encrypt key iv ad pt] takes a [key], an initial value [iv], additional data
      [ad], and plaintext [pt] and returns a tuple containing the encrypted [pt] and the
      authentication tag for the plaintext and the associated data. *)

  val decrypt: key:bytes -> iv:bytes -> ad:bytes -> ct:bytes -> tag:bytes -> bytes option
  (** [decrypt key iv ad ct tag] takes a [key], the initial value [iv], additional
      data [ad], ciphertext [ct], and authentication tag [tag], and, if successful,
      returns the decrypted [ct]. *)

  (** Versions of these functions which write their output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val encrypt: key:bytes -> iv:bytes -> ad:bytes -> pt:bytes -> ct:bytes -> tag:bytes -> unit
    (** [encrypt key iv ad pt ct tag] takes a [key], an initial value [iv], additional data
        [ad], and plaintext [pt], as well as output buffers [ct], which will
        contain the encrypted [pt], and [tag], which will contain the authentication tag for
        the plaintext and the associated data. *)

    val decrypt: key:bytes -> iv:bytes -> ad:bytes -> ct:bytes -> tag:bytes -> pt:bytes -> bool
    (** [decrypt key iv ad ct tag pt] takes a [key], the initial value [iv], additional
        data [ad], ciphertext [ct], and authentication tag [tag], as well as output buffer [pt],
        which, if successful, will contain the decrypted [ct]. *)
  end
end

module type Curve25519_generic = sig
(** See {{:https://hacl-star.github.io/HaclECDH.html#hacl-curve25519} here} for detailed
    usage instructions.
*)

  type bytes
  val secret_to_public : sk:bytes -> bytes
  (** [secret_to_public sk] takes a 32-byte secret key [sk] and returns the corresponding
      32-byte ECDH public key. *)

  val ecdh : sk:bytes -> pk:bytes -> bytes option
  (** [ecdh sk pk] takes a 32-byte secret key [sk] and another party's 32-byte public
      key and returns the 32-byte ECDH shared key. *)

  val scalarmult : scalar:bytes -> point:bytes -> bytes
  (** [scalarmult scalar point] performs scalar multiplication over the curve. Buffers
      are 32-byte long and must be distinct. *)

  (** Versions of these functions which write their output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val secret_to_public : sk:bytes -> pk:bytes -> unit
    (** [secret_to_public sk pk] takes a 32-byte secret key [sk] and writes the corresponding
        32-byte ECDH public key in [pk]. Buffers [pk] and [sk] must be distinct. *)

    val ecdh : sk:bytes -> pk:bytes -> shared:bytes -> bool
    (** [ecdh sk pk shared] takes a 32-byte secret key [sk] and another party's 32-byte public
        key and writes the 32-byte ECDH shared key in [shared]. Buffer [shared] must be distinct from
        [pk] and [sk]. *)

    val scalarmult : scalar:bytes -> point:bytes -> result:bytes -> unit
    (** [scalarmult scalar point] performs scalar multiplication over the curve. Buffers
        are 32-byte long and must be distinct. *)
  end
end

module type EdDSA_generic = sig
(** See {{:https://hacl-star.github.io/HaclSig.html} here} for detailed
    usage instructions.
*)

  type bytes

  (** {1 EdDSA} *)

  val secret_to_public : sk:bytes -> bytes
  (** [secret_to_public sk] takes a secret key [sk] and returns the corresponding
      public key. *)

  val sign : sk:bytes -> msg:bytes -> bytes
  (** [sign sk msg] takes secret key [sk] and message [msg] and returns
      the Ed25519 signature. *)

  val verify : pk:bytes -> msg:bytes -> signature:bytes -> bool
  (** [verify pk msg signature] takes public key [pk], message [msg] and verifies the
      Ed25519 signature, returning true if valid. *)

  (** {1 EdDSA Expanded Signing} *)

  val expand_keys : sk:bytes -> bytes
  (** [expand_keys sk] takes secret key [sk] and returns the expanded secret key. *)

  val sign_expanded : ks:bytes -> msg:bytes -> bytes
  (** [sign_expanded ks msg signature] takes expanded secret key [ks] and message [msg] and
      returns the Ed25519 signature. *)

  (** Versions of these functions which write their output in a buffer passed in as
      an argument *)
  module Noalloc : sig

    (** Buffers have the following size constraints:
        - [sk], [pk]: 32 bytes
        - [signature]: 64 bytes

        {1 EdDSA}

        Note: The [verify] function does not return a buffer so it has no been duplicated here.
    *)

    val secret_to_public : sk:bytes -> pk:bytes -> unit
    (** [secret_to_public sk pk] takes a secret key [sk] and writes the corresponding
        public key in [pk]. Buffers [pk] and [sk] must be distinct. *)

    val sign : sk:bytes -> msg:bytes -> signature:bytes -> unit
    (** [sign sk msg signature] takes secret key [sk] and message [msg] and writes
        the Ed25519 signature in [signature]. *)

    (** {1 EdDSA Expanded Signing}

        The buffer [ks] containing the expanded secret key must be 96 bytes long.
    *)

    val expand_keys : sk:bytes -> ks:bytes -> unit
    (** [expand_keys sk ks] takes secret key [sk] and writes the expanded secret key in [ks]. *)

    val sign_expanded : ks:bytes -> msg:bytes -> signature:bytes -> unit
    (** [sign_expanded ks msg signature] takes expanded secret key [ks] and message [msg] and writes
        the Ed25519 signature in [signature]. *)
  end
end

module type HashFunction_generic = sig

  type bytes

  val hash : bytes -> bytes
  (** [hash msg] returns the hash of [msg]. *)

  (** Version of this function which writes its output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val hash : msg:bytes -> digest:bytes -> unit
    (** [hash msg digest] hashes [msg] and outputs the result in [digest]. *)
  end
end

module type MAC_generic = sig
  (** For Poly1305, buffers have the following size constraints:
      - [key]: 32 bytes
      - output buffer: 16 bytes

      For HMAC with SHA-2, the output buffer is the same size as the digest size of
      the corresponding hash function (see {{!EverCrypt.Hash} here}). For HMAC with BLAKE2,
      the output buffer is 64 bytes for BLAKE2b and 32 bytes for BLAKE2s.
*)

  type bytes

  val mac : key:bytes -> msg:bytes -> bytes
  (** [mac key msg] computes the MAC of [msg] using key [key]. *)

  (** Version of this function which writes its output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val mac : key:bytes -> msg:bytes -> tag:bytes -> unit
    (** [mac key msg tag] computes the MAC of [msg] using key [key] and writes the result in [tag].
        The `tag` buffer needs to satisfy the size requirements for the output buffer. *)
  end
end

module type HKDF_generic = sig
  (** Buffers have the following size constraints with respect to the digest size of the underlying
      hash function, [digest_len]:
      - [prk]: = [digest_len]
      - [okm]: <= 255 * [digest_len]
*)

  type bytes

  val extract: salt:bytes -> ikm:bytes -> bytes
  (** [extract salt ikm] computes a pseudorandom key using input key material [ikm] and
      salt [salt]. *)

  val expand: prk:bytes -> info:bytes -> size:int -> bytes
  (** [expand prk info size] expands the pseudorandom key [prk], taking the info string [info] into
      account and returns a buffer of [size] bytes. *)

  (** Versions of these functions which write their output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val extract: salt:bytes -> ikm:bytes -> prk:bytes -> unit
    (** [extract salt ikm prk] computes a pseudorandom key [prk] using input key material [ikm] and
        salt [salt]. *)

    val expand: prk:bytes -> info:bytes -> okm:bytes -> unit
    (** [expand prk info okm] expands the pseudorandom key [prk], taking the info string [info] into
        account, and writes the output key material in [okm]. *)
  end
end

module type ECDSA_generic = sig
  (** Buffers have the following size constraints:
      - [pk]: 64 bytes, corresponding to the "raw" representation of an elliptic curve point (see {!section:points})
      - [sk], [k]: 32 bytes
      - [signature]: 64 bytes
      - [msg]: no size requirement for variants using SHA-2 hashing (see {!section:ecdsa})
  *)

  type bytes

  val sign : sk:bytes -> msg:bytes -> k:bytes -> bytes option
  (** [sign sk msg k] attempts to sign the message [msg] with secret key [sk] and
      signing secret [k] and returns the signature if successful. *)

  val verify : pk:bytes -> msg:bytes -> signature:bytes -> bool
  (** [verify pk msg signature] checks the [signature] of [msg] using public key [pk] and returns
  true if it is valid. *)

  (** Versions of these functions which write their output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val sign : sk:bytes -> msg:bytes -> k:bytes -> signature:bytes -> bool
    (** [sign sk msg k signature] attempts to sign the message [msg] with secret key [sk] and
        signing secret [k]. If successful, the signature is written in [signature] and the
        function returns true. *)
  end
end

module type Blake2_generic = sig
(** Buffers have the following size constraints:
    - [key]: <= 64 bytes for BLAKE2b, <= 32 bytes for BLAKE2s
    - [digest]: non-zero, <= 64 bytes for BLAKE2b, <= 32 bytes for BLAKE2s *)

  type bytes

  val hash : ?key:bytes -> bytes -> int -> bytes
  (** [hash ?key msg size] hashes [msg] and returns a digest of length [size].
      An optional [key] argument can be passed for keyed hashing. *)

  (** Version of this function which writes its output in a buffer passed in as
      an argument *)
  module Noalloc : sig
    val hash : key:bytes -> msg:bytes -> digest:bytes -> unit
    (** [hash key msg digest] hashes [msg] and outputs the result in [digest].
        A non-empty [key] can be passed for keyed hashing. *)
  end
end

module type Chacha20_Poly1305 = Chacha20_Poly1305_generic with type bytes = CBytes.t
module type Curve25519 = Curve25519_generic with type bytes = CBytes.t
module type EdDSA = EdDSA_generic with type bytes = CBytes.t
module type HashFunction = HashFunction_generic with type bytes = CBytes.t
module type MAC = MAC_generic with type bytes = CBytes.t
module type HKDF = HKDF_generic with type bytes = CBytes.t
module type ECDSA = ECDSA_generic with type bytes = CBytes.t
module type Blake2 = Blake2_generic with type bytes = CBytes.t