summaryrefslogtreecommitdiff
path: root/cipher/cipher.c
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2021-08-11 18:02:07 +0300
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2021-08-26 20:30:31 +0300
commit1b8994c4ecf2cb53fff46fa84a95a7c259e7cec7 (patch)
tree8b07e25cdc96e8590ca91c3e4a9e8abd69a55b09 /cipher/cipher.c
parent659a208cb065d686f60e2c4f51856f460d6b44f5 (diff)
downloadlibgcrypt-1b8994c4ecf2cb53fff46fa84a95a7c259e7cec7.tar.gz
Add AES-GCM-SIV mode (RFC 8452)
* cipher/Makefile.am: Add 'cipher-gcm-siv.c'. * cipher/cipher-gcm-siv.c: New. * cipher/cipher-gcm.c (_gcry_cipher_gcm_setupM): New. * cipher/cipher-internal.h (gcry_cipher_handle): Add 'siv_keylen'. (_gcry_cipher_gcm_setupM, _gcry_cipher_gcm_siv_encrypt) (_gcry_cipher_gcm_siv_decrypt, _gcry_cipher_gcm_siv_set_nonce) (_gcry_cipher_gcm_siv_authenticate) (_gcry_cipher_gcm_siv_set_decryption_tag) (_gcry_cipher_gcm_siv_get_tag, _gcry_cipher_gcm_siv_check_tag) (_gcry_cipher_gcm_siv_setkey): New prototypes. (cipher_block_bswap): New helper function. * cipher/cipher.c (_gcry_cipher_open_internal): Add 'GCRY_CIPHER_MODE_GCM_SIV'; Refactor mode requirement checks for better size optimization (check pointers & blocksize in same order for all). (cipher_setkey, cipher_reset, _gcry_cipher_setup_mode_ops) (_gcry_cipher_setup_mode_ops, _gcry_cipher_info): Add GCM-SIV. (_gcry_cipher_ctl): Handle 'set decryption tag' for GCM-SIV. * doc/gcrypt.texi: Add GCM-SIV. * src/gcrypt.h.in (GCRY_CIPHER_MODE_GCM_SIV): New. (GCRY_SIV_BLOCK_LEN, gcry_cipher_set_decryption_tag): Add to comment that these are also for GCM-SIV in addition to SIV mode. * tests/basic.c (check_gcm_siv_cipher): New. (check_cipher_modes): Check for GCM-SIV. * tests/bench-slope.c (bench_gcm_siv_encrypt_do_bench) (bench_gcm_siv_decrypt_do_bench, bench_gcm_siv_authenticate_do_bench) (gcm_siv_encrypt_ops, gcm_siv_decrypt_ops) (gcm_siv_authenticate_ops): New. (cipher_modes): Add GCM-SIV. (cipher_bench_one): Check key length requirement for GCM-SIV. -- GnuPG-bug-id: T4485 Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher/cipher.c')
-rw-r--r--cipher/cipher.c69
1 files changed, 55 insertions, 14 deletions
diff --git a/cipher/cipher.c b/cipher/cipher.c
index a274466f..2bde99ef 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -526,33 +526,46 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
if (! err)
switch (mode)
{
- case GCRY_CIPHER_MODE_CCM:
- if (spec->blocksize != GCRY_CCM_BLOCK_LEN)
+ case GCRY_CIPHER_MODE_ECB:
+ case GCRY_CIPHER_MODE_CBC:
+ case GCRY_CIPHER_MODE_CFB:
+ case GCRY_CIPHER_MODE_CFB8:
+ case GCRY_CIPHER_MODE_OFB:
+ case GCRY_CIPHER_MODE_CTR:
+ case GCRY_CIPHER_MODE_AESWRAP:
+ case GCRY_CIPHER_MODE_CMAC:
+ case GCRY_CIPHER_MODE_EAX:
+ if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
+ case GCRY_CIPHER_MODE_CCM:
if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
+ else if (spec->blocksize != GCRY_CCM_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
break;
case GCRY_CIPHER_MODE_XTS:
- if (spec->blocksize != GCRY_XTS_BLOCK_LEN)
- err = GPG_ERR_INV_CIPHER_MODE;
if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
+ else if (spec->blocksize != GCRY_XTS_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
break;
- case GCRY_CIPHER_MODE_ECB:
- case GCRY_CIPHER_MODE_CBC:
- case GCRY_CIPHER_MODE_CFB:
- case GCRY_CIPHER_MODE_CFB8:
- case GCRY_CIPHER_MODE_OFB:
- case GCRY_CIPHER_MODE_CTR:
- case GCRY_CIPHER_MODE_AESWRAP:
- case GCRY_CIPHER_MODE_CMAC:
- case GCRY_CIPHER_MODE_EAX:
case GCRY_CIPHER_MODE_GCM:
+ if (!spec->encrypt || !spec->decrypt)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ else if (spec->blocksize != GCRY_GCM_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
+ break;
+
case GCRY_CIPHER_MODE_SIV:
+ case GCRY_CIPHER_MODE_GCM_SIV:
if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
+ else if (spec->blocksize != GCRY_SIV_BLOCK_LEN)
+ err = GPG_ERR_INV_CIPHER_MODE;
break;
case GCRY_CIPHER_MODE_POLY1305:
@@ -569,7 +582,7 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
security too much. */
if (!spec->encrypt || !spec->decrypt)
err = GPG_ERR_INV_CIPHER_MODE;
- else if (spec->blocksize != (128/8))
+ else if (spec->blocksize != GCRY_OCB_BLOCK_LEN)
err = GPG_ERR_INV_CIPHER_MODE;
break;
@@ -769,6 +782,12 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
_gcry_cipher_gcm_setkey (c);
break;
+ case GCRY_CIPHER_MODE_GCM_SIV:
+ rc = _gcry_cipher_gcm_siv_setkey (c, keylen);
+ if (rc)
+ c->marks.key = 0;
+ break;
+
case GCRY_CIPHER_MODE_OCB:
_gcry_cipher_ocb_setkey (c);
break;
@@ -884,6 +903,7 @@ cipher_reset (gcry_cipher_hd_t c)
break;
case GCRY_CIPHER_MODE_GCM:
+ case GCRY_CIPHER_MODE_GCM_SIV:
/* Only clear head of u_mode, keep ghash_key and gcm_table. */
{
byte *u_mode_pos = (void *)&c->u_mode;
@@ -1375,6 +1395,11 @@ _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode)
c->mode_ops.decrypt = _gcry_cipher_siv_decrypt;
break;
+ case GCRY_CIPHER_MODE_GCM_SIV:
+ c->mode_ops.encrypt = _gcry_cipher_gcm_siv_encrypt;
+ c->mode_ops.decrypt = _gcry_cipher_gcm_siv_decrypt;
+ break;
+
default:
c->mode_ops.encrypt = do_encrypt_none_unknown;
c->mode_ops.decrypt = do_decrypt_none_unknown;
@@ -1408,6 +1433,10 @@ _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode)
c->mode_ops.setiv = _gcry_cipher_siv_set_nonce;
break;
+ case GCRY_CIPHER_MODE_GCM_SIV:
+ c->mode_ops.setiv = _gcry_cipher_gcm_siv_set_nonce;
+ break;
+
default:
c->mode_ops.setiv = cipher_setiv;
break;
@@ -1459,6 +1488,12 @@ _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode)
c->mode_ops.check_tag = _gcry_cipher_siv_check_tag;
break;
+ case GCRY_CIPHER_MODE_GCM_SIV:
+ c->mode_ops.authenticate = _gcry_cipher_gcm_siv_authenticate;
+ c->mode_ops.get_tag = _gcry_cipher_gcm_siv_get_tag;
+ c->mode_ops.check_tag = _gcry_cipher_gcm_siv_check_tag;
+ break;
+
default:
c->mode_ops.authenticate = NULL;
c->mode_ops.get_tag = NULL;
@@ -1540,6 +1575,8 @@ _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
if (h->mode == GCRY_CIPHER_MODE_SIV)
rc = _gcry_cipher_siv_set_decryption_tag (h, buffer, buflen);
+ else if (h->mode == GCRY_CIPHER_MODE_GCM_SIV)
+ rc = _gcry_cipher_gcm_siv_set_decryption_tag (h, buffer, buflen);
else
rc = GPG_ERR_INV_CIPHER_MODE;
}
@@ -1682,6 +1719,10 @@ _gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes)
*nbytes = GCRY_SIV_BLOCK_LEN;
break;
+ case GCRY_CIPHER_MODE_GCM_SIV:
+ *nbytes = GCRY_SIV_BLOCK_LEN;
+ break;
+
default:
rc = GPG_ERR_INV_CIPHER_MODE;
break;