diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2022-08-25 14:31:07 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2022-08-25 14:31:07 +0900 |
commit | 373b1f6c17948fa7d31880c3705391bef08a0471 (patch) | |
tree | d501a0204631027d908f4f53f333ced6c0bfd9f2 /cipher | |
parent | 249ca431ef881d510b90a5d3db9cd8507c4d697b (diff) | |
download | libgcrypt-373b1f6c17948fa7d31880c3705391bef08a0471.tar.gz |
cipher: Support internal generation of IV for AEAD cipher mode.
* cipher/cipher-gcm.c (_gcry_cipher_gcm_setiv_zero): New.
(_gcry_cipher_gcm_encrypt, _gcry_cipher_gcm_decrypt)
(_gcry_cipher_gcm_authenticate): Use _gcry_cipher_gcm_setiv_zero.
* cipher/cipher-internal.h (struct gcry_cipher_handle): Add aead field.
* cipher/cipher.c (_gcry_cipher_setiv): Check calling setiv to reject
direct invocation in FIPS mode.
(_gcry_cipher_setup_geniv, _gcry_cipher_geniv): New.
* doc/gcrypt.texi: Add explanation for two new functions.
* src/gcrypt-int.h (_gcry_cipher_setup_geniv, _gcry_cipher_geniv): New.
* src/gcrypt.h.in (enum gcry_cipher_geniv_methods): New.
(gcry_cipher_setup_geniv, gcry_cipher_geniv): New.
* src/libgcrypt.def (gcry_cipher_setup_geniv, gcry_cipher_geniv): Add.
* src/libgcrypt.vers: Likewise.
* src/visibility.c (gcry_cipher_setup_geniv, gcry_cipher_geniv): Add.
* src/visibility.h: Likewise.
--
GnuPG-bug-id: 4873
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/cipher-gcm.c | 25 | ||||
-rw-r--r-- | cipher/cipher-internal.h | 8 | ||||
-rw-r--r-- | cipher/cipher.c | 62 |
3 files changed, 83 insertions, 12 deletions
diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c index 683f07b0..08152a72 100644 --- a/cipher/cipher-gcm.c +++ b/cipher/cipher-gcm.c @@ -30,6 +30,8 @@ #include "./cipher-internal.h" +static gcry_err_code_t _gcry_cipher_gcm_setiv_zero (gcry_cipher_hd_t c); + /* Helper macro to force alignment to 16 or 64 bytes. */ #ifdef HAVE_GCC_ATTRIBUTE_ALIGNED # define ATTR_ALIGNED_64 __attribute__ ((aligned (64))) @@ -909,8 +911,6 @@ _gcry_cipher_gcm_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, const byte *inbuf, size_t inbuflen) { - static const unsigned char zerobuf[MAX_BLOCKSIZE]; - if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) return GPG_ERR_CIPHER_ALGO; if (outbuflen < inbuflen) @@ -923,7 +923,7 @@ _gcry_cipher_gcm_encrypt (gcry_cipher_hd_t c, return GPG_ERR_INV_STATE; if (!c->marks.iv) - _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + _gcry_cipher_gcm_setiv_zero (c); if (c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode) return GPG_ERR_INV_STATE; @@ -951,8 +951,6 @@ _gcry_cipher_gcm_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, const byte *inbuf, size_t inbuflen) { - static const unsigned char zerobuf[MAX_BLOCKSIZE]; - if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) return GPG_ERR_CIPHER_ALGO; if (outbuflen < inbuflen) @@ -965,7 +963,7 @@ _gcry_cipher_gcm_decrypt (gcry_cipher_hd_t c, return GPG_ERR_INV_STATE; if (!c->marks.iv) - _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + _gcry_cipher_gcm_setiv_zero (c); if (!c->u_mode.gcm.ghash_aad_finalized) { @@ -989,8 +987,6 @@ gcry_err_code_t _gcry_cipher_gcm_authenticate (gcry_cipher_hd_t c, const byte * aadbuf, size_t aadbuflen) { - static const unsigned char zerobuf[MAX_BLOCKSIZE]; - if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) return GPG_ERR_CIPHER_ALGO; if (c->u_mode.gcm.datalen_over_limits) @@ -1002,7 +998,7 @@ _gcry_cipher_gcm_authenticate (gcry_cipher_hd_t c, return GPG_ERR_INV_STATE; if (!c->marks.iv) - _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + _gcry_cipher_gcm_setiv_zero (c); gcm_bytecounter_add(c->u_mode.gcm.aadlen, aadbuflen); if (!gcm_check_aadlen_or_ivlen(c->u_mode.gcm.aadlen)) @@ -1105,6 +1101,15 @@ _gcry_cipher_gcm_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) { c->marks.iv = 0; c->marks.tag = 0; + + return _gcry_cipher_gcm_initiv (c, iv, ivlen); +} + +static gcry_err_code_t +_gcry_cipher_gcm_setiv_zero (gcry_cipher_hd_t c) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; if (fips_mode ()) @@ -1113,7 +1118,7 @@ _gcry_cipher_gcm_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 1; } - return _gcry_cipher_gcm_initiv (c, iv, ivlen); + return _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); } diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index e1ff0437..66b75955 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -246,6 +246,14 @@ struct gcry_cipher_handle unsigned int flags; struct { + int geniv_method; + unsigned char fixed[MAX_BLOCKSIZE]; + unsigned char dynamic[MAX_BLOCKSIZE]; + size_t fixed_iv_len; + size_t dynamic_iv_len; + } aead; + + struct { unsigned int key:1; /* Set to 1 if a key has been set. */ unsigned int iv:1; /* Set to 1 if a IV has been set. */ unsigned int tag:1; /* Set to 1 if a tag is finalized. */ diff --git a/cipher/cipher.c b/cipher/cipher.c index 9e850470..e8743496 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -1210,9 +1210,20 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) gcry_err_code_t -_gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) +_gcry_cipher_setiv (gcry_cipher_hd_t c, const void *iv, size_t ivlen) { - return hd->mode_ops.setiv (hd, iv, ivlen); + if (c->mode == GCRY_CIPHER_MODE_GCM) + { + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; + + if (fips_mode ()) + { + /* Direct invocation of GCM setiv in FIPS mode disables encryption. */ + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 1; + } + } + + return c->mode_ops.setiv (c, iv, ivlen); } @@ -1251,6 +1262,53 @@ _gcry_cipher_getctr (gcry_cipher_hd_t hd, void *ctr, size_t ctrlen) gcry_err_code_t +_gcry_cipher_setup_geniv (gcry_cipher_hd_t hd, int method, + const void *fixed_iv, size_t fixed_iv_len, + const void *dyn_iv, size_t dyn_iv_len) +{ + gcry_err_code_t rc = 0; + + if (method != GCRY_CIPHER_GENIV_METHOD_CONCAT) + return GPG_ERR_INV_ARG; + + hd->aead.geniv_method = GCRY_CIPHER_GENIV_METHOD_CONCAT; + hd->aead.fixed_iv_len = fixed_iv_len; + hd->aead.dynamic_iv_len = dyn_iv_len; + memset (hd->aead.fixed, 0, MAX_BLOCKSIZE); + memset (hd->aead.dynamic, 0, MAX_BLOCKSIZE); + memcpy (hd->aead.fixed, fixed_iv, fixed_iv_len); + memcpy (hd->aead.dynamic, dyn_iv, dyn_iv_len); + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_geniv (gcry_cipher_hd_t hd, void *iv, size_t iv_len) +{ + gcry_err_code_t rc = 0; + int i; + + if (hd->aead.geniv_method != GCRY_CIPHER_GENIV_METHOD_CONCAT) + return GPG_ERR_INV_ARG; + + if (iv_len != hd->aead.fixed_iv_len + hd->aead.dynamic_iv_len) + return GPG_ERR_INV_ARG; + + memcpy (iv, hd->aead.fixed, hd->aead.fixed_iv_len); + memcpy ((byte *)iv+hd->aead.fixed_iv_len, + hd->aead.dynamic, hd->aead.dynamic_iv_len); + rc = hd->mode_ops.setiv (hd, iv, iv_len); + + for (i = hd->aead.dynamic_iv_len; i > 0; i--) + if (++hd->aead.dynamic[i - 1] != 0) + break; + + return rc; +} + + +gcry_err_code_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen) { |