summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cipher/cipher-gcm.c25
-rw-r--r--cipher/cipher-internal.h30
-rw-r--r--cipher/cipher.c23
3 files changed, 58 insertions, 20 deletions
diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c
index 42cfc1ea..457e337a 100644
--- a/cipher/cipher-gcm.c
+++ b/cipher/cipher-gcm.c
@@ -344,7 +344,7 @@ do_ghash (unsigned char *hsub, unsigned char *result, const unsigned char *buf)
}
#define fillM(c, h) do { } while (0)
-#define GHASH(c, result, buf) do_ghash (c->u_iv.iv, result, buf)
+#define GHASH(c, result, buf) do_ghash (c->u_mode.gcm.u_ghash_key.key, result, buf)
#endif /* !GCM_USE_TABLES */
@@ -581,7 +581,7 @@ ghash (gcry_cipher_hd_t c, byte *result, const byte *buf,
"pshufb %[be_mask], %%xmm1\n\t" /* be => le */
:
: [hash] "m" (*result), [be_mask] "m" (*be_mask),
- [hsub] "m" (*c->u_iv.iv));
+ [hsub] "m" (*c->u_mode.gcm.u_ghash_key.key));
#ifdef __x86_64__
if (nblocks >= 4)
@@ -687,9 +687,9 @@ setupM (gcry_cipher_hd_t c, byte *h)
c->u_mode.gcm.use_intel_pclmul = 1;
/* Swap endianness of hsub. */
- tmp[0] = buf_get_be64(c->u_iv.iv + 8);
- tmp[1] = buf_get_be64(c->u_iv.iv + 0);
- buf_cpy (c->u_iv.iv, tmp, GCRY_GCM_BLOCK_LEN);
+ tmp[0] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 8);
+ tmp[1] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 0);
+ buf_cpy (c->u_mode.gcm.u_ghash_key.key, tmp, GCRY_GCM_BLOCK_LEN);
#ifdef __x86_64__
asm volatile ("movdqu %[h_1], %%xmm0\n\t"
@@ -982,6 +982,17 @@ _gcry_cipher_gcm_authenticate (gcry_cipher_hd_t c,
}
+void
+_gcry_cipher_gcm_setkey (gcry_cipher_hd_t c)
+{
+ memset (c->u_mode.gcm.u_ghash_key.key, 0, GCRY_GCM_BLOCK_LEN);
+
+ c->spec->encrypt (&c->context.c, c->u_mode.gcm.u_ghash_key.key,
+ c->u_mode.gcm.u_ghash_key.key);
+ setupM (c, c->u_mode.gcm.u_ghash_key.key);
+}
+
+
static gcry_err_code_t
_gcry_cipher_gcm_initiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
{
@@ -995,10 +1006,6 @@ _gcry_cipher_gcm_initiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen)
if (ivlen == 0)
return GPG_ERR_INV_LENGTH;
- c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_mode.gcm.u_tag.tag);
-
- setupM (c, c->u_iv.iv);
-
if (ivlen != GCRY_GCM_BLOCK_LEN - 4)
{
u32 iv_bytes[2] = {0, 0};
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index ede6f757..6fb3bace 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -179,6 +179,25 @@ struct gcry_cipher_handle
/* encrypted tag counter */
unsigned char tagiv[MAX_BLOCKSIZE];
+ unsigned int ghash_data_finalized:1;
+ unsigned int ghash_aad_finalized:1;
+
+ unsigned int datalen_over_limits:1;
+ unsigned int disallow_encryption_because_of_setiv_in_fips_mode:1;
+
+ /* --- Following members are not cleared in gcry_cipher_reset --- */
+
+ /* GHASH multiplier from key. */
+ union {
+ cipher_context_alignment_t iv_align;
+ unsigned char key[MAX_BLOCKSIZE];
+ } u_ghash_key;
+
+#ifdef GCM_USE_INTEL_PCLMUL
+ /* Use Intel PCLMUL instructions for accelerated GHASH. */
+ unsigned int use_intel_pclmul:1;
+#endif
+
/* Pre-calculated table for GCM. */
#ifdef GCM_USE_TABLES
#if defined(HAVE_U64_TYPEDEF) && (SIZEOF_UNSIGNED_LONG == 8 \
@@ -190,15 +209,6 @@ struct gcry_cipher_handle
u32 gcm_table[4 * 16];
#endif
#endif
-
- unsigned int ghash_data_finalized:1;
- unsigned int ghash_aad_finalized:1;
-
- unsigned int datalen_over_limits:1;
- unsigned int disallow_encryption_because_of_setiv_in_fips_mode:1;
-#ifdef GCM_USE_INTEL_PCLMUL
- unsigned int use_intel_pclmul:1;
-#endif
} gcm;
} u_mode;
@@ -302,6 +312,8 @@ gcry_err_code_t _gcry_cipher_gcm_get_tag
gcry_err_code_t _gcry_cipher_gcm_check_tag
/* */ (gcry_cipher_hd_t c,
const unsigned char *intag, size_t taglen);
+void _gcry_cipher_gcm_setkey
+/* */ (gcry_cipher_hd_t c);
#endif /*G10_CIPHER_INTERNAL_H*/
diff --git a/cipher/cipher.c b/cipher/cipher.c
index a3c2c6fe..516f44ba 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -593,6 +593,11 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
case GCRY_CIPHER_MODE_CMAC:
_gcry_cipher_cmac_set_subkeys (c);
break;
+
+ case GCRY_CIPHER_MODE_GCM:
+ _gcry_cipher_gcm_setkey (c);
+ break;
+
default:
break;
};
@@ -670,9 +675,23 @@ cipher_reset (gcry_cipher_hd_t c)
c->u_mode.cmac.tag = 0;
break;
- default:
- memset (&c->u_mode, 0, sizeof c->u_mode);
+ case GCRY_CIPHER_MODE_GCM:
+ /* Only clear head of u_mode, keep ghash_key and gcm_table. */
+ {
+ byte *u_mode_pos = (void *)&c->u_mode;
+ byte *ghash_key_pos = c->u_mode.gcm.u_ghash_key.key;
+ size_t u_mode_head_length = ghash_key_pos - u_mode_pos;
+
+ memset (&c->u_mode, 0, u_mode_head_length);
+ }
+ break;
+
+ case GCRY_CIPHER_MODE_CCM:
+ memset (&c->u_mode.ccm, 0, sizeof c->u_mode.ccm);
break;
+
+ default:
+ break; /* u_mode unused by other modes. */
}
}