Add framework to eventually support SHA3.
authorWerner Koch <wk@gnupg.org>
Sat, 8 Aug 2015 08:47:55 +0000 (10:47 +0200)
committerWerner Koch <wk@gnupg.org>
Sat, 8 Aug 2015 08:47:55 +0000 (10:47 +0200)
* src/gcrypt.h.in (GCRY_MD_SHA3_224, GCRY_MD_SHA3_256)
(GCRY_MD_SHA3_384, GCRY_MD_SHA3_512): New.
(GCRY_MAC_HMAC_SHA3_224, GCRY_MAC_HMAC_SHA3_256)
(GCRY_MAC_HMAC_SHA3_384, GCRY_MAC_HMAC_SHA3_512): New.
* cipher/keccak.c: New with stub functions.
* cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add keccak.c.
* configure.ac (available_digests): Add sha3.
(USE_SHA3): New.
* src/fips.c (run_hmac_selftests): Add SHA3 to the required selftests.
* cipher/md.c (digest_list) [USE_SHA3]: Add standard SHA3 algos.
(md_open): Ditto for hmac processing.
* cipher/mac-hmac.c (map_mac_algo_to_md): Add mapping.
* cipher/hmac-tests.c (run_selftests): Prepare for tests.
* cipher/pubkey-util.c (get_hash_algo): Add "sha3-xxx".
--

Note that the algo GCRY_MD_SHA3_xxx are prelimanry.  We should try to
sync them with OpenPGP.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/Makefile.am
cipher/hmac-tests.c
cipher/keccak.c [new file with mode: 0644]
cipher/mac-hmac.c
cipher/md.c
cipher/pubkey-util.c
configure.ac
src/cipher.h
src/fips.c
src/gcrypt.h.in

index 33a68ff..b08c9a9 100644 (file)
@@ -90,6 +90,7 @@ sha1.c sha1-ssse3-amd64.S sha1-avx-amd64.S sha1-avx-bmi2-amd64.S \
 sha256.c sha256-ssse3-amd64.S sha256-avx-amd64.S sha256-avx2-bmi2-amd64.S \
 sha512.c sha512-ssse3-amd64.S sha512-avx-amd64.S sha512-avx2-bmi2-amd64.S \
   sha512-armv7-neon.S \
+keccak.c \
 stribog.c \
 tiger.c \
 whirlpool.c whirlpool-sse2-amd64.S \
index 7c27342..46e1b22 100644 (file)
@@ -701,6 +701,17 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
     case GCRY_MD_SHA512:
       ec = selftests_sha512 (extended, report);
       break;
+
+    case GCRY_MD_SHA3_224:
+    case GCRY_MD_SHA3_256:
+    case GCRY_MD_SHA3_384:
+    case GCRY_MD_SHA3_512:
+      ec = 0;  /* FIXME: Add selftests.  */
+#ifdef __GNUC__
+# warning Please add the self text functions
+#endif
+      break;
+
     default:
       ec = GPG_ERR_DIGEST_ALGO;
       break;
diff --git a/cipher/keccak.c b/cipher/keccak.c
new file mode 100644 (file)
index 0000000..625c5c7
--- /dev/null
@@ -0,0 +1,264 @@
+/* keccak.c - SHA3 hash functions
+ * Copyright (C) 2015  g10 Code GmbH
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <config.h>
+#include <string.h>
+#include "g10lib.h"
+#include "bithelp.h"
+#include "bufhelp.h"
+#include "cipher.h"
+#include "hash-common.h"
+
+
+
+typedef struct
+{
+  u64 h0;
+} KECCAK_STATE;
+
+
+typedef struct
+{
+  gcry_md_block_ctx_t bctx;
+  KECCAK_STATE state;
+} KECCAK_CONTEXT;
+
+
+
+static void
+keccak_init (int algo, void *context, unsigned int flags)
+{
+  KECCAK_CONTEXT *ctx = context;
+  KECCAK_STATE *hd = &ctx->state;
+  unsigned int features = _gcry_get_hw_features ();
+
+  (void)flags;
+
+  memset (hd, 0, sizeof *hd);
+
+  ctx->bctx.nblocks = 0;
+  ctx->bctx.nblocks_high = 0;
+  ctx->bctx.count = 0;
+  ctx->bctx.blocksize = 128;
+  ctx->bctx.bwrite = NULL;
+
+  (void)features;
+}
+
+static void
+sha3_224_init (void *context, unsigned int flags)
+{
+  keccak_init (GCRY_MD_SHA3_224, context, flags);
+}
+
+static void
+sha3_256_init (void *context, unsigned int flags)
+{
+  keccak_init (GCRY_MD_SHA3_256, context, flags);
+}
+
+static void
+sha3_384_init (void *context, unsigned int flags)
+{
+  keccak_init (GCRY_MD_SHA3_384, context, flags);
+}
+
+static void
+sha3_512_init (void *context, unsigned int flags)
+{
+  keccak_init (GCRY_MD_SHA3_512, context, flags);
+}
+
+
+/* The routine final 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: 64 bytes representing the digest.  When used for sha384,
+ * we take the leftmost 48 of those bytes.
+ */
+static void
+keccak_final (void *context)
+{
+  KECCAK_CONTEXT *hd = context;
+  unsigned int stack_burn_depth;
+
+  _gcry_md_block_write (context, NULL, 0); /* flush */ ;
+}
+
+
+static byte *
+keccak_read (void *context)
+{
+  KECCAK_CONTEXT *hd = (KECCAK_CONTEXT *) context;
+  return hd->bctx.buf;
+}
+
+
+\f
+/*
+     Self-test section.
+ */
+
+
+static gpg_err_code_t
+selftests_keccak (int algo, int extended, selftest_report_func_t report)
+{
+  return 0;
+#if 0
+  const char *what;
+  const char *errtxt;
+
+  /* FIXME: Add a switch(algo) or use several functions.  */
+  what = "short string";
+  errtxt = _gcry_hash_selftest_check_one
+    (GCRY_MD_SHA3_384, 0,
+     "abc", 3,
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 48);
+  if (errtxt)
+    goto failed;
+
+  if (extended)
+    {
+      what = "long string";
+      errtxt = _gcry_hash_selftest_check_one
+        (GCRY_MD_SHA3_384, 0,
+         "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+         "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112,
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",48);
+      if (errtxt)
+        goto failed;
+
+      what = "one million \"a\"";
+      errtxt = _gcry_hash_selftest_check_one
+        (GCRY_MD_SHA3_384, 1,
+         NULL, 0,
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",48);
+      if (errtxt)
+        goto failed;
+    }
+
+  return 0; /* Succeeded. */
+
+ failed:
+  if (report)
+    report ("digest", algo, what, errtxt);
+  return GPG_ERR_SELFTEST_FAILED;
+#endif
+}
+
+
+/* Run a full self-test for ALGO and return 0 on success.  */
+static gpg_err_code_t
+run_selftests (int algo, int extended, selftest_report_func_t report)
+{
+  gpg_err_code_t ec;
+
+  switch (algo)
+    {
+    case GCRY_MD_SHA3_224:
+    case GCRY_MD_SHA3_256:
+    case GCRY_MD_SHA3_384:
+    case GCRY_MD_SHA3_512:
+      ec = selftests_keccak (algo, extended, report);
+      break;
+    default:
+      ec = GPG_ERR_DIGEST_ALGO;
+      break;
+
+    }
+  return ec;
+}
+
+
+
+\f
+static byte sha3_224_asn[] = { 0x30 };
+static gcry_md_oid_spec_t oid_spec_sha3_224[] =
+  {
+    { "?" },
+    /* PKCS#1 sha3_224WithRSAEncryption */
+    { "?" },
+    { NULL }
+  };
+static byte sha3_256_asn[] = { 0x30 };
+static gcry_md_oid_spec_t oid_spec_sha3_256[] =
+  {
+    { "?" },
+    /* PKCS#1 sha3_256WithRSAEncryption */
+    { "?" },
+    { NULL }
+  };
+static byte sha3_384_asn[] = { 0x30 };
+static gcry_md_oid_spec_t oid_spec_sha3_384[] =
+  {
+    { "?" },
+    /* PKCS#1 sha3_384WithRSAEncryption */
+    { "?" },
+    { NULL }
+  };
+static byte sha3_512_asn[] = { 0x30 };
+static gcry_md_oid_spec_t oid_spec_sha3_512[] =
+  {
+    { "?" },
+    /* PKCS#1 sha3_512WithRSAEncryption */
+    { "?" },
+    { NULL }
+  };
+
+
+gcry_md_spec_t _gcry_digest_spec_sha3_224 =
+  {
+    GCRY_MD_SHA3_224, {0, 1},
+    "SHA3-224", sha3_224_asn, DIM (sha3_224_asn), oid_spec_sha3_224, 64,
+    sha3_224_init, _gcry_md_block_write, keccak_final, keccak_read,
+    sizeof (KECCAK_CONTEXT),
+    run_selftests
+  };
+gcry_md_spec_t _gcry_digest_spec_sha3_256 =
+  {
+    GCRY_MD_SHA3_256, {0, 1},
+    "SHA3-256", sha3_256_asn, DIM (sha3_256_asn), oid_spec_sha3_256, 64,
+    sha3_256_init, _gcry_md_block_write, keccak_final, keccak_read,
+    sizeof (KECCAK_CONTEXT),
+    run_selftests
+  };
+gcry_md_spec_t _gcry_digest_spec_sha3_384 =
+  {
+    GCRY_MD_SHA3_384, {0, 1},
+    "SHA3-384", sha3_384_asn, DIM (sha3_384_asn), oid_spec_sha3_384, 64,
+    sha3_384_init, _gcry_md_block_write, keccak_final, keccak_read,
+    sizeof (KECCAK_CONTEXT),
+    run_selftests
+  };
+gcry_md_spec_t _gcry_digest_spec_sha3_512 =
+  {
+    GCRY_MD_SHA3_512, {0, 1},
+    "SHA3-512", sha3_512_asn, DIM (sha3_512_asn), oid_spec_sha3_512, 64,
+    sha3_512_init, _gcry_md_block_write, keccak_final, keccak_read,
+    sizeof (KECCAK_CONTEXT),
+    run_selftests
+  };
index 2c660e9..eeab130 100644 (file)
@@ -51,6 +51,14 @@ map_mac_algo_to_md (int mac_algo)
       return GCRY_MD_SHA384;
     case GCRY_MAC_HMAC_SHA512:
       return GCRY_MD_SHA512;
+    case GCRY_MAC_HMAC_SHA3_224:
+      return GCRY_MD_SHA3_224;
+    case GCRY_MAC_HMAC_SHA3_256:
+      return GCRY_MD_SHA3_256;
+    case GCRY_MAC_HMAC_SHA3_384:
+      return GCRY_MD_SHA3_384;
+    case GCRY_MAC_HMAC_SHA3_512:
+      return GCRY_MD_SHA512;
     case GCRY_MAC_HMAC_RMD160:
       return GCRY_MD_RMD160;
     case GCRY_MAC_HMAC_TIGER1:
index 3ab46ef..0c669ca 100644 (file)
@@ -51,6 +51,12 @@ static gcry_md_spec_t *digest_list[] =
      &_gcry_digest_spec_sha512,
      &_gcry_digest_spec_sha384,
 #endif
+#if USE_SHA3
+     &_gcry_digest_spec_sha3_224,
+     &_gcry_digest_spec_sha3_256,
+     &_gcry_digest_spec_sha3_384,
+     &_gcry_digest_spec_sha3_512,
+#endif
 #ifdef USE_GOST_R_3411_94
      &_gcry_digest_spec_gost3411_94,
      &_gcry_digest_spec_gost3411_cp,
@@ -333,6 +339,8 @@ md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
             {
               case GCRY_MD_SHA384:
               case GCRY_MD_SHA512:
+              case GCRY_MD_SHA3_384:
+              case GCRY_MD_SHA3_512:
                 ctx->macpads_Bsize = 128;
                 break;
               case GCRY_MD_GOSTR3411_94:
index b958e7d..d0d6003 100644 (file)
@@ -217,6 +217,10 @@ get_hash_algo (const char *s, size_t n)
     { "md4",    GCRY_MD_MD4 },
     { "tiger",  GCRY_MD_TIGER },
     { "haval",  GCRY_MD_HAVAL },
+    { "sha3-224", GCRY_MD_SHA3_224 },
+    { "sha3-256", GCRY_MD_SHA3_256 },
+    { "sha3-384", GCRY_MD_SHA3_384 },
+    { "sha3-512", GCRY_MD_SHA3_512 },
     { NULL, 0 }
   };
   int algo;
index 0f16175..48e2179 100644 (file)
@@ -198,7 +198,7 @@ enabled_pubkey_ciphers=""
 
 # Definitions for message digests.
 available_digests="crc gostr3411-94 md2 md4 md5 rmd160 sha1 sha256"
-available_digests_64="sha512 tiger whirlpool stribog"
+available_digests_64="sha512 sha3 tiger whirlpool stribog"
 enabled_digests=""
 
 # Definitions for kdfs (optional ones)
@@ -2094,6 +2094,24 @@ if test "$found" = "1" ; then
    fi
 fi
 
+LIST_MEMBER(sha3, $enabled_digests)
+if test "$found" = "1" ; then
+   GCRYPT_DIGESTS="$GCRYPT_DIGESTS keccak.lo"
+   AC_DEFINE(USE_SHA3, 1, [Defined if this module should be included])
+
+   case "${host}" in
+      x86_64-*-*)
+         # Build with the assembly implementation
+         :
+      ;;
+   esac
+
+   if test x"$neonsupport" = xyes ; then
+     # Build with the NEON implementation
+     :
+   fi
+fi
+
 LIST_MEMBER(tiger, $enabled_digests)
 if test "$found" = "1" ; then
    GCRYPT_DIGESTS="$GCRYPT_DIGESTS tiger.lo"
index 89ae2e2..d96fdb9 100644 (file)
@@ -289,8 +289,12 @@ extern gcry_md_spec_t _gcry_digest_spec_rmd160;
 extern gcry_md_spec_t _gcry_digest_spec_sha1;
 extern gcry_md_spec_t _gcry_digest_spec_sha224;
 extern gcry_md_spec_t _gcry_digest_spec_sha256;
-extern gcry_md_spec_t _gcry_digest_spec_sha512;
 extern gcry_md_spec_t _gcry_digest_spec_sha384;
+extern gcry_md_spec_t _gcry_digest_spec_sha512;
+extern gcry_md_spec_t _gcry_digest_spec_sha3_224;
+extern gcry_md_spec_t _gcry_digest_spec_sha3_256;
+extern gcry_md_spec_t _gcry_digest_spec_sha3_512;
+extern gcry_md_spec_t _gcry_digest_spec_sha3_384;
 extern gcry_md_spec_t _gcry_digest_spec_tiger;
 extern gcry_md_spec_t _gcry_digest_spec_tiger1;
 extern gcry_md_spec_t _gcry_digest_spec_tiger2;
index c90e4b6..7939abd 100644 (file)
@@ -518,6 +518,10 @@ run_hmac_selftests (int extended)
       GCRY_MD_SHA256,
       GCRY_MD_SHA384,
       GCRY_MD_SHA512,
+      GCRY_MD_SHA3_224,
+      GCRY_MD_SHA3_256,
+      GCRY_MD_SHA3_384,
+      GCRY_MD_SHA3_512,
       0
     };
   int idx;
index 0984d11..4b4646b 100644 (file)
@@ -1158,7 +1158,12 @@ enum gcry_md_algos
     GCRY_MD_SHA384  = 9,
     GCRY_MD_SHA512  = 10,
     GCRY_MD_SHA224  = 11,
-    GCRY_MD_MD4     = 301,
+    GCRY_MD_SHA3_224= 12,
+    GCRY_MD_SHA3_256= 13,
+    GCRY_MD_SHA3_384= 14,
+    GCRY_MD_SHA3_512= 15,
+
+    GCRY_MD_MD4           = 301,
     GCRY_MD_CRC32         = 302,
     GCRY_MD_CRC32_RFC1510 = 303,
     GCRY_MD_CRC24_RFC2440 = 304,
@@ -1345,6 +1350,10 @@ enum gcry_mac_algos
     GCRY_MAC_HMAC_STRIBOG256    = 112,
     GCRY_MAC_HMAC_STRIBOG512    = 113,
     GCRY_MAC_HMAC_MD2           = 114,
+    GCRY_MAC_HMAC_SHA3_224      = 115,
+    GCRY_MAC_HMAC_SHA3_256      = 116,
+    GCRY_MAC_HMAC_SHA3_384      = 117,
+    GCRY_MAC_HMAC_SHA3_512      = 118,
 
     GCRY_MAC_CMAC_AES           = 201,
     GCRY_MAC_CMAC_3DES          = 202,