summaryrefslogtreecommitdiff
path: root/cipher/cipher.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2013-11-14 14:10:27 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2013-11-19 19:18:56 +0200
commitb49cd64aaaff2e5488a84665362ef7150683226c (patch)
tree08a9aa2bd510d0231fa63ca481b03c5f42457aee /cipher/cipher.c
parentfcd6da37d55f248d3558ee0ff385b41b866e7ded (diff)
downloadlibgcrypt-b49cd64aaaff2e5488a84665362ef7150683226c.tar.gz
Add CMAC (Cipher-based MAC) to MAC API
* cipher/Makefile.am: Add 'cipher-cmac.c' and 'mac-cmac.c'. * cipher/cipher-cmac.c: New. * cipher/cipher-internal.h (gcry_cipher_handle.u_mode): Add 'cmac'. * cipher/cipher.c (gcry_cipher_open): Rename to... (_gcry_cipher_open_internal): ...this and add CMAC. (gcry_cipher_open): New wrapper that disallows use of internal modes (CMAC) from outside. (cipher_setkey, cipher_encrypt, cipher_decrypt) (_gcry_cipher_authenticate, _gcry_cipher_gettag) (_gcry_cipher_checktag): Add handling for CMAC mode. (cipher_reset): Do not reset 'marks.key' and do not clear subkeys in 'u_mode' in CMAC mode. * cipher/mac-cmac.c: New. * cipher/mac-internal.h: Add CMAC support and algorithms. * cipher/mac.c: Add CMAC algorithms. * doc/gcrypt.texi: Add documentation for CMAC. * src/cipher.h (gcry_cipher_internal_modes): New. (_gcry_cipher_open_internal, _gcry_cipher_cmac_authenticate) (_gcry_cipher_cmac_get_tag, _gcry_cipher_cmac_check_tag) (_gcry_cipher_cmac_set_subkeys): New prototypes. * src/gcrypt.h.in (gcry_mac_algos): Add CMAC algorithms. * tests/basic.c (check_mac): Add CMAC test vectors. -- Patch adds CMAC (Cipher-based MAC) as defined in RFC 4493 and NIST Special Publication 800-38B. Internally CMAC is added to cipher module, but is available to outside only through MAC API. [v2]: - Add documentation. [v3]: - CMAC algorithm ids start from 201. - Coding style fixes. Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher/cipher.c')
-rw-r--r--cipher/cipher.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 80aa7a74..b68703e3 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -344,6 +344,24 @@ gcry_error_t
gcry_cipher_open (gcry_cipher_hd_t *handle,
int algo, int mode, unsigned int flags)
{
+ gcry_err_code_t err;
+ gcry_cipher_hd_t h = NULL;
+
+ if (mode >= GCRY_CIPHER_MODE_INTERNAL)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ else
+ err = _gcry_cipher_open_internal (&h, algo, mode, flags);
+
+ *handle = err ? NULL : h;
+
+ return gcry_error (err);
+}
+
+
+gcry_err_code_t
+_gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
+ int algo, int mode, unsigned int flags)
+{
int secure = (flags & GCRY_CIPHER_SECURE);
gcry_cipher_spec_t *spec;
gcry_cipher_hd_t h = NULL;
@@ -388,6 +406,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle,
case GCRY_CIPHER_MODE_OFB:
case GCRY_CIPHER_MODE_CTR:
case GCRY_CIPHER_MODE_AESWRAP:
+ case GCRY_CIPHER_MODE_CMAC:
if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
break;
@@ -567,10 +586,20 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
(void *) &c->context.c,
c->spec->contextsize);
c->marks.key = 1;
+
+ switch (c->mode)
+ {
+ case GCRY_CIPHER_MODE_CMAC:
+ _gcry_cipher_cmac_set_subkeys (c);
+ break;
+ default:
+ break;
+ };
}
else
c->marks.key = 0;
+
return gcry_error (ret);
}
@@ -613,6 +642,10 @@ cipher_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
static void
cipher_reset (gcry_cipher_hd_t c)
{
+ unsigned int marks_key;
+
+ marks_key = c->marks.key;
+
memcpy (&c->context.c,
(char *) &c->context.c + c->spec->contextsize,
c->spec->contextsize);
@@ -620,8 +653,21 @@ cipher_reset (gcry_cipher_hd_t c)
memset (c->u_iv.iv, 0, c->spec->blocksize);
memset (c->lastiv, 0, c->spec->blocksize);
memset (c->u_ctr.ctr, 0, c->spec->blocksize);
- memset (&c->u_mode, 0, sizeof c->u_mode);
c->unused = 0;
+
+ c->marks.key = marks_key;
+
+ switch (c->mode)
+ {
+ case GCRY_CIPHER_MODE_CMAC:
+ /* Only clear 'tag' for cmac, keep subkeys. */
+ c->u_mode.cmac.tag = 0;
+ break;
+
+ default:
+ memset (&c->u_mode, 0, sizeof c->u_mode);
+ break;
+ }
}
@@ -717,6 +763,10 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_CMAC:
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stencrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -817,6 +867,10 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
break;
+ case GCRY_CIPHER_MODE_CMAC:
+ rc = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_STREAM:
c->spec->stdecrypt (&c->context.c,
outbuf, (byte*)/*arggg*/inbuf, inbuflen);
@@ -942,6 +996,10 @@ _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen);
break;
+ case GCRY_CIPHER_MODE_CMAC:
+ rc = _gcry_cipher_cmac_authenticate (hd, abuf, abuflen);
+ break;
+
default:
log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;
@@ -962,6 +1020,10 @@ _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen);
break;
+ case GCRY_CIPHER_MODE_CMAC:
+ rc = _gcry_cipher_cmac_get_tag (hd, outtag, taglen);
+ break;
+
default:
log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;
@@ -982,6 +1044,10 @@ _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen);
break;
+ case GCRY_CIPHER_MODE_CMAC:
+ rc = _gcry_cipher_cmac_check_tag (hd, intag, taglen);
+ break;
+
default:
log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
rc = GPG_ERR_INV_CIPHER_MODE;