summaryrefslogtreecommitdiff
path: root/cipher/cipher-cmac.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2018-01-20 21:08:37 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2018-01-20 22:17:14 +0200
commite8629e535bd0e9711b07904d4501de8ad57aaecd (patch)
treeae5c5264b8df5dd07b20453cd6be608f14f3e145 /cipher/cipher-cmac.c
parentcd7ed2e3546b12dd98df4211949f1cdbf5827013 (diff)
downloadlibgcrypt-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.c137
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);
}