···11+(* Based on https://github.com/abeaumont/ocaml-chacha.git *)
22+33+open Uncommon
44+55+let block = 64
66+77+let chacha20_block state idx key_stream =
88+ Native.Chacha.round 10 state.Cstruct.buffer 0 key_stream.Cstruct.buffer idx
99+1010+let init ctr ~key ~nonce =
1111+ let ctr_off = 48 in
1212+ let set_ctr32 b v = Cstruct.LE.set_uint32 b ctr_off v
1313+ and set_ctr64 b v = Cstruct.LE.set_uint64 b ctr_off v
1414+ in
1515+ let inc32 b = set_ctr32 b (Int32.add (Cstruct.LE.get_uint32 b ctr_off) 1l)
1616+ and inc64 b = set_ctr64 b (Int64.add (Cstruct.LE.get_uint64 b ctr_off) 1L)
1717+ in
1818+ let s, key, init_ctr, nonce_off, inc =
1919+ match Cstruct.len key, Cstruct.len nonce, Int64.shift_right ctr 32 = 0L with
2020+ | 32, 12, true ->
2121+ let ctr = Int64.to_int32 ctr in
2222+ "expand 32-byte k", key, (fun b -> set_ctr32 b ctr), 52, inc32
2323+ | 32, 12, false ->
2424+ invalid_arg "Counter too big for IETF mode (32 bit counter)"
2525+ | 32, 8, _ ->
2626+ "expand 32-byte k", key, (fun b -> set_ctr64 b ctr), 56, inc64
2727+ | 16, 8, _ ->
2828+ let k = Cstruct.append key key in
2929+ "expand 16-byte k", k, (fun b -> set_ctr64 b ctr), 56, inc64
3030+ | _ -> invalid_arg "Valid parameters are nonce 12 bytes and key 32 bytes \
3131+ (counter 32 bit), or nonce 8 byte and key 16 or 32 \
3232+ bytes (counter 64 bit)."
3333+ in
3434+ let state = Cstruct.create block in
3535+ Cstruct.blit_from_string s 0 state 0 16 ;
3636+ Cstruct.blit key 0 state 16 32 ;
3737+ init_ctr state ;
3838+ Cstruct.blit nonce 0 state nonce_off (Cstruct.len nonce) ;
3939+ state, inc
4040+4141+let crypt ~key ~nonce ?(ctr = 0L) data =
4242+ let state, inc = init ctr ~key ~nonce in
4343+ let l = Cstruct.len data in
4444+ let block_count = l // block in
4545+ let len = block * block_count in
4646+ let key_stream = Cstruct.create_unsafe len in
4747+ let rec loop i = function
4848+ | 0 -> ()
4949+ | n ->
5050+ chacha20_block state i key_stream ;
5151+ Native.xor_into data.buffer (data.off + i) key_stream.buffer i block ;
5252+ inc state;
5353+ loop (i + block) (n - 1)
5454+ in
5555+ loop 0 block_count ;
5656+ Cstruct.sub key_stream 0 l
5757+5858+module P = Poly1305.It
5959+6060+let generate_poly1305_key ~key ~nonce =
6161+ crypt ~key ~nonce (Cstruct.create 32)
6262+6363+let mac ~key ~adata ciphertext =
6464+ let pad16 b =
6565+ let len = Cstruct.len b mod 16 in
6666+ if len = 0 then Cstruct.empty else Cstruct.create (16 - len)
6767+ and len =
6868+ let data = Cstruct.create 16 in
6969+ Cstruct.LE.set_uint64 data 0 (Int64.of_int (Cstruct.len adata));
7070+ Cstruct.LE.set_uint64 data 8 (Int64.of_int (Cstruct.len ciphertext));
7171+ data
7272+ in
7373+ let ctx = P.empty ~key in
7474+ let ctx = P.feed ctx adata in
7575+ let ctx = P.feed ctx (pad16 adata) in
7676+ let ctx = P.feed ctx ciphertext in
7777+ let ctx = P.feed ctx (pad16 ciphertext) in
7878+ let ctx = P.feed ctx len in
7979+ P.get ctx
8080+8181+let aead_poly1305_encrypt ~key ~nonce ?(adata = Cstruct.empty) data =
8282+ let poly1305_key = generate_poly1305_key ~key ~nonce in
8383+ let ciphertext = crypt ~key ~nonce ~ctr:1L data in
8484+ let mac = mac ~key:poly1305_key ~adata ciphertext in
8585+ Cstruct.append ciphertext mac
8686+8787+let aead_poly1305_decrypt ~key ~nonce ?(adata = Cstruct.empty) data =
8888+ if Cstruct.len data < P.mac_size then
8989+ None
9090+ else
9191+ let cipher, tag = Cstruct.split data (Cstruct.len data - P.mac_size) in
9292+ let poly1305_key = generate_poly1305_key ~key ~nonce in
9393+ let ctag = mac ~key:poly1305_key ~adata cipher in
9494+ let plain = crypt ~key ~nonce ~ctr:1L cipher in
9595+ if Cstruct.equal tag ctag then Some plain else None
···187187 (** [digest_size algorithm] is the size of the [algorithm] in bytes. *)
188188end
189189190190+(** The poly1305 message authentication code *)
191191+module Poly1305 : sig
192192+ type mac = Cstruct.t
193193+194194+ type 'a iter = ('a -> unit) -> unit
195195+196196+ type t
197197+ (** Represents a running mac computation, suitable for appending inputs. *)
198198+199199+ val mac_size : int
200200+ (** [mac_size] is the size of the output. *)
201201+202202+ val empty : key:Cstruct.t -> t
203203+ (** [empty] is the empty context with the given [key].
204204+205205+ @raise Invalid_argument if key is not 32 bytes. *)
206206+207207+ val feed : t -> Cstruct.t -> t
208208+ (** [feed t msg] adds the information in [msg] to [t]. *)
209209+210210+ val feedi : t -> Cstruct.t iter -> t
211211+ (** [feedi t iter] feeds iter into [t]. *)
212212+213213+ val get : t -> mac
214214+ (** [get t] is the mac corresponding to [t]. *)
215215+216216+ val mac : key:Cstruct.t -> Cstruct.t -> mac
217217+ (** [mac ~key msg] is the all-in-one mac computation:
218218+ [get (feed (empty ~key) msg)]. *)
219219+220220+ val maci : key:Cstruct.t -> Cstruct.t iter -> mac
221221+ (** [maci ~key iter] is the all-in-one mac computation:
222222+ [get (feedi (empty ~key) iter)]. *)
223223+end
190224191225(** {1 Symmetric-key cryptography} *)
192226···437471 this build of the library. *)
438472end
439473474474+(** The ChaCha20 cipher proposed by D.J. Bernstein. *)
475475+module Chacha20 : sig
476476+ val crypt : key:Cstruct.t -> nonce:Cstruct.t -> ?ctr:int64 -> Cstruct.t -> Cstruct.t
477477+ (** [crypt ~key ~nonce ~ctr data] generates a ChaCha20 key stream using
478478+ the [key], and [nonce]. The [ctr] defaults to 0. The generated key
479479+ stream is of the same length as [data], and the output is the XOR
480480+ of the key stream and [data]. This implements, depending on the size
481481+ of the [nonce] (8 or 12 bytes) both the original specification (where
482482+ the counter is 8 byte, same as the nonce) and the IETF RFC 8439
483483+ specification (where nonce is 12 bytes, and counter 4 bytes).
484484+485485+ @raise Invalid_argument if invalid parameters are provided. Valid
486486+ parameters are: [key] must be 32 bytes and [nonce] 12 bytes for the
487487+ IETF mode (and counter fit into 32 bits), or [key] must be either 16
488488+ bytes or 32 bytes and [nonce] 8 bytes.
489489+ *)
490490+491491+ val aead_poly1305_encrypt : key:Cstruct.t -> nonce:Cstruct.t ->
492492+ ?adata:Cstruct.t -> Cstruct.t -> Cstruct.t
493493+ (** [aead_poly1305_encrypt ~key ~nonce ~adata data] encrypts [data]
494494+ with ChaCha20 using [key] and [nonce]. Additionally, an authentication
495495+ tag using {!Poly1305} is appended to the output. This conforms to
496496+ RFC 8439 Section 2.8. *)
497497+498498+ val aead_poly1305_decrypt : key:Cstruct.t -> nonce:Cstruct.t ->
499499+ ?adata:Cstruct.t -> Cstruct.t -> Cstruct.t option
500500+ (** [aead_poly1305_decrypt ~key ~nonce ~adata data] decrypts [data] with
501501+ ChaCha20 using [key] and [nonce]. Also, the authentication tag is split
502502+ off the end of [data] and verified using {!Poly1305}. This conforms to
503503+ RFC 8439 Section 2.8. *)
504504+end
440505441506(** Streaming ciphers. *)
442507module Cipher_stream : sig
+12
src/native.ml
···3030 external k_s : unit -> int = "mc_des_key_size" [@@noalloc]
3131end
32323333+module Chacha = struct
3434+ external round : int -> buffer -> off -> buffer -> off -> unit = "mc_chacha_round" [@@noalloc]
3535+end
3636+3737+module Poly1305 = struct
3838+ external init : ctx -> buffer -> off -> unit = "mc_poly1305_init" [@@noalloc]
3939+ external update : ctx -> buffer -> off -> size -> unit = "mc_poly1305_update" [@@noalloc]
4040+ external finalize : ctx -> buffer -> off -> unit = "mc_poly1305_finalize" [@@noalloc]
4141+ external ctx_size : unit -> int = "mc_poly1305_ctx_size" [@@noalloc]
4242+ external mac_size : unit -> int = "mc_poly1305_mac_size" [@@noalloc]
4343+end
4444+3345module MD5 = struct
3446 external init : ctx -> unit = "mc_md5_init" [@@noalloc]
3547 external update : ctx -> buffer -> off -> size -> unit = "mc_md5_update" [@@noalloc]
···11+// from https://github.com/floodyberry/poly1305-donna.git
22+33+/*
44+ poly1305 implementation using 64 bit * 64 bit = 128 bit multiplication and 128 bit addition
55+*/
66+77+#define uint128_t __uint128_t
88+#define MUL(out, x, y) out = ((uint128_t)x * y)
99+#define ADD(out, in) out += in
1010+#define ADDLO(out, in) out += in
1111+#define SHR(in, shift) (unsigned long long)(in >> (shift))
1212+#define LO(in) (unsigned long long)(in)
1313+1414+#define POLY1305_NOINLINE __attribute__((noinline))
1515+1616+#define poly1305_block_size 16
1717+1818+/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */
1919+typedef struct poly1305_state_internal_t {
2020+ unsigned long long r[3];
2121+ unsigned long long h[3];
2222+ unsigned long long pad[2];
2323+ size_t leftover;
2424+ unsigned char buffer[poly1305_block_size];
2525+ unsigned char final;
2626+} poly1305_state_internal_t;
2727+2828+/* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in little endian */
2929+static unsigned long long
3030+U8TO64(const unsigned char *p) {
3131+ return
3232+ (((unsigned long long)(p[0] & 0xff) ) |
3333+ ((unsigned long long)(p[1] & 0xff) << 8) |
3434+ ((unsigned long long)(p[2] & 0xff) << 16) |
3535+ ((unsigned long long)(p[3] & 0xff) << 24) |
3636+ ((unsigned long long)(p[4] & 0xff) << 32) |
3737+ ((unsigned long long)(p[5] & 0xff) << 40) |
3838+ ((unsigned long long)(p[6] & 0xff) << 48) |
3939+ ((unsigned long long)(p[7] & 0xff) << 56));
4040+}
4141+4242+/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little endian */
4343+static void
4444+U64TO8(unsigned char *p, unsigned long long v) {
4545+ p[0] = (v ) & 0xff;
4646+ p[1] = (v >> 8) & 0xff;
4747+ p[2] = (v >> 16) & 0xff;
4848+ p[3] = (v >> 24) & 0xff;
4949+ p[4] = (v >> 32) & 0xff;
5050+ p[5] = (v >> 40) & 0xff;
5151+ p[6] = (v >> 48) & 0xff;
5252+ p[7] = (v >> 56) & 0xff;
5353+}
5454+5555+void
5656+poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
5757+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
5858+ unsigned long long t0,t1;
5959+6060+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
6161+ t0 = U8TO64(&key[0]);
6262+ t1 = U8TO64(&key[8]);
6363+6464+ st->r[0] = ( t0 ) & 0xffc0fffffff;
6565+ st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
6666+ st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
6767+6868+ /* h = 0 */
6969+ st->h[0] = 0;
7070+ st->h[1] = 0;
7171+ st->h[2] = 0;
7272+7373+ /* save pad for later */
7474+ st->pad[0] = U8TO64(&key[16]);
7575+ st->pad[1] = U8TO64(&key[24]);
7676+7777+ st->leftover = 0;
7878+ st->final = 0;
7979+}
8080+8181+static void
8282+poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
8383+ const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
8484+ unsigned long long r0,r1,r2;
8585+ unsigned long long s1,s2;
8686+ unsigned long long h0,h1,h2;
8787+ unsigned long long c;
8888+ uint128_t d0,d1,d2,d;
8989+9090+ r0 = st->r[0];
9191+ r1 = st->r[1];
9292+ r2 = st->r[2];
9393+9494+ h0 = st->h[0];
9595+ h1 = st->h[1];
9696+ h2 = st->h[2];
9797+9898+ s1 = r1 * (5 << 2);
9999+ s2 = r2 * (5 << 2);
100100+101101+ while (bytes >= poly1305_block_size) {
102102+ unsigned long long t0,t1;
103103+104104+ /* h += m[i] */
105105+ t0 = U8TO64(&m[0]);
106106+ t1 = U8TO64(&m[8]);
107107+108108+ h0 += (( t0 ) & 0xfffffffffff);
109109+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
110110+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
111111+112112+ /* h *= r */
113113+ MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
114114+ MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
115115+ MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
116116+117117+ /* (partial) h %= p */
118118+ c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
119119+ ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
120120+ ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
121121+ h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff;
122122+ h1 += c;
123123+124124+ m += poly1305_block_size;
125125+ bytes -= poly1305_block_size;
126126+ }
127127+128128+ st->h[0] = h0;
129129+ st->h[1] = h1;
130130+ st->h[2] = h2;
131131+}
132132+133133+134134+POLY1305_NOINLINE void
135135+poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
136136+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
137137+ unsigned long long h0,h1,h2,c;
138138+ unsigned long long g0,g1,g2;
139139+ unsigned long long t0,t1;
140140+141141+ /* process the remaining block */
142142+ if (st->leftover) {
143143+ size_t i = st->leftover;
144144+ st->buffer[i] = 1;
145145+ for (i = i + 1; i < poly1305_block_size; i++)
146146+ st->buffer[i] = 0;
147147+ st->final = 1;
148148+ poly1305_blocks(st, st->buffer, poly1305_block_size);
149149+ }
150150+151151+ /* fully carry h */
152152+ h0 = st->h[0];
153153+ h1 = st->h[1];
154154+ h2 = st->h[2];
155155+156156+ c = (h1 >> 44); h1 &= 0xfffffffffff;
157157+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
158158+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
159159+ h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
160160+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
161161+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
162162+ h1 += c;
163163+164164+ /* compute h + -p */
165165+ g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
166166+ g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
167167+ g2 = h2 + c - ((unsigned long long)1 << 42);
168168+169169+ /* select h if h < p, or h + -p if h >= p */
170170+ c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
171171+ g0 &= c;
172172+ g1 &= c;
173173+ g2 &= c;
174174+ c = ~c;
175175+ h0 = (h0 & c) | g0;
176176+ h1 = (h1 & c) | g1;
177177+ h2 = (h2 & c) | g2;
178178+179179+ /* h = (h + pad) */
180180+ t0 = st->pad[0];
181181+ t1 = st->pad[1];
182182+183183+ h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
184184+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
185185+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
186186+187187+ /* mac = h % (2^128) */
188188+ h0 = ((h0 ) | (h1 << 44));
189189+ h1 = ((h1 >> 20) | (h2 << 24));
190190+191191+ U64TO8(&mac[0], h0);
192192+ U64TO8(&mac[8], h1);
193193+194194+ /* zero out the state */
195195+ st->h[0] = 0;
196196+ st->h[1] = 0;
197197+ st->h[2] = 0;
198198+ st->r[0] = 0;
199199+ st->r[1] = 0;
200200+ st->r[2] = 0;
201201+ st->pad[0] = 0;
202202+ st->pad[1] = 0;
203203+}
204204+
+75
src/native/poly1305-donna.c
···11+// from https://github.com/floodyberry/poly1305-donna.git
22+33+#include "mirage_crypto.h"
44+55+typedef struct poly1305_context {
66+ size_t aligner;
77+ unsigned char opaque[136];
88+} poly1305_context;
99+1010+#if defined (__x86_64__) || defined (__aarch64__)
1111+#include "poly1305-donna-64.h"
1212+#else
1313+#include "poly1305-donna-32.h"
1414+#endif
1515+1616+void
1717+poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
1818+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
1919+ size_t i;
2020+2121+ /* handle leftover */
2222+ if (st->leftover) {
2323+ size_t want = (poly1305_block_size - st->leftover);
2424+ if (want > bytes)
2525+ want = bytes;
2626+ for (i = 0; i < want; i++)
2727+ st->buffer[st->leftover + i] = m[i];
2828+ bytes -= want;
2929+ m += want;
3030+ st->leftover += want;
3131+ if (st->leftover < poly1305_block_size)
3232+ return;
3333+ poly1305_blocks(st, st->buffer, poly1305_block_size);
3434+ st->leftover = 0;
3535+ }
3636+3737+ /* process full blocks */
3838+ if (bytes >= poly1305_block_size) {
3939+ size_t want = (bytes & ~(poly1305_block_size - 1));
4040+ poly1305_blocks(st, m, want);
4141+ m += want;
4242+ bytes -= want;
4343+ }
4444+4545+ /* store leftover */
4646+ if (bytes) {
4747+ for (i = 0; i < bytes; i++)
4848+ st->buffer[st->leftover + i] = m[i];
4949+ st->leftover += bytes;
5050+ }
5151+}
5252+5353+//stubs for OCaml
5454+CAMLprim value mc_poly1305_init (value ctx, value key, value off) {
5555+ poly1305_init ((poly1305_context *) Bytes_val(ctx), _ba_uint8_off(key, off));
5656+ return Val_unit;
5757+}
5858+5959+CAMLprim value mc_poly1305_update (value ctx, value buf, value off, value len) {
6060+ poly1305_update ((poly1305_context *) Bytes_val(ctx), _ba_uint8_off(buf, off), Int_val(len));
6161+ return Val_unit;
6262+}
6363+6464+CAMLprim value mc_poly1305_finalize (value ctx, value mac, value off) {
6565+ poly1305_finish ((poly1305_context *) Bytes_val(ctx), _ba_uint8_off(mac, off));
6666+ return Val_unit;
6767+}
6868+6969+CAMLprim value mc_poly1305_ctx_size (__unit ()) {
7070+ return Val_int(sizeof(poly1305_context));
7171+}
7272+7373+CAMLprim value mc_poly1305_mac_size (__unit ()) {
7474+ return Val_int(16);
7575+}
+57
src/poly1305.ml
···11+module type S = sig
22+ type mac = Cstruct.t
33+ type 'a iter = 'a Uncommon.iter
44+55+ type t
66+ val mac_size : int
77+88+ val empty : key:Cstruct.t -> t
99+ val feed : t -> Cstruct.t -> t
1010+ val feedi : t -> Cstruct.t iter -> t
1111+ val get : t -> Cstruct.t
1212+1313+ val mac : key:Cstruct.t -> Cstruct.t -> mac
1414+ val maci : key:Cstruct.t -> Cstruct.t iter -> mac
1515+end
1616+1717+module It : S = struct
1818+ type mac = Cstruct.t
1919+ type 'a iter = 'a Uncommon.iter
2020+2121+ module P = Native.Poly1305
2222+ let mac_size = P.mac_size ()
2323+2424+ type t = Native.ctx
2525+2626+ let dup = Bytes.copy
2727+2828+ let empty ~key:{ Cstruct.buffer ; off ; len } =
2929+ let ctx = Bytes.create (P.ctx_size ()) in
3030+ if len <> 32 then invalid_arg "Poly1305 key must be 32 bytes" ;
3131+ P.init ctx buffer off ;
3232+ ctx
3333+3434+ let update ctx { Cstruct.buffer ; off ; len } =
3535+ P.update ctx buffer off len
3636+3737+ let feed ctx cs =
3838+ let t = dup ctx in
3939+ update t cs ;
4040+ t
4141+4242+ let feedi ctx iter =
4343+ let t = dup ctx in
4444+ iter (update t) ;
4545+ t
4646+4747+ let final ctx =
4848+ let res = Cstruct.create mac_size in
4949+ P.finalize ctx res.buffer res.off;
5050+ res
5151+5252+ let get ctx = final (dup ctx)
5353+5454+ let mac ~key data = feed (empty ~key) data |> final
5555+5656+ let maci ~key iter = feedi (empty ~key) iter |> final
5757+end
+263
tests/test_cipher.ml
···413413 ]
414414415415416416+let chacha20_cases =
417417+ let case msg ?ctr ~key ~nonce ?(input = Cstruct.create 128) output =
418418+ let key = vx key
419419+ and nonce = vx nonce
420420+ and output = vx output
421421+ in
422422+ assert_cs_equal ~msg (Chacha20.crypt ~key ~nonce ?ctr input) output
423423+ in
424424+ let rfc8439_input = Cstruct.of_string "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." in
425425+ let rfc8439_test_2_4_2 _ =
426426+ let key = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
427427+ and nonce = "000000000000004a00000000"
428428+ and output =
429429+{|6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81
430430+ e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b
431431+ f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57
432432+ 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8
433433+ 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e
434434+ 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36
435435+ 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42
436436+ 87 4d|}
437437+ in
438438+ case "Chacha20 RFC 8439 2.4.2" ~ctr:1L ~key ~nonce ~input:rfc8439_input output
439439+ and rfc8439_test_2_8_2 _ =
440440+ let key = vx "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
441441+ and adata = vx "50515253c0c1c2c3c4c5c6c7"
442442+ and nonce = vx "0700000040 41424344454647"
443443+ and output = vx {|
444444+ d3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2
445445+ a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6
446446+ 3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b
447447+ 1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36
448448+ 92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58
449449+ fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc
450450+ 3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b
451451+ 61 16
452452+ 1a e1 0b 59 4f 09 e2 6a 7e 90 2e cb d0 60 06 91|}
453453+ in
454454+ assert_cs_equal ~msg:"Chacha20/Poly1305 RFC 8439 2.8.2 encrypt"
455455+ (Chacha20.aead_poly1305_encrypt ~key ~nonce ~adata rfc8439_input)
456456+ output;
457457+ assert_cs_equal ~msg:"Chacha20/Poly1305 RFC 8439 2.8.2 decrypt"
458458+ (match Chacha20.aead_poly1305_decrypt ~key ~nonce ~adata output with
459459+ | Some cs -> cs | None -> assert false)
460460+ rfc8439_input;
461461+ let input = Cstruct.(shift (append (create 16) rfc8439_input) 16) in
462462+ assert_cs_equal ~msg:"Chacha20/Poly1305 RFC 8439 2.8.2 encrypt 2"
463463+ (Chacha20.aead_poly1305_encrypt ~key ~nonce ~adata input)
464464+ output;
465465+ in
466466+ (* from https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 *)
467467+ let case ~key ~nonce ~output0 ~output1 _ =
468468+ case "chacha20 crypt" ~key ~nonce (output0 ^ output1)
469469+ in
470470+ List.map test_case
471471+ [
472472+ rfc8439_test_2_4_2 ;
473473+474474+ rfc8439_test_2_8_2 ;
475475+476476+ case
477477+ ~key:(String.make 64 '0')
478478+ ~nonce:(String.make 16 '0')
479479+ ~output0:("76b8e0ada0f13d90405d6ae55386bd28" ^
480480+ "bdd219b8a08ded1aa836efcc8b770dc7" ^
481481+ "da41597c5157488d7724e03fb8d84a37" ^
482482+ "6a43b8f41518a11cc387b669b2ee6586")
483483+ ~output1:("9f07e7be5551387a98ba977c732d080d" ^
484484+ "cb0f29a048e3656912c6533e32ee7aed" ^
485485+ "29b721769ce64e43d57133b074d839d5" ^
486486+ "31ed1f28510afb45ace10a1f4b794d6f") ;
487487+488488+ case
489489+ ~key:("01" ^ String.make 62 '0')
490490+ ~nonce:(String.make 16 '0')
491491+ ~output0:("c5d30a7ce1ec119378c84f487d775a85" ^
492492+ "42f13ece238a9455e8229e888de85bbd" ^
493493+ "29eb63d0a17a5b999b52da22be4023eb" ^
494494+ "07620a54f6fa6ad8737b71eb0464dac0")
495495+ ~output1:("10f656e6d1fd55053e50c4875c9930a3" ^
496496+ "3f6d0263bd14dfd6ab8c70521c19338b" ^
497497+ "2308b95cf8d0bb7d202d2102780ea352" ^
498498+ "8f1cb48560f76b20f382b942500fceac") ;
499499+500500+ case
501501+ ~key:(String.make 64 '0')
502502+ ~nonce:("01" ^ String.make 14 '0')
503503+ ~output0:("ef3fdfd6c61578fbf5cf35bd3dd33b80" ^
504504+ "09631634d21e42ac33960bd138e50d32" ^
505505+ "111e4caf237ee53ca8ad6426194a8854" ^
506506+ "5ddc497a0b466e7d6bbdb0041b2f586b")
507507+ ~output1:("5305e5e44aff19b235936144675efbe4" ^
508508+ "409eb7e8e5f1430f5f5836aeb49bb532" ^
509509+ "8b017c4b9dc11f8a03863fa803dc71d5" ^
510510+ "726b2b6b31aa32708afe5af1d6b69058") ;
511511+512512+ case
513513+ ~key:(String.make 64 'f')
514514+ ~nonce:(String.make 16 'f')
515515+ ~output0:("d9bf3f6bce6ed0b54254557767fb5744" ^
516516+ "3dd4778911b606055c39cc25e674b836" ^
517517+ "3feabc57fde54f790c52c8ae43240b79" ^
518518+ "d49042b777bfd6cb80e931270b7f50eb")
519519+ ~output1:("5bac2acd86a836c5dc98c116c1217ec3" ^
520520+ "1d3a63a9451319f097f3b4d6dab07787" ^
521521+ "19477d24d24b403a12241d7cca064f79" ^
522522+ "0f1d51ccaff6b1667d4bbca1958c4306") ;
523523+524524+ case
525525+ ~key:(String.make 64 '5')
526526+ ~nonce:(String.make 16 '5')
527527+ ~output0:("bea9411aa453c5434a5ae8c92862f564" ^
528528+ "396855a9ea6e22d6d3b50ae1b3663311" ^
529529+ "a4a3606c671d605ce16c3aece8e61ea1" ^
530530+ "45c59775017bee2fa6f88afc758069f7")
531531+ ~output1:("e0b8f676e644216f4d2a3422d7fa36c6" ^
532532+ "c4931aca950e9da42788e6d0b6d1cd83" ^
533533+ "8ef652e97b145b14871eae6c6804c700" ^
534534+ "4db5ac2fce4c68c726d004b10fcaba86") ;
535535+536536+ case
537537+ ~key:(String.make 64 'a')
538538+ ~nonce:(String.make 16 'a')
539539+ ~output0:("9aa2a9f656efde5aa7591c5fed4b35ae" ^
540540+ "a2895dec7cb4543b9e9f21f5e7bcbcf3" ^
541541+ "c43c748a970888f8248393a09d43e0b7" ^
542542+ "e164bc4d0b0fb240a2d72115c4808906")
543543+ ~output1:("72184489440545d021d97ef6b693dfe5" ^
544544+ "b2c132d47e6f041c9063651f96b623e6" ^
545545+ "2a11999a23b6f7c461b2153026ad5e86" ^
546546+ "6a2e597ed07b8401dec63a0934c6b2a9") ;
547547+548548+ case
549549+ ~key:"00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100"
550550+ ~nonce:"0f1e2d3c4b5a6978"
551551+ ~output0:("9fadf409c00811d00431d67efbd88fba" ^
552552+ "59218d5d6708b1d685863fabbb0e961e" ^
553553+ "ea480fd6fb532bfd494b215101505742" ^
554554+ "3ab60a63fe4f55f7a212e2167ccab931")
555555+ ~output1:("fbfd29cf7bc1d279eddf25dd316bb884" ^
556556+ "3d6edee0bd1ef121d12fa17cbc2c574c" ^
557557+ "ccab5e275167b08bd686f8a09df87ec3" ^
558558+ "ffb35361b94ebfa13fec0e4889d18da5") ;
559559+560560+ case
561561+ ~key:"c46ec1b18ce8a878725a37e780dfb7351f68ed2e194c79fbc6aebee1a667975d"
562562+ ~nonce:"1ada31d5cf688221"
563563+ ~output0:("f63a89b75c2271f9368816542ba52f06" ^
564564+ "ed49241792302b00b5e8f80ae9a473af" ^
565565+ "c25b218f519af0fdd406362e8d69de7f" ^
566566+ "54c604a6e00f353f110f771bdca8ab92")
567567+ ~output1:("e5fbc34e60a1d9a9db17345b0a402736" ^
568568+ "853bf910b060bdf1f897b6290f01d138" ^
569569+ "ae2c4c90225ba9ea14d518f55929dea0" ^
570570+ "98ca7a6ccfe61227053c84e49a4a3332") ;
571571+572572+ case
573573+ ~key:(String.make 32 '0')
574574+ ~nonce:(String.make 16 '0')
575575+ ~output0:("89670952608364fd00b2f90936f031c8" ^
576576+ "e756e15dba04b8493d00429259b20f46" ^
577577+ "cc04f111246b6c2ce066be3bfb32d9aa" ^
578578+ "0fddfbc12123d4b9e44f34dca05a103f")
579579+ ~output1:("6cd135c2878c832b5896b134f6142a9d" ^
580580+ "4d8d0d8f1026d20a0a81512cbce6e975" ^
581581+ "8a7143d021978022a384141a80cea306" ^
582582+ "2f41f67a752e66ad3411984c787e30ad") ;
583583+584584+ case
585585+ ~key:("01" ^ String.make 30 '0')
586586+ ~nonce:(String.make 16 '0')
587587+ ~output0:("ae56060d04f5b597897ff2af1388dbce" ^
588588+ "ff5a2a4920335dc17a3cb1b1b10fbe70" ^
589589+ "ece8f4864d8c7cdf0076453a8291c7db" ^
590590+ "eb3aa9c9d10e8ca36be4449376ed7c42")
591591+ ~output1:("fc3d471c34a36fbbf616bc0a0e7c5230" ^
592592+ "30d944f43ec3e78dd6a12466547cb4f7" ^
593593+ "b3cebd0a5005e762e562d1375b7ac445" ^
594594+ "93a991b85d1a60fba2035dfaa2a642d5") ;
595595+596596+ case
597597+ ~key:(String.make 32 '0')
598598+ ~nonce:("01" ^ String.make 14 '0')
599599+ ~output0:("1663879eb3f2c9949e2388caa343d361" ^
600600+ "bb132771245ae6d027ca9cb010dc1fa7" ^
601601+ "178dc41f8278bc1f64b3f12769a24097" ^
602602+ "f40d63a86366bdb36ac08abe60c07fe8")
603603+ ~output1:("b057375c89144408cc744624f69f7f4c" ^
604604+ "cbd93366c92fc4dfcada65f1b959d8c6" ^
605605+ "4dfc50de711fb46416c2553cc60f21bb" ^
606606+ "fd006491cb17888b4fb3521c4fdd8745") ;
607607+608608+ case
609609+ ~key:(String.make 32 'f')
610610+ ~nonce:(String.make 16 'f')
611611+ ~output0:("992947c3966126a0e660a3e95db048de" ^
612612+ "091fb9e0185b1e41e41015bb7ee50150" ^
613613+ "399e4760b262f9d53f26d8dd19e56f5c" ^
614614+ "506ae0c3619fa67fb0c408106d0203ee")
615615+ ~output1:("40ea3cfa61fa32a2fda8d1238a2135d9" ^
616616+ "d4178775240f99007064a6a7f0c731b6" ^
617617+ "7c227c52ef796b6bed9f9059ba0614bc" ^
618618+ "f6dd6e38917f3b150e576375be50ed67") ;
619619+620620+ case
621621+ ~key:(String.make 32 '5')
622622+ ~nonce:(String.make 16 '5')
623623+ ~output0:("357d7d94f966778f5815a2051dcb0413" ^
624624+ "3b26b0ead9f57dd09927837bc3067e4b" ^
625625+ "6bf299ad81f7f50c8da83c7810bfc17b" ^
626626+ "b6f4813ab6c326957045fd3fd5e19915")
627627+ ~output1:("ec744a6b9bf8cbdcb36d8b6a5499c68a" ^
628628+ "08ef7be6cc1e93f2f5bcd2cad4e47c18" ^
629629+ "a3e5d94b5666382c6d130d822dd56aac" ^
630630+ "b0f8195278e7b292495f09868ddf12cc") ;
631631+632632+ case
633633+ ~key:(String.make 32 'a')
634634+ ~nonce:(String.make 16 'a')
635635+ ~output0:("fc79acbd58526103862776aab20f3b7d" ^
636636+ "8d3149b2fab65766299316b6e5b16684" ^
637637+ "de5de548c1b7d083efd9e3052319e0c6" ^
638638+ "254141da04a6586df800f64d46b01c87")
639639+ ~output1:("1f05bc67e07628ebe6f6865a2177e0b6" ^
640640+ "6a558aa7cc1e8ff1a98d27f7071f8335" ^
641641+ "efce4537bb0ef7b573b32f32765f2900" ^
642642+ "7da53bba62e7a44d006f41eb28fe15d6") ;
643643+644644+ case
645645+ ~key:"00112233445566778899aabbccddeeff"
646646+ ~nonce:"0f1e2d3c4b5a6978"
647647+ ~output0:("d1abf630467eb4f67f1cfb47cd626aae" ^
648648+ "8afedbbe4ff8fc5fe9cfae307e74ed45" ^
649649+ "1f1404425ad2b54569d5f18148939971" ^
650650+ "abb8fafc88ce4ac7fe1c3d1f7a1eb7ca")
651651+ ~output1:("e76ca87b61a9713541497760dd9ae059" ^
652652+ "350cad0dcedfaa80a883119a1a6f987f" ^
653653+ "d1ce91fd8ee0828034b411200a9745a2" ^
654654+ "85554475d12afc04887fef3516d12a2c") ;
655655+656656+ case
657657+ ~key:"c46ec1b18ce8a878725a37e780dfb735"
658658+ ~nonce:"1ada31d5cf688221"
659659+ ~output0:("826abdd84460e2e9349f0ef4af5b179b" ^
660660+ "426e4b2d109a9c5bb44000ae51bea90a" ^
661661+ "496beeef62a76850ff3f0402c4ddc99f" ^
662662+ "6db07f151c1c0dfac2e56565d6289625")
663663+ ~output1:("5b23132e7b469c7bfb88fa95d44ca5ae" ^
664664+ "3e45e848a4108e98bad7a9eb15512784" ^
665665+ "a6a9e6e591dce674120acaf9040ff50f" ^
666666+ "f3ac30ccfb5e14204f5e4268b90a8804")
667667+ ]
668668+669669+let poly1305_rfc8439_2_5_2 _ =
670670+ let key = vx "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"
671671+ and data = Cstruct.of_string "Cryptographic Forum Research Group"
672672+ and output = vx "a8061dc1305136c6c22b8baf0c0127a9"
673673+ in
674674+ assert_cs_equal ~msg:"poly 1305 RFC8439 Section 2.5.2"
675675+ (Poly1305.mac ~key data) output
676676+416677let suite = [
417678 "AES-ECB" >::: [ "SP 300-38A" >::: aes_ecb_cases ] ;
418679 "AES-CBC" >::: [ "SP 300-38A" >::: aes_cbc_cases ] ;
···421682 "AES-CCM" >::: ccm_cases ;
422683 "AES-CCM-REGRESSION" >::: ccm_regressions ;
423684 "AES-GCM-REGRESSION" >::: gcm_regressions ;
685685+ "Chacha20" >::: chacha20_cases ;
686686+ "poly1305" >:: poly1305_rfc8439_2_5_2 ;
424687]