| /* |
| * cifra - embedded cryptography library |
| * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com> |
| * |
| * To the extent possible under law, the author(s) have dedicated all |
| * copyright and related and neighboring rights to this software to the |
| * public domain worldwide. This software is distributed without any |
| * warranty. |
| * |
| * You should have received a copy of the CC0 Public Domain Dedication |
| * along with this software. If not, see |
| * <http://creativecommons.org/publicdomain/zero/1.0/>. |
| */ |
| |
| #include "handy.h" |
| #include "prp.h" |
| #include "modes.h" |
| #include "tassert.h" |
| |
| #include <string.h> |
| |
| static void cmac_compute_n(cf_cmac_stream *ctx, |
| uint8_t t, |
| const uint8_t *input, size_t ninput, |
| uint8_t out[CF_MAXBLOCK]) |
| { |
| size_t blocksz = ctx->cmac.prp->blocksz; |
| assert(blocksz > 0); |
| |
| uint8_t firstblock[CF_MAXBLOCK]; |
| memset(firstblock, 0, blocksz); |
| firstblock[blocksz - 1] = t; |
| |
| cf_cmac_stream_reset(ctx); |
| if (ninput) |
| { |
| cf_cmac_stream_update(ctx, firstblock, blocksz, 0); |
| cf_cmac_stream_update(ctx, input, ninput, 1); |
| } else { |
| cf_cmac_stream_update(ctx, firstblock, blocksz, 1); |
| } |
| |
| cf_cmac_stream_final(ctx, out); |
| } |
| |
| void cf_eax_encrypt(const cf_prp *prp, void *prpctx, |
| const uint8_t *plain, size_t nplain, |
| const uint8_t *header, size_t nheader, |
| const uint8_t *nonce, size_t nnonce, |
| uint8_t *cipher, /* the same size as nplain */ |
| uint8_t *tag, size_t ntag) |
| { |
| uint8_t NN[CF_MAXBLOCK], |
| HH[CF_MAXBLOCK], |
| CC[CF_MAXBLOCK]; |
| |
| cf_cmac_stream cmac; |
| cf_cmac_stream_init(&cmac, prp, prpctx); |
| |
| /* NN = OMAC_K^0(N) */ |
| cmac_compute_n(&cmac, 0, nonce, nnonce, NN); |
| |
| /* HH = OMAC_K^1(H) */ |
| cmac_compute_n(&cmac, 1, header, nheader, HH); |
| |
| /* C = CTR_K^NN(M) */ |
| cf_ctr ctr; |
| cf_ctr_init(&ctr, prp, prpctx, NN); |
| cf_ctr_cipher(&ctr, plain, cipher, nplain); |
| |
| /* CC = OMAC_K^2(C) */ |
| cmac_compute_n(&cmac, 2, cipher, nplain, CC); |
| |
| /* Tag = NN ^ CC ^ HH |
| * T = Tag [ first tau bits ] */ |
| assert(ntag <= prp->blocksz); |
| for (size_t i = 0; i < ntag; i++) |
| tag[i] = NN[i] ^ CC[i] ^ HH[i]; |
| } |
| |
| int cf_eax_decrypt(const cf_prp *prp, void *prpctx, |
| const uint8_t *cipher, size_t ncipher, |
| const uint8_t *header, size_t nheader, |
| const uint8_t *nonce, size_t nnonce, |
| const uint8_t *tag, size_t ntag, |
| uint8_t *plain) /* the same size as ncipher */ |
| { |
| uint8_t NN[CF_MAXBLOCK], |
| HH[CF_MAXBLOCK], |
| CC[CF_MAXBLOCK]; |
| |
| cf_cmac_stream cmac; |
| cf_cmac_stream_init(&cmac, prp, prpctx); |
| |
| /* NN = OMAC_K^0(N) */ |
| cmac_compute_n(&cmac, 0, nonce, nnonce, NN); |
| |
| /* HH = OMAC_K^1(H) */ |
| cmac_compute_n(&cmac, 1, header, nheader, HH); |
| |
| /* CC = OMAC_K^2(C) */ |
| cmac_compute_n(&cmac, 2, cipher, ncipher, CC); |
| |
| uint8_t tt[CF_MAXBLOCK]; |
| assert(ntag && ntag <= prp->blocksz); |
| for (size_t i = 0; i < ntag; i++) |
| tt[i] = NN[i] ^ CC[i] ^ HH[i]; |
| |
| if (!mem_eq(tt, tag, ntag)) |
| return 1; |
| |
| cf_ctr ctr; |
| cf_ctr_init(&ctr, prp, prpctx, NN); |
| cf_ctr_cipher(&ctr, cipher, plain, ncipher); |
| return 0; |
| } |