Make SHA-512 use the new _gcry_md_block_write helper
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 21 Sep 2013 10:54:38 +0000 (13:54 +0300)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 21 Sep 2013 10:54:38 +0000 (13:54 +0300)
* cipher/hash-common.c (_gcry_md_block_write): Check that hd->buf is
large enough.
* cipher/hash-common.h (MD_BLOCK_MAX_BLOCKSIZE, MD_NBLOCKS_TYPE): New
macros.
(gcry_md_block_ctx_t): Use above macros for 'nblocks' and 'buf'.
* cipher/sha512.c (SHA512_STATE): New struct.
(SHA512_CONTEXT): Add 'bctx' and 'state'.
(sha512_init, sha384_init): Initialize 'bctx'.
(__transform, _gcry_sha512_transform_armv7_neon): Use SHA512_STATE for
'hd'.
(transform): For now, do not return burn stack.
(sha512_write): Remove.
(sha512_final): Use _gcry_md_block_write and bctx.
(_gcry_digest_spec_sha512, _gcry_digest_spec_sha384): Use
_gcry_md_block_write.
--

Patch changes 'nblocks' counter to 64-bits when SHA-512 is enabled. This does
not cause problems with other algorithms; they are already casting 'nblocks'
to u32 variable in their finalization functions. Also move 'buf' member to
head of 'gcry_md_block_ctx_t' to ensure proper alignment; this is because some
algorithms cast buffer pointer to (u64*) in final endian conversion.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/hash-common.c
cipher/hash-common.h
cipher/sha512.c

index a823a66..1a6e8e9 100644 (file)
@@ -102,7 +102,10 @@ _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen)
   const unsigned char *inbuf = inbuf_arg;
   gcry_md_block_ctx_t *hd = context;
 
-  if ( hd->buf == NULL || hd->bwrite == NULL)
+  if (sizeof(hd->buf) < hd->blocksize)
+    BUG();
+
+  if (hd->buf == NULL || hd->bwrite == NULL)
     return;
 
   if (hd->count == hd->blocksize)  /* Flush the buffer. */
index 1d1d4ec..4dd5441 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef GCRY_HASH_COMMON_H
 #define GCRY_HASH_COMMON_H
 
+#include "types.h"
+
 
 const char * _gcry_hash_selftest_check_one
 /**/         (int algo,
@@ -29,11 +31,20 @@ const char * _gcry_hash_selftest_check_one
 /* Type for the md_write helper function.  */
 typedef void (*_gcry_md_block_write_t) (void *c, const unsigned char *buf);
 
+#if defined(HAVE_U64_TYPEDEF) && defined(USE_SHA512)
+/* SHA-512 needs u64 and larger buffer. */
+# define MD_BLOCK_MAX_BLOCKSIZE 128
+# define MD_NBLOCKS_TYPE u64
+#else
+# define MD_BLOCK_MAX_BLOCKSIZE 64
+# define MD_NBLOCKS_TYPE u32
+#endif
+
 typedef struct gcry_md_block_ctx
 {
-    u32  nblocks;
-    int  count;
-    byte buf[64];
+    byte buf[MD_BLOCK_MAX_BLOCKSIZE];
+    MD_NBLOCKS_TYPE nblocks;
+    int count;
     size_t blocksize;
     _gcry_md_block_write_t bwrite;
     size_t stack_burn;
index fee3e71..ed63ae6 100644 (file)
 typedef struct
 {
   u64 h0, h1, h2, h3, h4, h5, h6, h7;
-  u64 nblocks;
-  byte buf[128];
-  int count;
+} SHA512_STATE;
+
+typedef struct
+{
+  gcry_md_block_ctx_t bctx;
+  SHA512_STATE state;
 #ifdef USE_ARM_NEON_ASM
   int use_neon;
 #endif
 } SHA512_CONTEXT;
 
 static void
+transform (void *context, const unsigned char *data);
+
+static void
 sha512_init (void *context)
 {
-  SHA512_CONTEXT *hd = context;
+  SHA512_CONTEXT *ctx = context;
+  SHA512_STATE *hd = &ctx->state;
 
   hd->h0 = U64_C(0x6a09e667f3bcc908);
   hd->h1 = U64_C(0xbb67ae8584caa73b);
@@ -89,17 +96,22 @@ sha512_init (void *context)
   hd->h6 = U64_C(0x1f83d9abfb41bd6b);
   hd->h7 = U64_C(0x5be0cd19137e2179);
 
-  hd->nblocks = 0;
-  hd->count = 0;
+  ctx->bctx.nblocks = 0;
+  ctx->bctx.count = 0;
+  ctx->bctx.blocksize = 128;
+  ctx->bctx.bwrite = transform;
+  ctx->bctx.stack_burn = 256;
+
 #ifdef USE_ARM_NEON_ASM
-  hd->use_neon = (_gcry_get_hw_features () & HWF_ARM_NEON) != 0;
+  ctx->use_neon = (_gcry_get_hw_features () & HWF_ARM_NEON) != 0;
 #endif
 }
 
 static void
 sha384_init (void *context)
 {
-  SHA512_CONTEXT *hd = context;
+  SHA512_CONTEXT *ctx = context;
+  SHA512_STATE *hd = &ctx->state;
 
   hd->h0 = U64_C(0xcbbb9d5dc1059ed8);
   hd->h1 = U64_C(0x629a292a367cd507);
@@ -110,10 +122,14 @@ sha384_init (void *context)
   hd->h6 = U64_C(0xdb0c2e0d64f98fa7);
   hd->h7 = U64_C(0x47b5481dbefa4fa4);
 
-  hd->nblocks = 0;
-  hd->count = 0;
+  ctx->bctx.nblocks = 0;
+  ctx->bctx.count = 0;
+  ctx->bctx.blocksize = 128;
+  ctx->bctx.bwrite = transform;
+  ctx->bctx.stack_burn = 256;
+
 #ifdef USE_ARM_NEON_ASM
-  hd->use_neon = (_gcry_get_hw_features () & HWF_ARM_NEON) != 0;
+  ctx->use_neon = (_gcry_get_hw_features () & HWF_ARM_NEON) != 0;
 #endif
 }
 
@@ -196,7 +212,7 @@ static const u64 k[] =
  * Transform the message W which consists of 16 64-bit-words
  */
 static void
-__transform (SHA512_CONTEXT *hd, const unsigned char *data)
+__transform (SHA512_STATE *hd, const unsigned char *data)
 {
   u64 a, b, c, d, e, f, g, h;
   u64 w[16];
@@ -477,71 +493,33 @@ __transform (SHA512_CONTEXT *hd, const unsigned char *data)
 
 
 #ifdef USE_ARM_NEON_ASM
-void _gcry_sha512_transform_armv7_neon (SHA512_CONTEXT *hd,
+void _gcry_sha512_transform_armv7_neon (SHA512_STATE *hd,
                                        const unsigned char *data,
                                        const u64 k[]);
 #endif
 
 
-static unsigned int
-transform (SHA512_CONTEXT *hd, const unsigned char *data)
+static void
+transform (void *context, const unsigned char *data)
 {
+  SHA512_CONTEXT *ctx = context;
+
 #ifdef USE_ARM_NEON_ASM
   if (hd->use_neon)
     {
-      _gcry_sha512_transform_armv7_neon(hd, data, k);
+      _gcry_sha512_transform_armv7_neon(&ctx->state, data, k);
 
+      /* TODO: return burn stack to md_block_write */
       /* return stack burn depth */
-      return (sizeof(void *) * 3);
+      return /*(sizeof(void *) * 3)*/;
     }
 #endif
 
-  __transform (hd, data);
+  __transform (&ctx->state, data);
 
+  /* TODO: return burn stack to md_block_write */
   /* return stack burn depth */
-  return 256;
-}
-
-
-/* Update the message digest with the contents
- * of INBUF with length INLEN.
- */
-static void
-sha512_write (void *context, const void *inbuf_arg, size_t inlen)
-{
-  const unsigned char *inbuf = inbuf_arg;
-  SHA512_CONTEXT *hd = context;
-  unsigned int stack_burn_depth = 0;
-
-  if (hd->count == 128)
-    {                          /* flush the buffer */
-      stack_burn_depth = transform (hd, hd->buf);
-      _gcry_burn_stack (stack_burn_depth);
-      hd->count = 0;
-      hd->nblocks++;
-    }
-  if (!inbuf)
-    return;
-  if (hd->count)
-    {
-      for (; inlen && hd->count < 128; inlen--)
-       hd->buf[hd->count++] = *inbuf++;
-      sha512_write (context, NULL, 0);
-      if (!inlen)
-       return;
-    }
-
-  while (inlen >= 128)
-    {
-      stack_burn_depth = transform (hd, inbuf);
-      hd->count = 0;
-      hd->nblocks++;
-      inlen -= 128;
-      inbuf += 128;
-    }
-  _gcry_burn_stack (stack_burn_depth);
-  for (; inlen && hd->count < 128; inlen--)
-    hd->buf[hd->count++] = *inbuf++;
+  return /*256*/;
 }
 
 
@@ -561,15 +539,15 @@ sha512_final (void *context)
   u64 t, msb, lsb;
   byte *p;
 
-  sha512_write (context, NULL, 0); /* flush */ ;
+  _gcry_md_block_write (context, NULL, 0); /* flush */ ;
 
-  t = hd->nblocks;
+  t = hd->bctx.nblocks;
   /* multiply by 128 to make a byte count */
   lsb = t << 7;
   msb = t >> 57;
   /* add the count */
   t = lsb;
-  if ((lsb += hd->count) < t)
+  if ((lsb += hd->bctx.count) < t)
     msb++;
   /* multiply by 8 to make a bit count */
   t = lsb;
@@ -577,49 +555,50 @@ sha512_final (void *context)
   msb <<= 3;
   msb |= t >> 61;
 
-  if (hd->count < 112)
+  if (hd->bctx.count < 112)
     {                          /* enough room */
-      hd->buf[hd->count++] = 0x80;     /* pad */
-      while (hd->count < 112)
-       hd->buf[hd->count++] = 0;       /* pad */
+      hd->bctx.buf[hd->bctx.count++] = 0x80;   /* pad */
+      while (hd->bctx.count < 112)
+        hd->bctx.buf[hd->bctx.count++] = 0;    /* pad */
     }
   else
     {                          /* need one extra block */
-      hd->buf[hd->count++] = 0x80;     /* pad character */
-      while (hd->count < 128)
-       hd->buf[hd->count++] = 0;
-      sha512_write (context, NULL, 0); /* flush */ ;
-      memset (hd->buf, 0, 112);        /* fill next block with zeroes */
+      hd->bctx.buf[hd->bctx.count++] = 0x80;   /* pad character */
+      while (hd->bctx.count < 128)
+        hd->bctx.buf[hd->bctx.count++] = 0;
+      _gcry_md_block_write (context, NULL, 0); /* flush */ ;
+      memset (hd->bctx.buf, 0, 112);   /* fill next block with zeroes */
     }
   /* append the 128 bit count */
-  hd->buf[112] = msb >> 56;
-  hd->buf[113] = msb >> 48;
-  hd->buf[114] = msb >> 40;
-  hd->buf[115] = msb >> 32;
-  hd->buf[116] = msb >> 24;
-  hd->buf[117] = msb >> 16;
-  hd->buf[118] = msb >> 8;
-  hd->buf[119] = msb;
-
-  hd->buf[120] = lsb >> 56;
-  hd->buf[121] = lsb >> 48;
-  hd->buf[122] = lsb >> 40;
-  hd->buf[123] = lsb >> 32;
-  hd->buf[124] = lsb >> 24;
-  hd->buf[125] = lsb >> 16;
-  hd->buf[126] = lsb >> 8;
-  hd->buf[127] = lsb;
-  stack_burn_depth = transform (hd, hd->buf);
+  hd->bctx.buf[112] = msb >> 56;
+  hd->bctx.buf[113] = msb >> 48;
+  hd->bctx.buf[114] = msb >> 40;
+  hd->bctx.buf[115] = msb >> 32;
+  hd->bctx.buf[116] = msb >> 24;
+  hd->bctx.buf[117] = msb >> 16;
+  hd->bctx.buf[118] = msb >> 8;
+  hd->bctx.buf[119] = msb;
+
+  hd->bctx.buf[120] = lsb >> 56;
+  hd->bctx.buf[121] = lsb >> 48;
+  hd->bctx.buf[122] = lsb >> 40;
+  hd->bctx.buf[123] = lsb >> 32;
+  hd->bctx.buf[124] = lsb >> 24;
+  hd->bctx.buf[125] = lsb >> 16;
+  hd->bctx.buf[126] = lsb >> 8;
+  hd->bctx.buf[127] = lsb;
+  transform (hd, hd->bctx.buf);
+  stack_burn_depth = hd->bctx.stack_burn;
   _gcry_burn_stack (stack_burn_depth);
 
-  p = hd->buf;
+  p = hd->bctx.buf;
 #ifdef WORDS_BIGENDIAN
-#define X(a) do { *(u64*)p = hd->h##a ; p += 8; } while (0)
+#define X(a) do { *(u64*)p = hd->state.h##a ; p += 8; } while (0)
 #else /* little endian */
-#define X(a) do { *p++ = hd->h##a >> 56; *p++ = hd->h##a >> 48;              \
-                  *p++ = hd->h##a >> 40; *p++ = hd->h##a >> 32;              \
-                  *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16;              \
-                  *p++ = hd->h##a >> 8;  *p++ = hd->h##a; } while (0)
+#define X(a) do { *p++ = hd->state.h##a >> 56; *p++ = hd->state.h##a >> 48;    \
+                  *p++ = hd->state.h##a >> 40; *p++ = hd->state.h##a >> 32;    \
+                  *p++ = hd->state.h##a >> 24; *p++ = hd->state.h##a >> 16;    \
+                  *p++ = hd->state.h##a >> 8;  *p++ = hd->state.h##a; } while(0)
 #endif
   X (0);
   X (1);
@@ -638,7 +617,7 @@ static byte *
 sha512_read (void *context)
 {
   SHA512_CONTEXT *hd = (SHA512_CONTEXT *) context;
-  return hd->buf;
+  return hd->bctx.buf;
 }
 
 
@@ -797,7 +776,7 @@ static gcry_md_oid_spec_t oid_spec_sha512[] =
 gcry_md_spec_t _gcry_digest_spec_sha512 =
   {
     "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64,
-    sha512_init, sha512_write, sha512_final, sha512_read,
+    sha512_init, _gcry_md_block_write, sha512_final, sha512_read,
     sizeof (SHA512_CONTEXT),
   };
 md_extra_spec_t _gcry_digest_extraspec_sha512 =
@@ -825,7 +804,7 @@ static gcry_md_oid_spec_t oid_spec_sha384[] =
 gcry_md_spec_t _gcry_digest_spec_sha384 =
   {
     "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48,
-    sha384_init, sha512_write, sha512_final, sha512_read,
+    sha384_init, _gcry_md_block_write, sha512_final, sha512_read,
     sizeof (SHA512_CONTEXT),
   };
 md_extra_spec_t _gcry_digest_extraspec_sha384 =