diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-11-14 14:10:27 +0200 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-11-19 19:18:56 +0200 |
commit | b49cd64aaaff2e5488a84665362ef7150683226c (patch) | |
tree | 08a9aa2bd510d0231fa63ca481b03c5f42457aee /cipher/cipher.c | |
parent | fcd6da37d55f248d3558ee0ff385b41b866e7ded (diff) | |
download | libgcrypt-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.c | 68 |
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; |