diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-10-22 17:07:53 +0300 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-10-22 19:48:19 +0300 |
commit | 335d9bf7b035815750b63a3a8334d6ce44dc4449 (patch) | |
tree | 75a9ff903f9b7d2bd3f92dc459962ac7741e68c8 /cipher/cipher-internal.h | |
parent | 95654041f2aa62f71aac4d8614dafe8433d10f95 (diff) | |
download | libgcrypt-335d9bf7b035815750b63a3a8334d6ce44dc4449.tar.gz |
Add Counter with CBC-MAC mode (CCM)
* cipher/Makefile.am: Add 'cipher-ccm.c'.
* cipher/cipher-ccm.c: New.
* cipher/cipher-internal.h (gcry_cipher_handle): Add 'u_mode'.
(_gcry_cipher_ccm_encrypt, _gcry_cipher_ccm_decrypt)
(_gcry_cipher_ccm_set_nonce, _gcry_cipher_ccm_authenticate)
(_gcry_cipher_ccm_get_tag, _gcry_cipher_ccm_check_tag)
(_gcry_cipher_ccm_set_lengths): New prototypes.
* cipher/cipher.c (gcry_cipher_open, cipher_encrypt, cipher_decrypt)
(_gcry_cipher_setiv, _gcry_cipher_authenticate, _gcry_cipher_gettag)
(_gcry_cipher_checktag, gry_cipher_ctl): Add handling for CCM mode.
* doc/gcrypt.texi: Add documentation for GCRY_CIPHER_MODE_CCM.
* src/gcrypt.h.in (gcry_cipher_modes): Add 'GCRY_CIPHER_MODE_CCM'.
(gcry_ctl_cmds): Add 'GCRYCTL_SET_CCM_LENGTHS'.
(GCRY_CCM_BLOCK_LEN): New.
* tests/basic.c (check_ccm_cipher): New.
(check_cipher_modes): Call 'check_ccm_cipher'.
* tests/benchmark.c (ccm_aead_init): New.
(cipher_bench): Add handling for AEAD modes and add CCM benchmarking.
--
Patch adds CCM (Counter with CBC-MAC) mode as defined in RFC 3610 and NIST
Special Publication 800-38C.
Example for encrypting message (split in two buffers; buf1, buf2) and
authenticating additional non-encrypted data (split in two buffers; aadbuf1,
aadbuf2) with authentication tag length of eigth bytes:
size_t params[3];
taglen = 8;
gcry_cipher_setkey(h, key, len(key));
gcry_cipher_setiv(h, nonce, len(nonce));
params[0] = len(buf1) + len(buf2); /* 0: enclen */
params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */
params[2] = taglen; /* 2: authtaglen */
gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3);
gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1));
gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2));
gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1));
gcry_cipher_encrypt(h, buf2, len(buf2), buf2, len(buf2));
gcry_cipher_gettag(h, tag, taglen);
Example for decrypting above message and checking authentication tag:
size_t params[3];
taglen = 8;
gcry_cipher_setkey(h, key, len(key));
gcry_cipher_setiv(h, nonce, len(nonce));
params[0] = len(buf1) + len(buf2); /* 0: enclen */
params[1] = len(aadbuf1) + len(aadbuf2); /* 1: aadlen */
params[2] = taglen; /* 2: authtaglen */
gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3);
gcry_cipher_authenticate(h, aadbuf1, len(aadbuf1));
gcry_cipher_authenticate(h, aadbuf2, len(aadbuf2));
gcry_cipher_decrypt(h, buf1, len(buf1), buf1, len(buf1));
gcry_cipher_decrypt(h, buf2, len(buf2), buf2, len(buf2));
err = gcry_cipher_checktag(h, tag, taglen);
if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
{ /* Authentication failed. */ }
else if (err == 0)
{ /* Authentication ok. */ }
Example for encrypting message without additional authenticated data:
size_t params[3];
taglen = 10;
gcry_cipher_setkey(h, key, len(key));
gcry_cipher_setiv(h, nonce, len(nonce));
params[0] = len(buf1); /* 0: enclen */
params[1] = 0; /* 1: aadlen */
params[2] = taglen; /* 2: authtaglen */
gcry_cipher_ctl(h, GCRYCTL_SET_CCM_LENGTHS, params, sizeof(size_t) * 3);
gcry_cipher_encrypt(h, buf1, len(buf1), buf1, len(buf1));
gcry_cipher_gettag(h, tag, taglen);
To reset CCM state for cipher handle, one can either set new nonce or use
'gcry_cipher_reset'.
This implementation reuses existing CTR mode code for encryption/decryption
and is there for able to process multiple buffers that are not multiple of
blocksize. AAD data maybe also be passed into gcry_cipher_authenticate
in non-blocksize chunks.
[v4]: GCRYCTL_SET_CCM_PARAMS => GCRY_SET_CCM_LENGTHS
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher/cipher-internal.h')
-rw-r--r-- | cipher/cipher-internal.h | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index b60ef386..981caa83 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -100,7 +100,8 @@ struct gcry_cipher_handle /* The initialization vector. For best performance we make sure that it is properly aligned. In particular some implementations - of bulk operations expect an 16 byte aligned IV. */ + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ union { cipher_context_alignment_t iv_align; unsigned char iv[MAX_BLOCKSIZE]; @@ -117,6 +118,26 @@ struct gcry_cipher_handle unsigned char lastiv[MAX_BLOCKSIZE]; int unused; /* Number of unused bytes in LASTIV. */ + union { + /* Mode specific storage for CCM mode. */ + struct { + size_t encryptlen; + size_t aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int lengths:1; /* Set to 1 if CCM length parameters has been + processed. */ + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + } ccm; + } u_mode; + /* What follows are two contexts of the cipher in use. The first one needs to be aligned well enough for the cipher operation whereas the second one is a copy created by cipher_setkey and @@ -175,5 +196,30 @@ gcry_err_code_t _gcry_cipher_aeswrap_decrypt const byte *inbuf, unsigned int inbuflen); +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, unsigned int outbuflen, + const unsigned char *inbuf, unsigned int inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +gcry_err_code_t _gcry_cipher_ccm_set_lengths +/* */ (gcry_cipher_hd_t c, size_t encryptedlen, size_t aadlen, + size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + #endif /*G10_CIPHER_INTERNAL_H*/ |