* basic.c (check_one_md): Kludge to check a one million "a".
authorWerner Koch <wk@gnupg.org>
Mon, 20 Jan 2003 16:58:20 +0000 (16:58 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 20 Jan 2003 16:58:20 +0000 (16:58 +0000)
(check_digests): Add checks for SHA-256.

* sha256.c: New.
* bithelp.h (ror): New.
* Makfile.am: Add sha256.c.
* md.c (oid_table): Add values for SHA256 et al.
(gcry_md_get_algo_dlen): Likewise

* configure.ac (LIBGCRYPT_LT_REVISION): Bumbed up.

NEWS
cipher/ChangeLog
cipher/Makefile.am
cipher/bithelp.h
cipher/md.c
cipher/sha256.c [new file with mode: 0644]
configure.ac
doc/gcrypt.texi
src/gcrypt.h
tests/ChangeLog
tests/basic.c

diff --git a/NEWS b/NEWS
index 1737286..e2c7f4b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 Noteworthy changes in version 1.1.13 (unreleased)
 -------------------------------------------------
 
+ * SHA-256 is now supported.
 
 Noteworthy changes in version 1.1.12 (2003-01-20)
 -------------------------------------------------
index 14b193f..f95600f 100644 (file)
@@ -1,5 +1,13 @@
 2003-01-20  Werner Koch  <wk@gnupg.org>
 
+       * sha256.c: New.
+       * bithelp.h (ror): New.
+       * Makfile.am: Add sha256.c.
+       * md.c (oid_table): Add values for SHA256 et al.
+       (gcry_md_get_algo_dlen): Likewise
+
+2003-01-20  Werner Koch  <wk@gnupg.org>
+
        * pubkey.c (gcry_pk_get_keygrip): Implemented keygrips for DSA
        and ElGamal.
 
index 9ce1cd0..c8edc61 100644 (file)
@@ -28,7 +28,7 @@ noinst_LTLIBRARIES = libcipher.la
 
 
 # The configure script greps the module names from the EXTRA_PROGRAMS line
-EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 rmd160 md4 md5 tiger
+EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 sha256 rmd160 md4 md5 tiger
 
 EXTRA_rndlinux_SOURCES = rndlinux.c
 EXTRA_rndunix_SOURCES = rndunix.c
@@ -38,6 +38,7 @@ EXTRA_md4_SOURCES = md4.c
 EXTRA_md5_SOURCES = md5.c
 EXTRA_rmd160_SOURCES = rmd160.c
 EXTRA_sha1_SOURCES = sha1.c
+EXTRA_sha256_SOURCES = sha256.c
 EXTRA_tiger_SOURCES = tiger.c
 
 
index c9fda65..1505324 100644 (file)
@@ -22,7 +22,7 @@
 
 
 /****************
- * Rotate a 32 bit integer by n bytes
+ * Rotate the 32 bit unsigned integer X by N bits left/right
  */
 #if defined(__GNUC__) && defined(__i386__)
 static inline u32
@@ -34,7 +34,20 @@ rol( u32 x, int n)
        return x;
 }
 #else
-  #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+#if defined(__GNUC__) && defined(__i386__)
+static inline u32
+ror(u32 x, int n)
+{
+       __asm__("rorl %%cl,%0"
+               :"=r" (x)
+               :"0" (x),"c" (n));
+       return x;
+}
+#else
+#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) )
 #endif
 
 
index bd5f7a2..1928dc2 100644 (file)
@@ -53,6 +53,10 @@ static struct {
   { "1.2.840.113549.2.4", GCRY_MD_MD4 },
   /* from NIST OIW (sha-1WithRSAEncryption) */
   { "1.3.14.3.2.29", GCRY_MD_SHA1 },
+  /* According to the OpenPGG draft rfc2440-bis06 */
+  { "2.16.840.1.101.3.4.2.1", GCRY_MD_SHA256 }, 
+  { "2.16.840.1.101.3.4.2.2", GCRY_MD_SHA384 }, 
+  { "2.16.840.1.101.3.4.2.3", GCRY_MD_SHA512 }, 
   {NULL}
 };
 
@@ -818,19 +822,23 @@ md_digest_length( int algo )
 unsigned int
 gcry_md_get_algo_dlen( int algo )
 {
-    /* we do some very quick checks here */
-    switch( algo )
+  /* we cheat a little bit */
+  switch( algo )
     {
-      case GCRY_MD_MD4:
-      case GCRY_MD_MD5: return 16;
-      case GCRY_MD_SHA1:
-      case GCRY_MD_RMD160: return 20;
-      default: {
-           int len = md_digest_length( algo );
-           if( !len )
-               set_lasterr( GCRYERR_INV_MD_ALGO );
-           return 0;
-       }
+    case GCRY_MD_MD4:
+    case GCRY_MD_MD5: return 16;
+    case GCRY_MD_SHA1:
+    case GCRY_MD_RMD160: return 20;
+    case GCRY_MD_SHA256: return 32;
+    case GCRY_MD_SHA384: return 48;
+    case GCRY_MD_SHA512: return 64;
+    default: 
+      {
+        int len = md_digest_length( algo );
+        if( !len )
+          set_lasterr( GCRYERR_INV_MD_ALGO );
+        return 0;
+      }
     }
 }
 
diff --git a/cipher/sha256.c b/cipher/sha256.c
new file mode 100644 (file)
index 0000000..9eb2bbe
--- /dev/null
@@ -0,0 +1,392 @@
+/* sha256.c - SHA256 hash function
+ *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  Test vectors:
+    
+    "abc"
+    ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad
+
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+    248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
+    "a" one million times
+    cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0
+
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "g10lib.h"
+#include "memory.h"
+#include "dynload.h"
+#include "bithelp.h"
+
+
+typedef struct {
+  u32  h0,h1,h2,h3,h4,h5,h6,h7;
+  u32  nblocks;
+  byte buf[64];
+  int  count;
+} SHA256_CONTEXT;
+
+
+static void
+burn_stack (int bytes)
+{
+    char buf[128];
+    
+    memset (buf, 0, sizeof buf);
+    bytes -= sizeof buf;
+    if (bytes > 0)
+        burn_stack (bytes);
+}
+
+
+static void
+sha256_init (SHA256_CONTEXT *hd)
+{
+  hd->h0 = 0x6a09e667;
+  hd->h1 = 0xbb67ae85;
+  hd->h2 = 0x3c6ef372;
+  hd->h3 = 0xa54ff53a;
+  hd->h4 = 0x510e527f;
+  hd->h5 = 0x9b05688c;
+  hd->h6 = 0x1f83d9ab;
+  hd->h7 = 0x5be0cd19;
+
+  hd->nblocks = 0;
+  hd->count = 0;
+}
+
+
+/*
+  Transform the message X which consists of 16 32-bit-words. See FIPS
+  180-2 for details.  */
+#define Cho(x,y,z) (z ^ (x & (y ^ z)))      /* (4.2) same as SHA-1's F1 */
+#define Maj(x,y,z) ((x & y) | (z & (x|y)))  /* (4.3) same as SHA-1's F3 */
+#define Sum0(x) (ror ((x), 2) ^ ror ((x), 13) ^ ror ((x), 22))  /* (4.4) */
+#define Sum1(x) (ror ((x), 6) ^ ror ((x), 11) ^ ror ((x), 25))  /* (4.5) */
+#define S0(x) (ror ((x), 7) ^ ror ((x), 18) ^ ((x) >> 3))       /* (4.6) */
+#define S1(x) (ror ((x), 17) ^ ror ((x), 19) ^ ((x) >> 10))     /* (4.7) */
+#define R(a,b,c,d,e,f,g,h,k,w) do                                 \
+          {                                                       \
+            t1 = (h) + Sum1((e)) + Cho((e),(f),(g)) + (k) + (w);  \
+            t2 = Sum0((a)) + Maj((a),(b),(c));                    \
+            h = g;                                                \
+            g = f;                                                \
+            f = e;                                                \
+            e = d + t1;                                           \
+            d = c;                                                \
+            c = b;                                                \
+            b = a;                                                \
+            a = t1 + t2;                                          \
+          } while (0)
+static void
+transform (SHA256_CONTEXT *hd, byte *data)
+{
+  static const u32 K[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+  };
+
+  u32 a,b,c,d,e,f,g,h,t1,t2;
+  u32 x[16];
+  u32 w[64];
+  int i;
+  
+  a = hd->h0;
+  b = hd->h1;
+  c = hd->h2;
+  d = hd->h3;
+  e = hd->h4;
+  f = hd->h5;
+  g = hd->h6;
+  h = hd->h7;
+  
+#ifdef BIG_ENDIAN_HOST
+  memcpy (x, data, 64);
+#else
+  { 
+    byte *p2;
+  
+    for (i=0, p2=(byte*)x; i < 16; i++, p2 += 4 ) 
+      {
+        p2[3] = *data++;
+        p2[2] = *data++;
+        p2[1] = *data++;
+        p2[0] = *data++;
+      }
+  }
+#endif
+
+  for (i=0; i < 16; i++)
+    w[i] = x[i];
+  for (; i < 64; i++)
+    w[i] = S1(w[i-2]) + w[i-7] + S0(w[i-15]) + w[i-16];
+
+  for (i=0; i < 64; i++)
+    R(a,b,c,d,e,f,g,h,K[i],w[i]);
+
+  hd->h0 += a;
+  hd->h1 += b;
+  hd->h2 += c;
+  hd->h3 += d;
+  hd->h4 += e;
+  hd->h5 += f;
+  hd->h6 += g;
+  hd->h7 += h;
+}
+#undef Cho
+#undef Maj
+#undef Sum0
+#undef Sum1
+#undef S0
+#undef S1
+#undef R
+
+
+/* Update the message digest with the contents of INBUF with length
+  INLEN.  */
+static void
+sha256_write (SHA256_CONTEXT *hd, byte *inbuf, size_t inlen)
+{
+  if (hd->count == 64)
+    { /* flush the buffer */
+      transform (hd, hd->buf);
+      burn_stack (74*4+32);
+      hd->count = 0;
+      hd->nblocks++;
+    }
+  if (!inbuf)
+    return;
+  if (hd->count)
+    {
+      for (; inlen && hd->count < 64; inlen--)
+        hd->buf[hd->count++] = *inbuf++;
+      sha256_write (hd, NULL, 0);
+      if (!inlen)
+        return;
+    }
+
+  while (inlen >= 64)
+    {
+      transform (hd, inbuf);
+      hd->count = 0;
+      hd->nblocks++;
+      inlen -= 64;
+      inbuf += 64;
+    }
+  burn_stack (74*4+32);
+  for (; inlen && hd->count < 64; inlen--)
+    hd->buf[hd->count++] = *inbuf++;
+}
+
+
+/*
+   The routine finally terminates the computation and returns the
+   digest.  The handle is prepared for a new cycle, but adding bytes
+   to the handle will the destroy the returned buffer.  Returns: 32
+   bytes with the message the digest.  */
+static void
+sha256_final(SHA256_CONTEXT *hd)
+{
+  u32 t, msb, lsb;
+  byte *p;
+  
+  sha256_write (hd, NULL, 0); /* flush */;
+
+  t = hd->nblocks;
+  /* multiply by 64 to make a byte count */
+  lsb = t << 6;
+  msb = t >> 26;
+  /* add the count */
+  t = lsb;
+  if ((lsb += hd->count) < t)
+    msb++;
+  /* multiply by 8 to make a bit count */
+  t = lsb;
+  lsb <<= 3;
+  msb <<= 3;
+  msb |= t >> 29;
+
+  if (hd->count < 56)
+    { /* enough room */
+      hd->buf[hd->count++] = 0x80; /* pad */
+      while (hd->count < 56)
+        hd->buf[hd->count++] = 0;  /* pad */
+    }
+  else
+    { /* need one extra block */
+      hd->buf[hd->count++] = 0x80; /* pad character */
+      while (hd->count < 64)
+        hd->buf[hd->count++] = 0;
+      sha256_write (hd, NULL, 0);  /* flush */;
+      memset (hd->buf, 0, 56 ); /* fill next block with zeroes */
+    }
+  /* append the 64 bit count */
+  hd->buf[56] = msb >> 24;
+  hd->buf[57] = msb >> 16;
+  hd->buf[58] = msb >>  8;
+  hd->buf[59] = msb;
+  hd->buf[60] = lsb >> 24;
+  hd->buf[61] = lsb >> 16;
+  hd->buf[62] = lsb >>  8;
+  hd->buf[63] = lsb;
+  transform (hd, hd->buf);
+  burn_stack (74*4+32);
+
+  p = hd->buf;
+#ifdef BIG_ENDIAN_HOST
+#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+#else /* little endian */
+#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16;         \
+                 *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
+#endif
+  X(0);
+  X(1);
+  X(2);
+  X(3);
+  X(4);
+  X(5);
+  X(6);
+  X(7);
+#undef X
+}
+
+static byte *
+sha256_read (SHA256_CONTEXT *hd)
+{
+  return hd->buf;
+}
+
+/*
+   Return some information about the algorithm.  We need algo here to
+   distinguish different flavors of the algorithm.  Returns: A pointer
+   to string describing the algorithm or NULL if the ALGO is invalid.  */
+static const char *
+sha256_get_info (int algo, size_t *contextsize,
+                 byte **r_asnoid, int *r_asnlen, int *r_mdlen,
+                 void (**r_init)( void *c ),
+                 void (**r_write)( void *c, byte *buf, size_t nbytes ),
+                 void (**r_final)( void *c ),
+                 byte *(**r_read)( void *c )
+                 )
+{
+  static byte asn[19] = /* Object ID is  2.16.840.1.101.3.4.2.1 */
+  { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+    0x00, 0x04, 0x20 };
+
+  if(algo != 8)
+    return NULL;
+
+  *contextsize = sizeof(SHA256_CONTEXT);
+  *r_asnoid = asn;
+  *r_asnlen = DIM(asn);
+  *r_mdlen = 32;
+  *(void  (**)(SHA256_CONTEXT *))r_init                  = sha256_init;
+  *(void  (**)(SHA256_CONTEXT *, byte*, size_t))r_write = sha256_write;
+  *(void  (**)(SHA256_CONTEXT *))r_final                 = sha256_final;
+  *(byte *(**)(SHA256_CONTEXT *))r_read                  = sha256_read;
+  
+  return "SHA256";
+}
+
+
+
+#ifndef IS_MODULE
+static
+#endif
+const char * const gnupgext_version = "SHA256 ($Revision$)";
+
+static struct {
+    int class;
+    int version;
+    int  value;
+    void (*func)(void);
+} func_table[] = {
+    { 10, 1, 0, (void(*)(void))sha256_get_info },
+    { 11, 1, 8 },
+};
+
+
+#ifndef IS_MODULE
+static
+#endif
+void *
+gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
+{
+    void *ret;
+    int i = *sequence;
+
+    do {
+       if( i >= DIM(func_table) || i < 0 ) {
+           return NULL;
+       }
+       *class = func_table[i].class;
+       *vers  = func_table[i].version;
+       switch( *class ) {
+         case 11:
+         case 21:
+         case 31:
+           ret = &func_table[i].value;
+           break;
+         default:
+           ret = func_table[i].func;
+           break;
+       }
+       i++;
+    } while( what && what != *class );
+
+    *sequence = i;
+    return ret;
+}
+
+
+
+
+#ifndef IS_MODULE
+void
+_gcry_sha256_constructor(void)
+{
+  _gcry_register_internal_cipher_extension (gnupgext_version,
+                                            gnupgext_enum_func );
+}
+#endif
index 653047b..821e871 100644 (file)
@@ -71,7 +71,7 @@ AC_SUBST(VERSION)
 AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package])
 AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package])
 
-static_modules="sha1 md4 md5 rmd160"
+static_modules="sha1 sha256 md4 md5 rmd160"
 static_random_module=""
 
 AC_PROG_AWK
index e141555..24049d2 100644 (file)
@@ -645,8 +645,8 @@ bit. It yields a message digest of 20 bytes.  Note that there is no
 implementation yet available.
 
 @item GCRY_MD_SHA256
-This is reserved for SHA-2 with 256 bits. It yields a message digest of
-32 bytes.  Note that there is no implementation yet available.
+This is the SHA-256 algorithm which yields a message digest of 32 bytes.
+See FIPS 180-2 for the specification.
 
 @item GCRY_MD_SHA384
 This is reserved for SHA-2 with 384 bits. It yields a message digest of
index 6ae2346..bfa2cb7 100644 (file)
@@ -37,7 +37,7 @@ extern "C" {
    autoconf (using the AM_PATH_GCRYPT macro) check that this header
    matches the installed library.  Note: Do not edit the next line as
    configure may fix the string here.  */
-#define GCRYPT_VERSION "1.1.12"
+#define GCRYPT_VERSION "1.1.13-cvs"
 
 /* Internal: We can't use the convenience macros for the multi
    precision integer functions when building this library. */
index 962d3c3..26e594d 100644 (file)
@@ -1,5 +1,10 @@
 2003-01-20  Werner Koch  <wk@gnupg.org>
 
+       * basic.c (check_one_md): Kludge to check a one million "a".
+       (check_digests): Add checks for SHA-256.
+
+2003-01-20  Werner Koch  <wk@gnupg.org>
+
        * basic.c (check_pubkey): Check the keygrip for the sample key.
 
 2003-01-15  Werner Koch  <wk@gnupg.org>
index b3712e9..c065d9d 100644 (file)
@@ -282,12 +282,15 @@ check_ciphers (void)
   /* TODO: add some extra encryption to test the higher level functions */
 }
 
+
+
 static void
 check_one_md (int algo, char *data, int len, char *expect)
 {
     GCRY_MD_HD hd;
     char *p;
     int mdlen;
+    int i;
 
     hd = gcry_md_open (algo, 0);
     if (!hd) {
@@ -301,8 +304,17 @@ check_one_md (int algo, char *data, int len, char *expect)
         fail ("algo %d, grcy_md_get_algo_dlen failed: %d\n", algo, mdlen);
         return;
     }
-    
-    gcry_md_write (hd, data, len);
+
+    if (*data == '!' && !data[1])
+      { /* hash one million times a "a" */
+        char aaa[1000];
+        
+        memset (aaa, 'a', 1000);
+        for (i=0; i < 1000; i++)
+          gcry_md_write (hd, aaa, 1000);
+      }
+    else
+      gcry_md_write (hd, data, len);
 
     p = gcry_md_read (hd, algo);
 
@@ -340,6 +352,18 @@ check_digests ()
     { GCRY_MD_SHA1, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
       "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE"
       "\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1" },
+    { GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */,
+      "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
+      "\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
+    { GCRY_MD_SHA256, "abc",
+      "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
+      "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
+    { GCRY_MD_SHA256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
+      "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
+    { GCRY_MD_SHA256, "!",
+      "\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67" 
+      "\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0" },
     { GCRY_MD_RMD160, "",
       "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
       "\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31" },