GCM: Move gcm_table initialization to setkey
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Wed, 20 Nov 2013 13:44:27 +0000 (15:44 +0200)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Thu, 21 Nov 2013 09:58:09 +0000 (11:58 +0200)
* cipher/cipher-gcm.c: Change all 'c->u_iv.iv' to
'c->u_mode.gcm.u_ghash_key.key'.
(_gcry_cipher_gcm_setkey): New.
(_gcry_cipher_gcm_initiv): Move ghash initialization to function above.
* cipher/cipher-internal.h (gcry_cipher_handle): Add
'u_mode.gcm.u_ghash_key'; Reorder 'u_mode.gcm' members for partial
clearing in gcry_cipher_reset.
(_gcry_cipher_gcm_setkey): New prototype.
* cipher/cipher.c (cipher_setkey): Add GCM setkey.
(cipher_reset): Clear 'u_mode' only partially for GCM.
--

GHASH tables can be generated at setkey time. No need to regenerate
for every new IV.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/cipher-gcm.c
cipher/cipher-internal.h
cipher/cipher.c

index 42cfc1e..457e337 100644 (file)
@@ -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};
index ede6f75..6fb3bac 100644 (file)
@@ -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*/
index a3c2c6f..516f44b 100644 (file)
@@ -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. */
     }
 }