aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/BearSSL/src/aead
diff options
context:
space:
mode:
Diffstat (limited to 'test/monniaux/BearSSL/src/aead')
-rw-r--r--test/monniaux/BearSSL/src/aead/ccm.c346
-rw-r--r--test/monniaux/BearSSL/src/aead/eax.c526
-rw-r--r--test/monniaux/BearSSL/src/aead/gcm.c319
3 files changed, 1191 insertions, 0 deletions
diff --git a/test/monniaux/BearSSL/src/aead/ccm.c b/test/monniaux/BearSSL/src/aead/ccm.c
new file mode 100644
index 00000000..68cc913e
--- /dev/null
+++ b/test/monniaux/BearSSL/src/aead/ccm.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary.
+ *
+ * - 'ptr' contains a value from 0 to 15, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current CBC-MAC computation.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the plaintext bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available. When 'ptr' is 0, the
+ * contents of buf[] are to be ignored.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ */
+
+/* see bearssl_block.h */
+void
+br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ ctx->bctx = bctx;
+}
+
+/* see bearssl_block.h */
+int
+br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
+ uint64_t aad_len, uint64_t data_len, size_t tag_len)
+{
+ unsigned char tmp[16];
+ unsigned u, q;
+
+ if (nonce_len < 7 || nonce_len > 13) {
+ return 0;
+ }
+ if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
+ return 0;
+ }
+ q = 15 - (unsigned)nonce_len;
+ ctx->tag_len = tag_len;
+
+ /*
+ * Block B0, to start CBC-MAC.
+ */
+ tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
+ | (((unsigned)tag_len - 2) << 2)
+ | (q - 1);
+ memcpy(tmp + 1, nonce, nonce_len);
+ for (u = 0; u < q; u ++) {
+ tmp[15 - u] = (unsigned char)data_len;
+ data_len >>= 8;
+ }
+ if (data_len != 0) {
+ /*
+ * If the data length was not entirely consumed in the
+ * loop above, then it exceeds the maximum limit of
+ * q bytes (when encoded).
+ */
+ return 0;
+ }
+
+ /*
+ * Start CBC-MAC.
+ */
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
+
+ /*
+ * Assemble AAD length header.
+ */
+ if ((aad_len >> 32) != 0) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFF;
+ br_enc64be(ctx->buf + 2, aad_len);
+ ctx->ptr = 10;
+ } else if (aad_len >= 0xFF00) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFE;
+ br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
+ ctx->ptr = 6;
+ } else if (aad_len > 0) {
+ br_enc16be(ctx->buf, (unsigned)aad_len);
+ ctx->ptr = 2;
+ } else {
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Make initial counter value and compute tag mask.
+ */
+ ctx->ctr[0] = q - 1;
+ memcpy(ctx->ctr + 1, nonce, nonce_len);
+ memset(ctx->ctr + 1 + nonce_len, 0, q);
+ memset(ctx->tagmask, 0, sizeof ctx->tagmask);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->tagmask, sizeof ctx->tagmask);
+
+ return 1;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
+{
+ const unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete partial block, if needed.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ memcpy(ctx->buf + ptr, dbuf, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, dbuf, clen);
+ dbuf += clen;
+ len -= clen;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process complete blocks.
+ */
+ ptr = len & 15;
+ len -= ptr;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
+ dbuf += len;
+
+ /*
+ * Copy last partial block in the context buffer.
+ */
+ memcpy(ctx->buf, dbuf, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_flip(br_ccm_context *ctx)
+{
+ size_t ptr;
+
+ /*
+ * Complete AAD partial block with zeros, if necessary.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Counter was already set by br_ccm_reset().
+ */
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete a partial block, if any: ctx->buf[] contains
+ * ctx->ptr plaintext bytes (already reported), and the other
+ * bytes are CTR stream output.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+ size_t u;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[ptr + u];
+ x = dbuf[u];
+ ctx->buf[ptr + u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned w;
+
+ w = ctx->buf[ptr + u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[ptr + u] = w;
+ }
+ }
+ dbuf += clen;
+ len -= clen;
+ ptr += clen;
+ if (ptr < sizeof ctx->buf) {
+ ctx->ptr = ptr;
+ return;
+ }
+ (*ctx->bctx)->mac(ctx->bctx,
+ ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process all complete blocks. Note that the ctrcbc API is for
+ * encrypt-then-MAC (CBC-MAC is computed over the encrypted
+ * blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
+ * over the plaintext blocks). Therefore, we need to use the
+ * _decryption_ function for encryption, and the encryption
+ * function for decryption (this works because CTR encryption
+ * and decryption are identical, so the choice really is about
+ * computing the CBC-MAC before or after XORing with the CTR
+ * stream).
+ */
+ ptr = len & 15;
+ len -= ptr;
+ if (encrypt) {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * If there is some remaining data, then we need to compute an
+ * extra block of CTR stream.
+ */
+ if (ptr != 0) {
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[u];
+ x = dbuf[u];
+ ctx->buf[u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w;
+
+ w = ctx->buf[u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[u] = w;
+ }
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+size_t
+br_ccm_get_tag(br_ccm_context *ctx, void *tag)
+{
+ size_t ptr;
+ size_t u;
+
+ /*
+ * If there is some buffered data, then we need to pad it with
+ * zeros and finish up CBC-MAC.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * XOR the tag mask into the CBC-MAC output.
+ */
+ for (u = 0; u < ctx->tag_len; u ++) {
+ ctx->cbcmac[u] ^= ctx->tagmask[u];
+ }
+ memcpy(tag, ctx->cbcmac, ctx->tag_len);
+ return ctx->tag_len;
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
+{
+ unsigned char tmp[16];
+ size_t u, tag_len;
+ uint32_t z;
+
+ tag_len = br_ccm_get_tag(ctx, tmp);
+ z = 0;
+ for (u = 0; u < tag_len; u ++) {
+ z |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(z);
+}
diff --git a/test/monniaux/BearSSL/src/aead/eax.c b/test/monniaux/BearSSL/src/aead/eax.c
new file mode 100644
index 00000000..f0351b01
--- /dev/null
+++ b/test/monniaux/BearSSL/src/aead/eax.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary. Moreover, EAX has a special padding
+ * rule for CBC-MAC, which implies that we cannot compute the MAC over
+ * the last received full block until we know whether we are at the
+ * end of the data or not.
+ *
+ * - 'ptr' contains a value from 1 to 16, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current OMAC computation. Beware that this can go to 16: a
+ * complete block cannot be processed until it is known whether it
+ * is the last block or not. However, it can never be 0, because
+ * OMAC^t works on an input that is at least one-block long.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the encrypted bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ *
+ * - The derived keys for padding are kept in L2 and L4 (double and
+ * quadruple of Enc_K(0^n), in GF(2^128), respectively).
+ */
+
+/*
+ * Start an OMAC computation; the first block is the big-endian
+ * representation of the provided value ('val' must fit on one byte).
+ * We make it a delayed block because it may also be the last one,
+ */
+static void
+omac_start(br_eax_context *ctx, unsigned val)
+{
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->buf[15] = val;
+ ctx->ptr = 16;
+}
+
+/*
+ * Double a value in finite field GF(2^128), defined with modulus
+ * X^128+X^7+X^2+X+1.
+ */
+static void
+double_gf128(unsigned char *dst, const unsigned char *src)
+{
+ unsigned cc;
+ int i;
+
+ cc = 0x87 & -((unsigned)src[0] >> 7);
+ for (i = 15; i >= 0; i --) {
+ unsigned z;
+
+ z = (src[i] << 1) ^ cc;
+ cc = z >> 8;
+ dst[i] = (unsigned char)z;
+ }
+}
+
+/*
+ * Apply padding to the last block, currently in ctx->buf (with
+ * ctx->ptr bytes), and finalize OMAC computation.
+ */
+static void
+do_pad(br_eax_context *ctx)
+{
+ unsigned char *pad;
+ size_t ptr, u;
+
+ ptr = ctx->ptr;
+ if (ptr == 16) {
+ pad = ctx->L2;
+ } else {
+ ctx->buf[ptr ++] = 0x80;
+ memset(ctx->buf + ptr, 0x00, 16 - ptr);
+ pad = ctx->L4;
+ }
+ for (u = 0; u < sizeof ctx->buf; u ++) {
+ ctx->buf[u] ^= pad[u];
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ KILL_TAIL_CALL();
+}
+
+/*
+ * Apply CBC-MAC on the provided data, with buffering management.
+ *
+ * Upon entry, two situations are acceptable:
+ *
+ * ctx->ptr == 0: there is no data to process in ctx->buf
+ * ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
+ *
+ * Upon exit, ctx->ptr may be zero only if it was already zero on entry,
+ * and len == 0. In all other situations, ctx->ptr will be non-zero on
+ * exit (and may have value 16).
+ */
+static void
+do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ if (len == 0) {
+ return;
+ }
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (ctx->ptr == 16) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
+ memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ unsigned char tmp[16], iv[16];
+
+ ctx->vtable = &br_eax_vtable;
+ ctx->bctx = bctx;
+
+ /*
+ * Encrypt a whole-zero block to compute L2 and L4.
+ */
+ memset(tmp, 0, sizeof tmp);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
+ double_gf128(ctx->L2, tmp);
+ double_gf128(ctx->L4, ctx->L2);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_capture(const br_eax_context *ctx, br_eax_state *st)
+{
+ /*
+ * We capture the three OMAC* states _after_ processing the
+ * initial block (assuming that nonce, message and AAD are
+ * all non-empty).
+ */
+ int i;
+
+ memset(st->st, 0, sizeof st->st);
+ for (i = 0; i < 3; i ++) {
+ unsigned char tmp[16];
+
+ memset(tmp, 0, sizeof tmp);
+ tmp[15] = (unsigned char)i;
+ (*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
+{
+ /*
+ * Process nonce with OMAC^0.
+ */
+ omac_start(ctx, 0);
+ do_cbcmac_chunk(ctx, nonce, len);
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^1 for the AAD ("header" in the EAX specification).
+ */
+ omac_start(ctx, 1);
+
+ /*
+ * We use ctx->head[0] as temporary flag to mark that we are
+ * using a "normal" reset().
+ */
+ ctx->head[0] = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+
+ memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
+
+ /*
+ * We use ctx->head[0] as a flag to indicate that we use a
+ * a recorded state, with ctx->ctr containing the preprocessed
+ * first block for OMAC^2.
+ */
+ ctx->head[0] = 1;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+
+ memcpy(ctx->head, st->st[1], sizeof ctx->head);
+
+ memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ ptr = ctx->ptr;
+
+ /*
+ * If there is a partial block, first complete it.
+ */
+ if (ptr < 16) {
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a full block in buf[], and this is not the last
+ * block.
+ */
+ do_cbcmac_chunk(ctx, data, len);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_flip(br_eax_context *ctx)
+{
+ int from_capture;
+
+ /*
+ * ctx->head[0] may be non-zero if the context was reset with
+ * a pre-AAD captured state. In that case, ctx->ctr[] contains
+ * the state for OMAC^2 _after_ processing the first block.
+ */
+ from_capture = ctx->head[0];
+
+ /*
+ * Complete the OMAC computation on the AAD.
+ */
+ do_pad(ctx);
+ memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^2 for the encrypted data.
+ * If the context was initialized from a captured state, then
+ * the OMAC^2 value is in the ctr[] array.
+ */
+ if (from_capture) {
+ memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ } else {
+ omac_start(ctx, 2);
+ }
+
+ /*
+ * Initial counter value for CTR is the processed nonce.
+ */
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ /*
+ * Ensure that there is actual data to process.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ dbuf = data;
+ ptr = ctx->ptr;
+
+ /*
+ * We may have ptr == 0 here if we initialized from a captured
+ * state. In that case, there is no partially consumed block
+ * or unprocessed data.
+ */
+ if (ptr != 0 && ptr != 16) {
+ /*
+ * We have a partially consumed block.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ ctx->buf[ptr + u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf + ptr, clen);
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[ptr + u];
+ dx = dbuf[u];
+ ctx->buf[ptr + u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+
+ if (len <= clen) {
+ ctx->ptr = ptr + clen;
+ return;
+ }
+ dbuf += clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a complete encrypted block in buf[] that must still
+ * be processed with OMAC, and this is not the final buf.
+ * Exception: when ptr == 0, no block has been produced yet.
+ */
+ if (ptr != 0) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Do CTR encryption or decryption and CBC-MAC for all full blocks
+ * except the last.
+ */
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (encrypt) {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * Compute next block of CTR stream, and use it to finish
+ * encrypting or decrypting the data.
+ */
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ ctx->buf[u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf, ptr);
+ } else {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[u];
+ dx = dbuf[u];
+ ctx->buf[u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/*
+ * Complete tag computation. The final tag is written in ctx->cbcmac.
+ */
+static void
+do_final(br_eax_context *ctx)
+{
+ size_t u;
+
+ do_pad(ctx);
+
+ /*
+ * Authentication tag is the XOR of the three OMAC outputs for
+ * the nonce, AAD and encrypted data.
+ */
+ for (u = 0; u < 16; u ++) {
+ ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag(br_eax_context *ctx, void *tag)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_eax_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag(br_eax_context *ctx, const void *tag)
+{
+ return br_eax_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_eax_vtable = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_eax_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_eax_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_eax_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_eax_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_eax_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_check_tag_trunc
+};
diff --git a/test/monniaux/BearSSL/src/aead/gcm.c b/test/monniaux/BearSSL/src/aead/gcm.c
new file mode 100644
index 00000000..8b1b5dba
--- /dev/null
+++ b/test/monniaux/BearSSL/src/aead/gcm.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * Since CTR and GHASH implementations can handle only full blocks, a
+ * 16-byte buffer (buf[]) is maintained in the context:
+ *
+ * - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
+ *
+ * - When doing CTR encryption / decryption, buf[] contains the AES output
+ * for the last partial block, to be used with the next few bytes of
+ * data, as well as the already encrypted bytes. For instance, if the
+ * processed data length so far is 21 bytes, then buf[0..4] contains
+ * the five last encrypted bytes, and buf[5..15] contains the next 11
+ * AES output bytes to be XORed with the next 11 bytes of input.
+ *
+ * The recorded AES output bytes are used to complete the block when
+ * the corresponding bytes are obtained. Note that buf[] always
+ * contains the _encrypted_ bytes, whether we apply encryption or
+ * decryption: these bytes are used as input to GHASH when the block
+ * is complete.
+ *
+ * In both cases, the low bits of the data length counters (count_aad,
+ * count_ctr) are used to work out the current situation.
+ */
+
+/* see bearssl_aead.h */
+void
+br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
+{
+ unsigned char iv[12];
+
+ ctx->vtable = &br_gcm_vtable;
+ ctx->bctx = bctx;
+ ctx->gh = gh;
+
+ /*
+ * The GHASH key h[] is the raw encryption of the all-zero
+ * block. Since we only have a CTR implementation, we use it
+ * with an all-zero IV and a zero counter, to CTR-encrypt an
+ * all-zero block.
+ */
+ memset(ctx->h, 0, sizeof ctx->h);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
+{
+ /*
+ * If the provided nonce is 12 bytes, then this is the initial
+ * IV for CTR mode; it will be used with a counter that starts
+ * at 2 (value 1 is for encrypting the GHASH output into the tag).
+ *
+ * If the provided nonce has any other length, then it is hashed
+ * (with GHASH) into a 16-byte value that will be the IV for CTR
+ * (both 12-byte IV and 32-bit counter).
+ */
+ if (len == 12) {
+ memcpy(ctx->j0_1, iv, 12);
+ ctx->j0_2 = 1;
+ } else {
+ unsigned char ty[16], tmp[16];
+
+ memset(ty, 0, sizeof ty);
+ ctx->gh(ty, ctx->h, iv, len);
+ memset(tmp, 0, 8);
+ br_enc64be(tmp + 8, (uint64_t)len << 3);
+ ctx->gh(ty, ctx->h, tmp, 16);
+ memcpy(ctx->j0_1, ty, 12);
+ ctx->j0_2 = br_dec32be(ty + 12);
+ }
+ ctx->jc = ctx->j0_2 + 1;
+ memset(ctx->y, 0, sizeof ctx->y);
+ ctx->count_aad = 0;
+ ctx->count_ctr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
+{
+ size_t ptr, dlen;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If there is a partial block, then we first try to
+ * complete it.
+ */
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->count_aad += (uint64_t)len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ ctx->count_aad += (uint64_t)clen;
+ }
+
+ /*
+ * Now AAD is aligned on a 16-byte block (with regards to GHASH).
+ * We process all complete blocks, and save the last partial
+ * block.
+ */
+ dlen = len & ~(size_t)15;
+ ctx->gh(ctx->y, ctx->h, data, dlen);
+ memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
+ ctx->count_aad += (uint64_t)len;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_flip(br_gcm_context *ctx)
+{
+ /*
+ * We complete the GHASH computation if there is a partial block.
+ * The GHASH implementation automatically applies padding with
+ * zeros.
+ */
+ size_t ptr;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+ KILL_TAIL_CALL();
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *buf;
+ size_t ptr, dlen;
+
+ buf = data;
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If we have a partial block, then we try to complete it.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ clen = len;
+ }
+ for (u = 0; u < clen; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[ptr + u];
+ ctx->buf[ptr + u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)clen;
+ buf += clen;
+ len -= clen;
+ if (ptr + clen < 16) {
+ return;
+ }
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ }
+
+ /*
+ * Process full blocks.
+ */
+ dlen = len & ~(size_t)15;
+ if (!encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
+ if (encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ buf += dlen;
+ len -= dlen;
+ ctx->count_ctr += (uint64_t)dlen;
+
+ if (len > 0) {
+ /*
+ * There is a partial block.
+ */
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
+ ctx->jc, ctx->buf, 16);
+ for (u = 0; u < len; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[u];
+ ctx->buf[u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)len;
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag(br_gcm_context *ctx, void *tag)
+{
+ size_t ptr;
+ unsigned char tmp[16];
+
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr > 0) {
+ /*
+ * There is a partial block: encrypted/decrypted data has
+ * been produced, but the encrypted bytes must still be
+ * processed by GHASH.
+ */
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+
+ /*
+ * Final block for GHASH: the AAD and plaintext lengths (in bits).
+ */
+ br_enc64be(tmp, ctx->count_aad << 3);
+ br_enc64be(tmp + 8, ctx->count_ctr << 3);
+ ctx->gh(ctx->y, ctx->h, tmp, 16);
+
+ /*
+ * Tag is the GHASH output XORed with the encryption of the
+ * nonce with the initial counter value.
+ */
+ memcpy(tag, ctx->y, 16);
+ (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
+{
+ unsigned char tmp[16];
+
+ br_gcm_get_tag(ctx, tmp);
+ memcpy(tag, tmp, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_gcm_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
+{
+ return br_gcm_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_gcm_vtable = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_gcm_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_gcm_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_gcm_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_gcm_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_gcm_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_check_tag_trunc
+};