}
/*
- * Apply CBC-MAC on the provided data, with buffering management. This
- * function assumes that on input, ctx->buf contains a full block of
- * unprocessed data.
+ * 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)
} else {
len -= ptr;
}
- (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ 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;
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)
* 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_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.
*/
/*
* 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.
*/
- omac_start(ctx, 2);
+ 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.
dbuf = data;
ptr = ctx->ptr;
- if (ptr != 16) {
+ /*
+ * 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.
*/
/*
* 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.
*/
- (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ 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