diff options
-rw-r--r-- | cipher/cipher-gcm.c | 25 | ||||
-rw-r--r-- | cipher/cipher-internal.h | 30 | ||||
-rw-r--r-- | cipher/cipher.c | 23 |
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. */ } } |