diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2018-01-20 21:08:37 +0200 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2018-01-20 22:17:14 +0200 |
commit | e8629e535bd0e9711b07904d4501de8ad57aaecd (patch) | |
tree | ae5c5264b8df5dd07b20453cd6be608f14f3e145 /cipher/cipher-cmac.c | |
parent | cd7ed2e3546b12dd98df4211949f1cdbf5827013 (diff) | |
download | libgcrypt-e8629e535bd0e9711b07904d4501de8ad57aaecd.tar.gz |
Add EAX mode
* cipher/Makefile.am: Add 'cipher-eax.c'.
* cipher/cipher-cmac.c (cmac_write): Rename to ...
(_gcry_cmac_write): ... this; Take CMAC context as new input
parameter; Return error code.
(cmac_generate_subkeys): Rename to ...
(_gcry_cmac_generate_subkeys): ... this; Take CMAC context as new
input parameter; Return error code.
(cmac_final): Rename to ...
(_gcry_cmac_final): ... this; Take CMAC context as new input
parameter; Return error code.
(cmac_tag): Take CMAC context as new input parameter.
(_gcry_cmac_reset): New.
(_gcry_cipher_cmac_authenticate): Remove duplicate tag flag check;
Adapt to changes above.
(_gcry_cipher_cmac_get_tag): Adapt to changes above.
(_gcry_cipher_cmac_check_tag): Ditto.
(_gcry_cipher_cmac_set_subkeys): Ditto.
* cipher-eax.c: New.
* cipher-internal.h (gcry_cmac_context_t): New.
(gcry_cipher_handle): Update u_mode.cmac; Add u_mode.eax.
(_gcry_cmac_write, _gcry_cmac_generate_subkeys, _gcry_cmac_final)
(_gcry_cmac_reset, _gcry_cipher_eax_encrypt, _gcry_cipher_eax_decrypt)
(_gcry_cipher_eax_set_nonce, _gcry_cipher_eax_authenticate)
(_gcry_cipher_eax_get_tag, _gcry_cipher_eax_check_tag)
(_gcry_cipher_eax_setkey): New prototypes.
* cipher/cipher.c (_gcry_cipher_open_internal, cipher_setkey)
(cipher_reset, cipher_encrypt, cipher_decrypt, _gcry_cipher_setiv)
(_gcry_cipher_authenticate, _gcry_cipher_gettag, _gcry_cipher_checktag)
(_gcry_cipher_info): Add EAX mode.
* doc/gcrypt.texi: Add EAX mode.
* src/gcrypt.h.in (GCRY_CIPHER_MODE_EAX): New.
* tests/basic.c (_check_gcm_cipher, _check_poly1305_cipher): Constify
test vectors array.
(_check_eax_cipher, check_eax_cipher): New.
(check_ciphers, check_cipher_modes): Add EAX mode.
* tests/bench-slope.c (bench_eax_encrypt_do_bench)
(bench_eax_decrypt_do_bench, bench_eax_authenticate_do_bench)
(eax_encrypt_ops, eax_decrypt_ops, eax_authenticate_ops): New.
(cipher_modes): Add EAX mode.
* tests/benchmark.c (cipher_bench): Add EAX mode.
--
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher/cipher-cmac.c')
-rw-r--r-- | cipher/cipher-cmac.c | 137 |
1 files changed, 82 insertions, 55 deletions
diff --git a/cipher/cipher-cmac.c b/cipher/cipher-cmac.c index da3ef759..30567b7f 100644 --- a/cipher/cipher-cmac.c +++ b/cipher/cipher-cmac.c @@ -1,5 +1,5 @@ /* cmac.c - CMAC, Cipher-based MAC. - * Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * Copyright (C) 2013,2018 Jussi Kivilinna <jussi.kivilinna@iki.fi> * * This file is part of Libgcrypt. * @@ -33,8 +33,9 @@ (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) -static void -cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) +gcry_err_code_t +_gcry_cmac_write (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, + const byte * inbuf, size_t inlen) { gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; const unsigned int blocksize = c->spec->blocksize; @@ -42,31 +43,37 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) unsigned int burn = 0; unsigned int nblocks; + if (ctx->tag) + return GPG_ERR_INV_STATE; + /* Tell compiler that we require a cipher with a 64bit or 128 bit block * length, to allow better optimization of this function. */ if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1)) - return; + return GPG_ERR_INV_CIPHER_MODE; - if (!inlen || !inbuf) - return; + if (!inbuf) + return GPG_ERR_INV_ARG; + + if (inlen == 0) + return 0; /* Last block is needed for cmac_final. */ - if (c->unused + inlen <= blocksize) + if (ctx->mac_unused + inlen <= blocksize) { - for (; inlen && c->unused < blocksize; inlen--) - c->lastiv[c->unused++] = *inbuf++; - return; + for (; inlen && ctx->mac_unused < blocksize; inlen--) + ctx->macbuf[ctx->mac_unused++] = *inbuf++; + return 0; } - if (c->unused) + if (ctx->mac_unused) { - for (; inlen && c->unused < blocksize; inlen--) - c->lastiv[c->unused++] = *inbuf++; + for (; inlen && ctx->mac_unused < blocksize; inlen--) + ctx->macbuf[ctx->mac_unused++] = *inbuf++; - buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); - set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv)); + buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); - c->unused = 0; + ctx->mac_unused = 0; } if (c->bulk.cbc_enc && inlen > blocksize) @@ -74,7 +81,7 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) nblocks = inlen / blocksize; nblocks -= (nblocks * blocksize == inlen); - c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, 1); + c->bulk.cbc_enc (&c->context.c, ctx->u_iv.iv, outbuf, inbuf, nblocks, 1); inbuf += nblocks * blocksize; inlen -= nblocks * blocksize; @@ -83,8 +90,8 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) else while (inlen > blocksize) { - buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); - set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv)); + buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, inbuf, blocksize); + set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); inlen -= blocksize; inbuf += blocksize; } @@ -93,16 +100,18 @@ cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) if (inlen == 0) BUG (); - for (; inlen && c->unused < blocksize; inlen--) - c->lastiv[c->unused++] = *inbuf++; + for (; inlen && ctx->mac_unused < blocksize; inlen--) + ctx->macbuf[ctx->mac_unused++] = *inbuf++; if (burn) _gcry_burn_stack (burn + 4 * sizeof (void *)); + + return 0; } -static void -cmac_generate_subkeys (gcry_cipher_hd_t c) +gcry_err_code_t +_gcry_cmac_generate_subkeys (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx) { const unsigned int blocksize = c->spec->blocksize; byte rb, carry, t, bi; @@ -117,7 +126,7 @@ cmac_generate_subkeys (gcry_cipher_hd_t c) /* Tell compiler that we require a cipher with a 64bit or 128 bit block * length, to allow better optimization of this function. */ if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1)) - return; + return GPG_ERR_INV_CIPHER_MODE; if (MAX_BLOCKSIZE < blocksize) BUG (); @@ -127,7 +136,7 @@ cmac_generate_subkeys (gcry_cipher_hd_t c) burn = c->spec->encrypt (&c->context.c, u.buf, u.buf); /* Currently supported blocksizes are 16 and 8. */ - rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8 */ ; + rb = blocksize == 16 ? 0x87 : 0x1B /* blocksize == 8 */ ; for (j = 0; j < 2; j++) { @@ -139,93 +148,113 @@ cmac_generate_subkeys (gcry_cipher_hd_t c) t = carry | (bi << 1); carry = bi >> 7; u.buf[i] = t & 0xff; - c->u_mode.cmac.subkeys[j][i] = u.buf[i]; + ctx->subkeys[j][i] = u.buf[i]; } u.buf[blocksize - 1] ^= carry ? rb : 0; - c->u_mode.cmac.subkeys[j][blocksize - 1] = u.buf[blocksize - 1]; + ctx->subkeys[j][blocksize - 1] = u.buf[blocksize - 1]; } wipememory (&u, sizeof (u)); if (burn) _gcry_burn_stack (burn + 4 * sizeof (void *)); + + return 0; } -static void -cmac_final (gcry_cipher_hd_t c) +gcry_err_code_t +_gcry_cmac_final (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx) { const unsigned int blocksize = c->spec->blocksize; - unsigned int count = c->unused; + unsigned int count = ctx->mac_unused; unsigned int burn; byte *subkey; /* Tell compiler that we require a cipher with a 64bit or 128 bit block * length, to allow better optimization of this function. */ if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1)) - return; + return GPG_ERR_INV_CIPHER_MODE; if (count == blocksize) - subkey = c->u_mode.cmac.subkeys[0]; /* K1 */ + subkey = ctx->subkeys[0]; /* K1 */ else { - subkey = c->u_mode.cmac.subkeys[1]; /* K2 */ - c->lastiv[count++] = 0x80; + subkey = ctx->subkeys[1]; /* K2 */ + ctx->macbuf[count++] = 0x80; while (count < blocksize) - c->lastiv[count++] = 0; + ctx->macbuf[count++] = 0; } - buf_xor (c->lastiv, c->lastiv, subkey, blocksize); + buf_xor (ctx->macbuf, ctx->macbuf, subkey, blocksize); - buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); - burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv); + buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + burn = c->spec->encrypt (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv); if (burn) _gcry_burn_stack (burn + 4 * sizeof (void *)); - c->unused = 0; + ctx->mac_unused = 0; + + return 0; } static gcry_err_code_t -cmac_tag (gcry_cipher_hd_t c, unsigned char *tag, size_t taglen, int check) +cmac_tag (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, + unsigned char *tag, size_t taglen, int check) { + gcry_err_code_t ret; + if (!tag || taglen == 0 || taglen > c->spec->blocksize) return GPG_ERR_INV_ARG; - if (!c->u_mode.cmac.tag) + if (!ctx->tag) { - cmac_final (c); - c->u_mode.cmac.tag = 1; + ret = _gcry_cmac_final (c, ctx); + if (ret != 0) + return ret; + + ctx->tag = 1; } if (!check) { - memcpy (tag, c->u_iv.iv, taglen); + memcpy (tag, ctx->u_iv.iv, taglen); return GPG_ERR_NO_ERROR; } else { - return buf_eq_const (tag, c->u_iv.iv, taglen) ? + return buf_eq_const (tag, ctx->u_iv.iv, taglen) ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; } } +void +_gcry_cmac_reset (gcry_cmac_context_t *ctx) +{ + char tmp_buf[sizeof(ctx->subkeys)]; + + /* Only keep subkeys when reseting context. */ + + buf_cpy (tmp_buf, ctx->subkeys, sizeof(ctx->subkeys)); + memset (ctx, 0, sizeof(*ctx)); + buf_cpy (ctx->subkeys, tmp_buf, sizeof(ctx->subkeys)); + wipememory (tmp_buf, sizeof(tmp_buf)); +} + + gcry_err_code_t _gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen) { if (abuflen > 0 && !abuf) return GPG_ERR_INV_ARG; - if (c->u_mode.cmac.tag) - return GPG_ERR_INV_STATE; /* To support new blocksize, update cmac_generate_subkeys() then add new blocksize here. */ if (c->spec->blocksize != 16 && c->spec->blocksize != 8) return GPG_ERR_INV_CIPHER_MODE; - cmac_write (c, abuf, abuflen); - - return GPG_ERR_NO_ERROR; + return _gcry_cmac_write (c, &c->u_mode.cmac, abuf, abuflen); } @@ -233,7 +262,7 @@ gcry_err_code_t _gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, size_t taglen) { - return cmac_tag (c, outtag, taglen, 0); + return cmac_tag (c, &c->u_mode.cmac, outtag, taglen, 0); } @@ -241,13 +270,11 @@ gcry_err_code_t _gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, size_t taglen) { - return cmac_tag (c, (unsigned char *) intag, taglen, 1); + return cmac_tag (c, &c->u_mode.cmac, (unsigned char *) intag, taglen, 1); } gcry_err_code_t _gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c) { - cmac_generate_subkeys (c); - - return GPG_ERR_NO_ERROR; + return _gcry_cmac_generate_subkeys (c, &c->u_mode.cmac); } |