summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2022-08-25 14:31:07 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2022-08-25 14:31:07 +0900
commit373b1f6c17948fa7d31880c3705391bef08a0471 (patch)
treed501a0204631027d908f4f53f333ced6c0bfd9f2 /cipher
parent249ca431ef881d510b90a5d3db9cd8507c4d697b (diff)
downloadlibgcrypt-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.c25
-rw-r--r--cipher/cipher-internal.h8
-rw-r--r--cipher/cipher.c62
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)
{