summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/cipher-gcm.c25
-rw-r--r--cipher/cipher-internal.h8
-rw-r--r--cipher/cipher.c62
-rw-r--r--doc/gcrypt.texi27
-rw-r--r--src/gcrypt-int.h6
-rw-r--r--src/gcrypt.h.in16
-rw-r--r--src/libgcrypt.def3
-rw-r--r--src/libgcrypt.vers3
-rw-r--r--src/visibility.c16
-rw-r--r--src/visibility.h4
10 files changed, 158 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)
{
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index b608dba2..277717d2 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -2005,6 +2005,33 @@ truncated lengths (4, 8, 12, 13, 14, or 15).
@end deftypefun
+For encryption of AEAD cipher modes, it should be possible to generate
+an initialization vector internally within libgcrypt implementation,
+in coordinated way, instead of calling @code{gcry_cipher_setiv} with
+arbitrary value, so that it can ensure the security properties of AEAD
+block cipher. For this purpose, the following two functions are provided:
+
+@deftypefun {gcry_error_t} gcry_cipher_setup_geniv (gcry_cipher_hd_t @var{h}, @
+ int @var{method}, const void *@var{fixed_iv}, size_t @var{fixed_ivlen}, @
+ const void *@var{dyn_iv}, size_t @var{dyn_ivlen})
+
+Set up an initialization vector generation for AEAD cipher modes.
+Generation is specified by @var{method}, fixed part of initialization
+vector by @var{fixed_iv} and @var{fixed_ivlen}, and dynamic part of
+initialization vector by @var{dyn_iv} and @var{dyn_ivlen}.
+For @var{method}, valid values are @code{GCRY_CIPHER_GENIV_METHOD_CONCAT}
+and @code{GCRY_CIPHER_GENIV_METHOD_XOR}.
+@end deftypefun
+
+@deftypefun {gcry_error_t} gcry_cipher_geniv (gcry_cipher_hd_t @var{h}, @
+ void *@var{iv}, size_t @var{ivlen})
+
+Generate the initialization vector into the output buffer @var{iv}
+with length @var{ivlen}. The initialization vector will be used by
+following @code{gcry_cipher_encrypt} call.
+@end deftypefun
+
+
The actual encryption and decryption is done by using one of the
following functions. They may be used as often as required to process
all the data.
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index 04953ffc..c3ca5d71 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -69,6 +69,12 @@ gcry_err_code_t _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_err_code_t _gcry_cipher_setup_geniv (gcry_cipher_hd_t hd, int method,
+ const void *fixed_iv,
+ size_t fixed_ivlen,
+ const void *dyn_iv, size_t dyn_ivlen);
+gcry_err_code_t _gcry_cipher_geniv (gcry_cipher_hd_t hd,
+ void *iv, size_t ivlen);
gpg_err_code_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
size_t abuflen);
gpg_err_code_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag,
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 60bcb6d1..8451a4ce 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -986,6 +986,13 @@ enum gcry_cipher_flags
GCRY_CIPHER_EXTENDED = 16 /* Enable extended AES-WRAP. */
};
+/* Methods used for AEAD IV generation. */
+enum gcry_cipher_geniv_methods
+ {
+ GCRY_CIPHER_GENIV_METHOD_CONCAT = 1,
+ GCRY_CIPHER_GENIV_METHOD_XOR = 2
+ };
+
/* GCM works only with blocks of 128 bits */
#define GCRY_GCM_BLOCK_LEN (128 / 8)
@@ -1057,6 +1064,15 @@ gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd,
gcry_error_t gcry_cipher_setiv (gcry_cipher_hd_t hd,
const void *iv, size_t ivlen);
+/* Initialization vector generation setup for AEAD modes/ciphers. */
+gcry_error_t gcry_cipher_setup_geniv (gcry_cipher_hd_t hd, int method,
+ const void *fixed_iv, size_t fixed_ivlen,
+ const void *dyn_iv, size_t dyn_ivlen);
+
+/* Initialization vector generation for AEAD modes/ciphers. */
+gcry_error_t gcry_cipher_geniv (gcry_cipher_hd_t hd,
+ void *iv, size_t ivlen);
+
/* Provide additional authentication data for AEAD modes/ciphers. */
gcry_error_t gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
size_t abuflen);
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index d6de731f..a66511c8 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -298,4 +298,7 @@ EXPORTS
gcry_kdf_final @260
gcry_kdf_close @261
+ gcry_cipher_setup_geniv @262
+ gcry_cipher_geniv @263
+
;; end of file with public symbols for Windows.
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index 2e274f60..62b0e4ee 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -125,6 +125,9 @@ GCRYPT_1.6 {
gcry_pk_hash_sign; gcry_pk_hash_verify; gcry_pk_random_override_new;
gcry_kdf_open; gcry_kdf_compute; gcry_kdf_final; gcry_kdf_close;
+
+ gcry_cipher_setup_geniv; gcry_cipher_geniv;
+
local:
*;
diff --git a/src/visibility.c b/src/visibility.c
index daaf4033..150b197d 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -774,6 +774,22 @@ gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
}
gcry_error_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)
+{
+ return gcry_error (_gcry_cipher_setup_geniv (hd, method,
+ fixed_iv, fixed_iv_len,
+ dyn_iv, dyn_iv_len));
+}
+
+gcry_error_t
+gcry_cipher_geniv (gcry_cipher_hd_t hd, void *iv, size_t iv_len)
+{
+ return gcry_error (_gcry_cipher_geniv (hd, iv, iv_len));
+}
+
+gcry_error_t
gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, size_t abuflen)
{
if (!fips_is_operational ())
diff --git a/src/visibility.h b/src/visibility.h
index 14bf6248..6aef3278 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -122,6 +122,8 @@ MARK_VISIBLEX (gcry_cipher_close)
MARK_VISIBLEX (gcry_cipher_setkey)
MARK_VISIBLEX (gcry_cipher_setiv)
MARK_VISIBLEX (gcry_cipher_setctr)
+MARK_VISIBLEX (gcry_cipher_setup_geniv)
+MARK_VISIBLEX (gcry_cipher_geniv)
MARK_VISIBLEX (gcry_cipher_authenticate)
MARK_VISIBLEX (gcry_cipher_checktag)
MARK_VISIBLEX (gcry_cipher_gettag)
@@ -344,6 +346,8 @@ MARK_VISIBLEX (_gcry_mpi_get_const)
#define gcry_cipher_setctr _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_cipher_algo_info _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_cipher_algo_name _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_cipher_setup_geniv _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_cipher_geniv _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_cipher_authenticate _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_cipher_checktag _gcry_USE_THE_UNDERSCORED_FUNCTION
#define gcry_cipher_gettag _gcry_USE_THE_UNDERSCORED_FUNCTION