[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-108-gf23a068

by Werner Koch cvs at cvs.gnupg.org
Fri Apr 5 12:42:45 CEST 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  f23a068bcb6ec9788710698578d8be0a2a006dbc (commit)
       via  855b1a8f81b5a3b5b31d0c3c303675425f58a5af (commit)
       via  02e8344d3803b80b74bc9b56d718304a6588bc14 (commit)
      from  8650b6ca7c77e477234f9a1586e6a86b1c79fff3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f23a068bcb6ec9788710698578d8be0a2a006dbc
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Apr 5 12:23:41 2013 +0200

    Add test case for SCRYPT and rework the code.
    
    * tests/t-kdf.c (check_scrypt): New.
    (main): Call new test.
    
    * configure.ac: Support disabling of the scrypt algorithm.  Make KDF
    enabling similar to the other algorithm classes.  Disable scrypt if we
    don't have a 64 bit type.
    * cipher/memxor.c, cipher/memxor.h: Remove.
    * cipher/scrypt.h: Remove.
    * cipher/kdf-internal.h: New.
    * cipher/Makefile.am: Remove files.  Add new file.  Move scrypt.c to
    EXTRA_libcipher_la_SOURCES.
    (GCRYPT_MODULES): Add GCRYPT_KDFS.
    * src/gcrypt.h.in (GCRY_KDF_SCRYPT): Change value.
    * cipher/kdf.c (pkdf2): Rename to _gcry_kdf_pkdf2.
    (_gcry_kdf_pkdf2): Don't bail out for SALTLEN==0.
    (gcry_kdf_derive): Allow for a passwordlen of zero for scrypt.  Check
    for SALTLEN > 0 for GCRY_KDF_PBKDF2.  Pass algo to _gcry_kdf_scrypt.
    (gcry_kdf_derive) [!USE_SCRYPT]: Return an error.
    * cipher/scrypt.c: Replace memxor.h by bufhelp.h.  Replace scrypt.h by
    kdf-internal.h.  Enable code only if HAVE_U64_TYPEDEF is defined.
    Replace C99 types uint64_t, uint32_t, and uint8_t by libgcrypt types.
    (_SALSA20_INPUT_LENGTH): Remove underscore from identifier.
    (_scryptBlockMix): Replace memxor by buf_xor.
    (_gcry_kdf_scrypt): Use gcry_malloc and gcry_free.  Check for integer
    overflow.  Add hack to support blocksize of 1 for tests.  Return
    errors from calls to _gcry_kdf_pkdf2.
    
    * cipher/kdf.c (openpgp_s2k): Make static.
    --
    
    This patch prepares the addition of more KDF functions, brings the
    code into Libgcrypt shape, adds a test case and makes the code more
    robust.  For example, scrypt would have fail silently if Libgcrypt was
    not build with SHA256 support.  Also fixed symbol naming for systems
    without a visibility support.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 0d75680..926e531 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ Noteworthy changes in version 1.6.0 (unreleased)
  * Added a random number generator to directly use the system's RNG.
    Also added an interface to prefer the use of a specified RNG.
 
+ * Added support for the SCRYPT algorithm.
+
  * Interface changes relative to the 1.5.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gcry_ac_*              REMOVED.
@@ -58,6 +60,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  GCRYMPI_FLAG_IMMUTABLE          NEW.
  GCRYMPI_FLAG_CONST              NEW.
  GCRYPT_VERSION_NUMBER           NEW.
+ GCRY_KDF_SCRYPT                 NEW.
 
 
 Noteworthy changes in version 1.5.0 (2011-06-29)
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 5b016f0..5189794 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -31,7 +31,8 @@ AM_CCASFLAGS = $(NOEXECSTACK_FLAGS)
 
 noinst_LTLIBRARIES = libcipher.la
 
-GCRYPT_MODULES = @GCRYPT_CIPHERS@ @GCRYPT_PUBKEY_CIPHERS@ @GCRYPT_DIGESTS@
+GCRYPT_MODULES = @GCRYPT_CIPHERS@ @GCRYPT_PUBKEY_CIPHERS@ \
+                 @GCRYPT_DIGESTS@ @GCRYPT_KDFS@
 
 libcipher_la_DEPENDENCIES = $(GCRYPT_MODULES)
 libcipher_la_LIBADD = $(GCRYPT_MODULES)
@@ -39,7 +40,8 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES)
 libcipher_la_SOURCES = \
 cipher.c cipher-internal.h \
 cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \
-pubkey.c md.c kdf.c scrypt.c memxor.c \
+pubkey.c md.c \
+kdf.c kdf-internal.h \
 hmac-tests.c \
 bithelp.h  \
 bufhelp.h  \
@@ -62,6 +64,7 @@ md5.c \
 rijndael.c rijndael-tables.h \
 rmd160.c \
 rsa.c \
+scrypt.c \
 seed.c \
 serpent.c \
 sha1.c \
diff --git a/cipher/kdf-internal.h b/cipher/kdf-internal.h
new file mode 100644
index 0000000..7079860
--- /dev/null
+++ b/cipher/kdf-internal.h
@@ -0,0 +1,40 @@
+/* kdf-internal.h  - Internal defs for kdf.c
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef GCRY_KDF_INTERNAL_H
+#define GCRY_KDF_INTERNAL_H
+
+/*-- kdf.c --*/
+gpg_err_code_t
+_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen,
+                 int hashalgo,
+                 const void *salt, size_t saltlen,
+                 unsigned long iterations,
+                 size_t keysize, void *keybuffer);
+
+/*-- scrypt.c --*/
+gcry_err_code_t
+_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen,
+                  int algo, int subalgo,
+                  const unsigned char *salt, size_t saltlen,
+                  unsigned long iterations,
+                  size_t dklen, unsigned char *dk);
+
+
+#endif /*GCRY_KDF_INTERNAL_H*/
diff --git a/cipher/kdf.c b/cipher/kdf.c
index 4ea0fb2..da63574 100644
--- a/cipher/kdf.c
+++ b/cipher/kdf.c
@@ -1,5 +1,6 @@
 /* kdf.c  - Key Derivation Functions
  * Copyright (C) 1998, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -26,7 +27,7 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "ath.h"
-#include "scrypt.h"
+#include "kdf-internal.h"
 
 
 /* Transform a passphrase into a suitable key of length KEYSIZE and
@@ -34,7 +35,7 @@
    must provide an HASHALGO, a valid ALGO and depending on that algo a
    SALT of 8 bytes and the number of ITERATIONS.  Code taken from
    gnupg/agent/protect.c:hash_passphrase.  */
-gpg_err_code_t
+static gpg_err_code_t
 openpgp_s2k (const void *passphrase, size_t passphraselen,
              int algo, int hashalgo,
              const void *salt, size_t saltlen,
@@ -117,11 +118,11 @@ openpgp_s2k (const void *passphrase, size_t passphraselen,
    used in HMAC mode.  SALT is a salt of length SALTLEN and ITERATIONS
    gives the number of iterations.  */
 gpg_err_code_t
-pkdf2 (const void *passphrase, size_t passphraselen,
-       int hashalgo,
-       const void *salt, size_t saltlen,
-       unsigned long iterations,
-       size_t keysize, void *keybuffer)
+_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen,
+                 int hashalgo,
+                 const void *salt, size_t saltlen,
+                 unsigned long iterations,
+                 size_t keysize, void *keybuffer)
 {
   gpg_err_code_t ec;
   gcry_md_hd_t md;
@@ -139,7 +140,10 @@ pkdf2 (const void *passphrase, size_t passphraselen,
   unsigned long iter;  /* Current iteration number.  */
   unsigned int i;
 
-  if (!salt || !saltlen || !iterations || !dklen)
+  /* NWe allow for a saltlen of 0 here to support scrypt.  It is not
+     clear whether rfc2898 allows for this this, thus we do a test on
+     saltlen > 0 only in gcry_kdf_derive.  */
+  if (!salt || !iterations || !dklen)
     return GPG_ERR_INV_VALUE;
 
   hlen = gcry_md_get_algo_dlen (hashalgo);
@@ -239,11 +243,12 @@ gcry_kdf_derive (const void *passphrase, size_t passphraselen,
 {
   gpg_err_code_t ec;
 
-  if (!passphrase || (!passphraselen && algo != GCRY_KDF_PBKDF2))
+  if (!passphrase)
     {
       ec = GPG_ERR_INV_DATA;
       goto leave;
     }
+
   if (!keybuffer || !keysize)
     {
       ec = GPG_ERR_INV_VALUE;
@@ -256,8 +261,11 @@ gcry_kdf_derive (const void *passphrase, size_t passphraselen,
     case GCRY_KDF_SIMPLE_S2K:
     case GCRY_KDF_SALTED_S2K:
     case GCRY_KDF_ITERSALTED_S2K:
-      ec = openpgp_s2k (passphrase, passphraselen, algo, subalgo,
-                        salt, saltlen, iterations, keysize, keybuffer);
+      if (!passphraselen)
+        ec = GPG_ERR_INV_DATA;
+      else
+        ec = openpgp_s2k (passphrase, passphraselen, algo, subalgo,
+                          salt, saltlen, iterations, keysize, keybuffer);
       break;
 
     case GCRY_KDF_PBKDF1:
@@ -265,12 +273,22 @@ gcry_kdf_derive (const void *passphrase, size_t passphraselen,
       break;
 
     case GCRY_KDF_PBKDF2:
-      ec = pkdf2 (passphrase, passphraselen, subalgo,
-                  salt, saltlen, iterations, keysize, keybuffer);
+      if (!saltlen)
+        ec = GPG_ERR_INV_VALUE;
+      else
+        ec = _gcry_kdf_pkdf2 (passphrase, passphraselen, subalgo,
+                              salt, saltlen, iterations, keysize, keybuffer);
       break;
+
+    case 41:
     case GCRY_KDF_SCRYPT:
-      ec = scrypt (passphrase, passphraselen, subalgo,
-                   salt, saltlen, iterations, keysize, keybuffer);
+#if USE_SCRYPT
+      ec = _gcry_kdf_scrypt (passphrase, passphraselen, algo, subalgo,
+                             salt, saltlen, iterations, keysize, keybuffer);
+#else
+      ec = GPG_ERR_UNSUPPORTED_ALGORITHM;
+#endif /*USE_SCRYPT*/
+      break;
 
     default:
       ec = GPG_ERR_UNKNOWN_ALGORITHM;
diff --git a/cipher/memxor.c b/cipher/memxor.c
deleted file mode 100644
index 74307f0..0000000
--- a/cipher/memxor.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/* memxor.c
- *
- *
- * This file is part of Libgcrypt.
- * Adapted from the nettle, low-level cryptographics library for
- * libgcrypt by Christian Grothoff; original license:
- */
-
-/*
- * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
- * Copyright (C) 2010 Niels Möller
- *
- * The nettle library 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.
- *
- * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02111-1301, USA.
- */
-
-/* Implementation inspired by memcmp in glibc, contributed to the FSF
-   by Torbjorn Granlund.
- */
-
-#include <config.h>
-#include <limits.h>
-#include <stdint.h>
-#include "memxor.h"
-
-typedef unsigned long int word_t;
-
-// FIXME: need configure test for this hack...
-#define SIZEOF_LONG 8
-
-#if SIZEOF_LONG & (SIZEOF_LONG - 1)
-#error Word size must be a power of two
-#endif
-
-#define ALIGN_OFFSET(p) ((uintptr_t) (p) % sizeof(word_t))
-
-#ifndef WORDS_BIGENDIAN
-#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
-#else
-#define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
-#endif
-
-#define WORD_T_THRESH 16
-
-/* XOR word-aligned areas. n is the number of words, not bytes. */
-static void
-memxor_common_alignment (word_t *dst, const word_t *src, size_t n)
-{
-  /* FIXME: Require n > 0? */
-  /* FIXME: Unroll four times, like memcmp? Probably not worth the
-     effort. */
-
-  if (n & 1)
-    {
-      *dst++ ^= *src++;
-      n--;
-    }
-  for (; n >= 2; dst += 2, src += 2, n -= 2)
-    {
-      dst[0] ^= src[0];
-      dst[1] ^= src[1];
-    }
-}
-
-/* XOR *un-aligned* src-area onto aligned dst area. n is number of
-   words, not bytes. Assumes we can read complete words at the start
-   and end of the src operand. */
-static void
-memxor_different_alignment (word_t *dst, const uint8_t *src, size_t n)
-{
-  size_t i;
-  int shl, shr;
-  const word_t *src_word;
-  unsigned offset = ALIGN_OFFSET (src);
-  word_t s0, s1;
-
-  shl = CHAR_BIT * offset;
-  shr = CHAR_BIT * (sizeof(word_t) - offset);
-
-  src_word = (const word_t *) ((uintptr_t) src & -SIZEOF_LONG);
-
-  /* FIXME: Unroll four times, like memcmp? */
-  i = n & 1;
-  s0 = src_word[i];
-  if (i)
-    {
-      s1 = src_word[0];
-      dst[0] ^= MERGE (s1, shl, s0, shr);
-    }
-
-  for (; i < n; i += 2)
-    {
-      s1 = src_word[i+1];
-      dst[i] ^= MERGE(s0, shl, s1, shr);
-      s0 = src_word[i+2];
-      dst[i+1] ^= MERGE(s1, shl, s0, shr);
-    }
-}
-
-/* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45
-   cycles/byte unaligned. */
-
-/* XOR LEN bytes starting at SRCADDR onto DESTADDR. Result undefined
-   if the source overlaps with the destination. Return DESTADDR. */
-uint8_t *
-memxor(uint8_t *dst, const uint8_t *src, size_t n)
-{
-  uint8_t *orig_dst = dst;
-
-  if (n >= WORD_T_THRESH)
-    {
-      /* There are at least some bytes to compare.  No need to test
-	 for N == 0 in this alignment loop.  */
-      while (ALIGN_OFFSET (dst))
-	{
-	  *dst++ ^= *src++;
-	  n--;
-	}
-      if (ALIGN_OFFSET (src))
-	memxor_different_alignment ((word_t *) dst, src, n / sizeof(word_t));
-      else
-	memxor_common_alignment ((word_t *) dst, (const word_t *) src, n / sizeof(word_t));
-
-      dst += n & -SIZEOF_LONG;
-      src += n & -SIZEOF_LONG;
-      n = n & (SIZEOF_LONG - 1);
-    }
-  for (; n > 0; n--)
-    *dst++ ^= *src++;
-
-  return orig_dst;
-}
-
-
-/* XOR word-aligned areas. n is the number of words, not bytes. */
-static void
-memxor3_common_alignment (word_t *dst,
-			  const word_t *a, const word_t *b, size_t n)
-{
-  /* FIXME: Require n > 0? */
-  while (n-- > 0)
-    dst[n] = a[n] ^ b[n];
-}
-
-static void
-memxor3_different_alignment_b (word_t *dst,
-			       const word_t *a, const uint8_t *b, unsigned offset, size_t n)
-{
-  int shl, shr;
-  const word_t *b_word;
-
-  word_t s0, s1;
-
-  shl = CHAR_BIT * offset;
-  shr = CHAR_BIT * (sizeof(word_t) - offset);
-
-  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
-
-  if (n & 1)
-    {
-      n--;
-      s1 = b_word[n];
-      s0 = b_word[n+1];
-      dst[n] = a[n] ^ MERGE (s1, shl, s0, shr);
-    }
-  else
-    s1 = b_word[n];
-
-  while (n > 0)
-    {
-      n -= 2;
-      s0 = b_word[n+1];
-      dst[n+1] = a[n+1] ^ MERGE(s0, shl, s1, shr);
-      s1 = b_word[n];
-      dst[n] = a[n] ^ MERGE(s1, shl, s0, shr);
-    }
-}
-
-static void
-memxor3_different_alignment_ab (word_t *dst,
-				const uint8_t *a, const uint8_t *b,
-				unsigned offset, size_t n)
-{
-  int shl, shr;
-  const word_t *a_word;
-  const word_t *b_word;
-
-  word_t s0, s1;
-
-  shl = CHAR_BIT * offset;
-  shr = CHAR_BIT * (sizeof(word_t) - offset);
-
-  a_word = (const word_t *) ((uintptr_t) a & -SIZEOF_LONG);
-  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
-
-  if (n & 1)
-    {
-      n--;
-      s1 = a_word[n] ^ b_word[n];
-      s0 = a_word[n+1] ^ b_word[n+1];
-      dst[n] = MERGE (s1, shl, s0, shr);
-    }
-  else
-    s1 = a_word[n] ^ b_word[n];
-
-  while (n > 0)
-    {
-      n -= 2;
-      s0 = a_word[n+1] ^ b_word[n+1];
-      dst[n+1] = MERGE(s0, shl, s1, shr);
-      s1 = a_word[n] ^ b_word[n];
-      dst[n] = MERGE(s1, shl, s0, shr);
-    }
-}
-
-static void
-memxor3_different_alignment_all (word_t *dst,
-				 const uint8_t *a, const uint8_t *b,
-				 unsigned a_offset, unsigned b_offset,
-				 size_t n)
-{
-  int al, ar, bl, br;
-  const word_t *a_word;
-  const word_t *b_word;
-
-  word_t a0, a1, b0, b1;
-
-  al = CHAR_BIT * a_offset;
-  ar = CHAR_BIT * (sizeof(word_t) - a_offset);
-  bl = CHAR_BIT * b_offset;
-  br = CHAR_BIT * (sizeof(word_t) - b_offset);
-
-  a_word = (const word_t *) ((uintptr_t) a & -SIZEOF_LONG);
-  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
-
-  if (n & 1)
-    {
-      n--;
-      a1 = a_word[n]; a0 = a_word[n+1];
-      b1 = b_word[n]; b0 = b_word[n+1];
-
-      dst[n] = MERGE (a1, al, a0, ar) ^ MERGE (b1, bl, b0, br);
-    }
-  else
-    {
-      a1 = a_word[n];
-      b1 = b_word[n];
-    }
-
-  while (n > 0)
-    {
-      n -= 2;
-      a0 = a_word[n+1]; b0 = b_word[n+1];
-      dst[n+1] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);
-      a1 = a_word[n]; b1 = b_word[n];
-      dst[n] = MERGE(a1, al, a0, ar) ^ MERGE(b1, bl, b0, br);
-    }
-}
-
-/* Current implementation processes data in descending order, to
-   support overlapping operation with one of the sources overlapping
-   the start of the destination area. This feature is used only
-   internally by cbc decrypt, and it is not advertised or documented
-   to nettle users. */
-uint8_t *
-memxor3(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t n)
-{
-  if (n >= WORD_T_THRESH)
-    {
-      unsigned i;
-      unsigned a_offset;
-      unsigned b_offset;
-      size_t nwords;
-
-      for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
-	{
-	  n--;
-	  dst[n] = a[n] ^ b[n];
-	}
-
-      a_offset = ALIGN_OFFSET(a + n);
-      b_offset = ALIGN_OFFSET(b + n);
-
-      nwords = n / sizeof (word_t);
-      n %= sizeof (word_t);
-
-      if (a_offset == b_offset)
-	{
-	  if (!a_offset)
-	    memxor3_common_alignment((word_t *) (dst + n),
-				     (const word_t *) (a + n),
-				     (const word_t *) (b + n), nwords);
-	  else
-	    memxor3_different_alignment_ab((word_t *) (dst + n),
-					   a + n, b + n, a_offset,
-					   nwords);
-	}
-      else if (!a_offset)
-	memxor3_different_alignment_b((word_t *) (dst + n),
-				      (const word_t *) (a + n), b + n,
-				      b_offset, nwords);
-      else if (!b_offset)
-	memxor3_different_alignment_b((word_t *) (dst + n),
-				      (const word_t *) (b + n), a + n,
-				      a_offset, nwords);
-      else
-	memxor3_different_alignment_all((word_t *) (dst + n), a + n, b + n,
-					a_offset, b_offset, nwords);
-    }
-  while (n-- > 0)
-    dst[n] = a[n] ^ b[n];
-
-  return dst;
-}
diff --git a/cipher/memxor.h b/cipher/memxor.h
deleted file mode 100644
index f308155..0000000
--- a/cipher/memxor.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* memxor.h
- *
- */
-
-#ifndef MEMXOR_H_INCLUDED
-#define MEMXOR_H_INCLUDED
-
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-uint8_t *memxor(uint8_t *dst, const uint8_t *src, size_t n);
-uint8_t *memxor3(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t n);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* MEMXOR_H_INCLUDED */
diff --git a/cipher/scrypt.c b/cipher/scrypt.c
index 45ab4b3..06196d6 100644
--- a/cipher/scrypt.c
+++ b/cipher/scrypt.c
@@ -1,6 +1,22 @@
 /* scrypt.c - Scrypt password-based key derivation function.
+ * Copyright (C) 2012 Simon Josefsson
+ * Copyright (C) 2013 Christian Grothoff
+ * Copyright (C) 2013 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/>.
  */
 
 /* Adapted from the nettle, low-level cryptographics library for
@@ -30,39 +46,40 @@
 #include <string.h>
 
 #include "g10lib.h"
-#include "scrypt.h"
-#include "memxor.h"
-
+#include "kdf-internal.h"
+#include "bufhelp.h"
 
+/* We really need a 64 bit type for this code.  */
+#ifdef HAVE_U64_TYPEDEF
 
-#define _SALSA20_INPUT_LENGTH 16
+#define SALSA20_INPUT_LENGTH 16
 
 #define ROTL32(n,x) (((x)<<(n)) | ((x)>>(32-(n))))
 
 
 /* Reads a 64-bit integer, in network, big-endian, byte order */
 #define READ_UINT64(p)                          \
-(  (((uint64_t) (p)[0]) << 56)                  \
- | (((uint64_t) (p)[1]) << 48)                  \
- | (((uint64_t) (p)[2]) << 40)                  \
- | (((uint64_t) (p)[3]) << 32)                  \
- | (((uint64_t) (p)[4]) << 24)                  \
- | (((uint64_t) (p)[5]) << 16)                  \
- | (((uint64_t) (p)[6]) << 8)                   \
- |  ((uint64_t) (p)[7]))
+(  (((u64) (p)[0]) << 56)                  \
+ | (((u64) (p)[1]) << 48)                  \
+ | (((u64) (p)[2]) << 40)                  \
+ | (((u64) (p)[3]) << 32)                  \
+ | (((u64) (p)[4]) << 24)                  \
+ | (((u64) (p)[5]) << 16)                  \
+ | (((u64) (p)[6]) << 8)                   \
+ |  ((u64) (p)[7]))
 
 
 
 /* And the other, little-endian, byteorder */
 #define LE_READ_UINT64(p)                       \
-(  (((uint64_t) (p)[7]) << 56)                  \
- | (((uint64_t) (p)[6]) << 48)                  \
- | (((uint64_t) (p)[5]) << 40)                  \
- | (((uint64_t) (p)[4]) << 32)                  \
- | (((uint64_t) (p)[3]) << 24)                  \
- | (((uint64_t) (p)[2]) << 16)                  \
- | (((uint64_t) (p)[1]) << 8)                   \
- |  ((uint64_t) (p)[0]))
+(  (((u64) (p)[7]) << 56)                  \
+ | (((u64) (p)[6]) << 48)                  \
+ | (((u64) (p)[5]) << 40)                  \
+ | (((u64) (p)[4]) << 32)                  \
+ | (((u64) (p)[3]) << 24)                  \
+ | (((u64) (p)[2]) << 16)                  \
+ | (((u64) (p)[1]) << 8)                   \
+ |  ((u64) (p)[0]))
 
 
 
@@ -83,9 +100,9 @@
 
 
 static void
-_salsa20_core(uint32_t *dst, const uint32_t *src, unsigned rounds)
+_salsa20_core(u32 *dst, const u32 *src, unsigned rounds)
 {
-  uint32_t x[_SALSA20_INPUT_LENGTH];
+  u32 x[SALSA20_INPUT_LENGTH];
   unsigned i;
 
   assert ( (rounds & 1) == 0);
@@ -104,33 +121,36 @@ _salsa20_core(uint32_t *dst, const uint32_t *src, unsigned rounds)
       QROUND(x[15], x[12], x[13], x[14]);
     }
 
-  for (i = 0; i < _SALSA20_INPUT_LENGTH; i++)
+  for (i = 0; i < SALSA20_INPUT_LENGTH; i++)
     {
-      uint32_t t = x[i] + src[i];
+      u32 t = x[i] + src[i];
       dst[i] = LE_SWAP32 (t);
     }
 }
 
 
 static void
-_scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
+_scryptBlockMix (u32 r, unsigned char *B, unsigned char *tmp2)
 {
-  uint64_t i;
-  uint8_t *X = tmp2;
-  uint8_t *Y = tmp2 + 64;
+  u64 i;
+  unsigned char *X = tmp2;
+  unsigned char *Y = tmp2 + 64;
 
 #if 0
-  for (i = 0; i < 2 * r; i++)
+  if (r == 1)
     {
-      size_t j;
-      printf ("B[%d]: ", i);
-      for (j = 0; j < 64; j++)
-	{
-	  if (j % 4 == 0)
-	    printf (" ");
-	  printf ("%02x", B[i * 64 + j]);
-	}
-      printf ("\n");
+      for (i = 0; i < 2 * r; i++)
+        {
+          size_t j;
+          printf ("B[%d] = ", (int)i);
+          for (j = 0; j < 64; j++)
+            {
+              if (j && !(j % 16))
+                printf ("\n       ");
+              printf (" %02x", B[i * 64 + j]);
+            }
+          putchar ('\n');
+        }
     }
 #endif
 
@@ -141,10 +161,10 @@ _scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
   for (i = 0; i <= 2 * r - 1; i++)
     {
       /* T = X xor B[i] */
-      memxor(X, &B[i * 64], 64);
+      buf_xor(X, X, &B[i * 64], 64);
 
       /* X = Salsa (T) */
-      _salsa20_core (X, X, 8);
+      _salsa20_core ((u32*)X, (u32*)X, 8);
 
       /* Y[i] = X */
       memcpy (&Y[i * 64], X, 64);
@@ -157,38 +177,43 @@ _scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
     }
 
 #if 0
-  for (i = 0; i < 2 * r; i++)
+  if (r==1)
     {
-      size_t j;
-      printf ("B'[%d]: ", i);
-      for (j = 0; j < 64; j++)
-	{
-	  if (j % 4 == 0)
-	    printf (" ");
-	  printf ("%02x", B[i * 64 + j]);
-	}
-      printf ("\n");
+      for (i = 0; i < 2 * r; i++)
+        {
+          size_t j;
+          printf ("B'[%d] =", (int)i);
+          for (j = 0; j < 64; j++)
+            {
+              if (j && !(j % 16))
+                printf ("\n       ");
+              printf (" %02x", B[i * 64 + j]);
+            }
+          putchar ('\n');
+        }
     }
 #endif
 }
 
 static void
-_scryptROMix (uint32_t r, uint8_t *B, uint64_t N,
-	      uint8_t *tmp1, uint8_t *tmp2)
+_scryptROMix (u32 r, unsigned char *B, u64 N,
+	      unsigned char *tmp1, unsigned char *tmp2)
 {
-  uint8_t *X = B, *T = B;
-  uint64_t i;
+  unsigned char *X = B, *T = B;
+  u64 i;
 
 #if 0
-  printf ("B: ");
-  for (i = 0; i < 128 * r; i++)
+  if (r == 1)
     {
-      size_t j;
-      if (i % 4 == 0)
-	printf (" ");
-      printf ("%02x", B[i]);
+      printf ("B = ");
+      for (i = 0; i < 128 * r; i++)
+        {
+          if (i && !(i % 16))
+            printf ("\n    ");
+          printf (" %02x", B[i]);
+        }
+      putchar ('\n');
     }
-  printf ("\n");
 #endif
 
   /* for i = 0 to N - 1 do */
@@ -204,81 +229,118 @@ _scryptROMix (uint32_t r, uint8_t *B, uint64_t N,
   /* for i = 0 to N - 1 do */
   for (i = 0; i <= N - 1; i++)
     {
-      uint64_t j;
+      u64 j;
 
       /* j = Integerify (X) mod N */
       j = LE_READ_UINT64 (&X[128 * r - 64]) % N;
 
       /* T = X xor V[j] */
-      memxor (T, &tmp1[j * 128 * r], 128 * r);
+      buf_xor (T, T, &tmp1[j * 128 * r], 128 * r);
 
       /* X = scryptBlockMix (T) */
       _scryptBlockMix (r, T, tmp2);
     }
 
 #if 0
-  printf ("B': ");
-  for (i = 0; i < 128 * r; i++)
+  if (r == 1)
     {
-      size_t j;
-      if (i % 4 == 0)
-	printf (" ");
-      printf ("%02x", B[i]);
+      printf ("B' =");
+      for (i = 0; i < 128 * r; i++)
+        {
+          if (i && !(i % 16))
+            printf ("\n    ");
+          printf (" %02x", B[i]);
+        }
+      putchar ('\n');
     }
-  printf ("\n");
 #endif
 }
 
 /**
  */
 gcry_err_code_t
-scrypt (const uint8_t * passwd, size_t passwdlen,
-	int subalgo,
-	const uint8_t * salt, size_t saltlen,
-	unsigned long iterations,
-	size_t dkLen, uint8_t * DK)
+_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen,
+                  int algo, int subalgo,
+                  const unsigned char *salt, size_t saltlen,
+                  unsigned long iterations,
+                  size_t dkLen, unsigned char *DK)
 {
-  /* XXX sanity-check parameters */
-  uint64_t N = subalgo; /* CPU/memory cost paramter */
-  uint32_t r = 8; /* block size, should be sane enough */
-  uint32_t p = iterations; /* parallelization parameter */
-
-  uint32_t i;
-  uint8_t *B;
-  uint8_t *tmp1;
-  uint8_t *tmp2;
-
+  u64 N = subalgo;    /* CPU/memory cost paramter.  */
+  u32 r;              /* Block size.  */
+  u32 p = iterations; /* Parallelization parameter.  */
+
+  gpg_err_code_t ec;
+  u32 i;
+  unsigned char *B = NULL;
+  unsigned char *tmp1 = NULL;
+  unsigned char *tmp2 = NULL;
+  size_t r128;
+  size_t nbytes;
+
+  if (subalgo < 1 || !iterations)
+    return GPG_ERR_INV_VALUE;
+
+  if (algo == GCRY_KDF_SCRYPT)
+    r = 8;
+  else if (algo == 41) /* Hack to allow the use of all test vectors.  */
+    r = 1;
+  else
+    return GPG_ERR_UNKNOWN_ALGORITHM;
+
+  r128 = r * 128;
+  if (r128 / 128 != r)
+    return GPG_ERR_ENOMEM;
 
-  B = malloc (p * 128 * r);
-  if (B == NULL)
+  nbytes = p * r128;
+  if (r128 && nbytes / r128 != p)
     return GPG_ERR_ENOMEM;
 
-  tmp1 = malloc (N * 128 * r);
-  if (tmp1 == NULL)
-  {
-    free (B);
+  nbytes = N * r128;
+  if (r128 && nbytes / r128 != N)
     return GPG_ERR_ENOMEM;
-  }
 
-  tmp2 = malloc (64 + 128 * r);
-  if (tmp2 == NULL)
-  {
-    free (B);
-    free (tmp1);
+  nbytes = 64 + r128;
+  if (nbytes < r128)
     return GPG_ERR_ENOMEM;
-  }
 
-  pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen, 1 /* iterations */, p * 128 * r, B);
+  B = gcry_malloc (p * r128);
+  if (!B)
+    {
+      ec = gpg_err_code_from_syserror ();
+      goto leave;
+    }
 
-  for (i = 0; i < p; i++)
-    _scryptROMix (r, &B[i * 128 * r], N, tmp1, tmp2);
+  tmp1 = gcry_malloc (N * r128);
+  if (!tmp1)
+    {
+      ec = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+
+  tmp2 = gcry_malloc (64 + r128);
+  if (!tmp2)
+    {
+      ec = gpg_err_code_from_syserror ();
+      goto leave;
+    }
 
-  for (i = 0; i < p; i++)
-    pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * 128 * r, 1 /* iterations */, dkLen, DK);
+  ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen,
+                        1 /* iterations */, p * r128, B);
 
-  free (tmp2);
-  free (tmp1);
-  free (B);
+  for (i = 0; !ec && i < p; i++)
+    _scryptROMix (r, &B[i * r128], N, tmp1, tmp2);
 
-  return 0;
+  for (i = 0; !ec && i < p; i++)
+    ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * r128,
+                          1 /* iterations */, dkLen, DK);
+
+ leave:
+  gcry_free (tmp2);
+  gcry_free (tmp1);
+  gcry_free (B);
+
+  return ec;
 }
+
+
+#endif /* HAVE_U64_TYPEDEF */
diff --git a/cipher/scrypt.h b/cipher/scrypt.h
deleted file mode 100644
index e0c8df9..0000000
--- a/cipher/scrypt.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* scrypt.h - Scrypt password-based key derivation function.
- *
- * This file is part of Libgcrypt.
- */
-
-/* Adapted from the nettle, low-level cryptographics library for
- * libgcrypt by Christian Grothoff; original license:
- *
- * Copyright (C) 2012 Simon Josefsson
- *
- * The nettle library 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.
- *
- * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02111-1301, USA.
- */
-
-#ifndef SCRYPT_H_INCLUDED
-#define SCRYPT_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stdint.h>
-#include "g10lib.h"
-#include "cipher.h"
-
-
-/* Transform a passphrase into a suitable key of length KEYSIZE and
-   store this key in the caller provided buffer KEYBUFFER.  The caller
-   must provide PRFALGO which indicates the pseudorandom function to
-   use: This shall be the algorithms id of a hash algorithm; it is
-   used in HMAC mode.  SALT is a salt of length SALTLEN and ITERATIONS
-   gives the number of iterations; implemented in 'kdf.c', used by
-   scrypt.c */
-gpg_err_code_t
-pkdf2 (const void *passphrase, size_t passphraselen,
-       int hashalgo,
-       const void *salt, size_t saltlen,
-       unsigned long iterations,
-       size_t keysize, void *keybuffer);
-
-
-gcry_err_code_t
-scrypt (const uint8_t * passwd, size_t passwdlen,
-	int subalgo,
-	const uint8_t * salt, size_t saltlen,
-	unsigned long iterations,
-	size_t dkLen, uint8_t * DK);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SCRYPT_H_INCLUDED */
diff --git a/configure.ac b/configure.ac
index cebf4b9..c597389 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,11 @@ available_digests="crc md4 md5 rmd160 sha1 sha256"
 available_digests_64="sha512 tiger whirlpool"
 enabled_digests=""
 
+# Definitions for kdfs (optional ones)
+available_kdfs="s2k pkdf2"
+available_kdfs_64="scrypt"
+enabled_kdfs=""
+
 # Definitions for random modules.
 available_random_modules="linux egd unix"
 auto_random_modules="$available_random_modules"
@@ -351,9 +356,11 @@ if test "$ac_cv_sizeof_unsigned_int" != "8" \
    && test "$ac_cv_sizeof_unsigned_long" != "8" \
    && test "$ac_cv_sizeof_unsigned_long_long" != "8" \
    && test "$ac_cv_sizeof_uint64_t" != "8"; then
-    AC_MSG_WARN([No 64-bit types.  Disabling TIGER/192, SHA-384, and SHA-512])
+    AC_MSG_WARN([No 64-bit types.  Disabling TIGER/192, SCRYPT, SHA-384, \
+ and SHA-512])
 else
   available_digests="$available_digests $available_digests_64"
+  available_kdfs="$available_kdfs $available_kdfs_64"
 fi
 
 # If not specified otherwise, all available algorithms will be
@@ -361,6 +368,7 @@ fi
 default_ciphers="$available_ciphers"
 default_pubkey_ciphers="$available_pubkey_ciphers"
 default_digests="$available_digests"
+default_kdfs="$available_kdfs"
 
 # Substitutions to set generated files in a Emacs buffer to read-only.
 AC_SUBST(emacs_local_vars_begin, ['Local Variables:'])
@@ -431,6 +439,26 @@ for digest in $enabled_digests; do
 done
 AC_MSG_RESULT([$enabled_digests])
 
+# Implementation of the --enable-kdfs switch.
+AC_ARG_ENABLE(kdfs,
+      AC_HELP_STRING([--enable-kfds=kdfs],
+		     [select the KDFs to include]),
+      [enabled_kdfs=`echo $enableval | tr ',:' '  ' | tr '[A-Z]' '[a-z]'`],
+      [enabled_kdfs=""])
+if test "x$enabled_kdfs" = "x" \
+   -o "$enabled_kdfs" = "yes"  \
+   -o "$enabled_kdfs" = "no"; then
+   enabled_kdfs=$default_kdfs
+fi
+AC_MSG_CHECKING([which key derivation functions to include])
+for kdf in $enabled_kdfs; do
+    LIST_MEMBER($kdf, $available_kdfs)
+    if test "$found" = "0"; then
+       AC_MSG_ERROR([unsupported key derivation function specified])
+    fi
+done
+AC_MSG_RESULT([$enabled_kdfs])
+
 # Implementation of the --enable-random switch.
 AC_ARG_ENABLE(random,
 	      AC_HELP_STRING([--enable-random=name],
@@ -1145,7 +1173,7 @@ fi
 
 
 # Define conditional sources and config.h symbols depending on the
-# selected ciphers, pubkey-ciphers, digests and random modules.
+# selected ciphers, pubkey-ciphers, digests, kdfs, and random modules.
 
 LIST_MEMBER(arcfour, $enabled_ciphers)
 if test "$found" = "1"; then
@@ -1291,6 +1319,12 @@ GCRYPT_DIGESTS="$GCRYPT_DIGESTS rmd160.lo sha1.lo"
 AC_DEFINE(USE_RMD160, 1, [Defined if this module should be included])
 AC_DEFINE(USE_SHA1, 1,   [Defined if this module should be included])
 
+LIST_MEMBER(scrypt, $enabled_kdfs)
+if test "$found" = "1" ; then
+   GCRYPT_KDFS="$GCRYPT_KDFS scrypt.lo"
+   AC_DEFINE(USE_SCRYPT, 1, [Defined if this module should be included])
+fi
+
 LIST_MEMBER(linux, $random_modules)
 if test "$found" = "1" ; then
    GCRYPT_RANDOM="$GCRYPT_RANDOM rndlinux.lo"
@@ -1327,6 +1361,7 @@ fi
 AC_SUBST([GCRYPT_CIPHERS])
 AC_SUBST([GCRYPT_PUBKEY_CIPHERS])
 AC_SUBST([GCRYPT_DIGESTS])
+AC_SUBST([GCRYPT_KDFS])
 AC_SUBST([GCRYPT_RANDOM])
 
 AC_SUBST(LIBGCRYPT_CIPHERS, $enabled_ciphers)
@@ -1344,6 +1379,9 @@ AC_DEFINE_UNQUOTED(LIBGCRYPT_PUBKEY_CIPHERS, "$tmp",
 tmp=`echo "$enabled_digests" | tr ' ' : `
 AC_DEFINE_UNQUOTED(LIBGCRYPT_DIGESTS, "$tmp",
                    [List of available digest algorithms])
+tmp=`echo "$enabled_kdfs" | tr ' ' : `
+AC_DEFINE_UNQUOTED(LIBGCRYPT_KDFS, "$tmp",
+                   [List of available KDF algorithms])
 
 
 #
@@ -1428,6 +1466,7 @@ GCRY_MSG_SHOW([Platform:                 ],[$PRINTABLE_OS_NAME ($host)])
 GCRY_MSG_SHOW([Hardware detection module:],[$detection_module])
 GCRY_MSG_WRAP([Enabled cipher algorithms:],[$enabled_ciphers])
 GCRY_MSG_WRAP([Enabled digest algorithms:],[$enabled_digests])
+GCRY_MSG_WRAP([Enabled kdf algorithms:   ],[$enabled_kdfs])
 GCRY_MSG_WRAP([Enabled pubkey algorithms:],[$enabled_pubkey_ciphers])
 GCRY_MSG_SHOW([Random number generator:  ],[$random])
 GCRY_MSG_SHOW([Using linux capabilities: ],[$use_capabilities])
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index fe040f0..8f277c2 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3174,7 +3174,7 @@ The PKCS#5 Passphrase Based Key Derivation Function number 2.
 
 @item GCRY_KDF_SCRYPT
 The SCRYPT Key Derivation Function.  The subalgorithm is used to specify
-the CPU/memory cost paramter N, and the number of iterations
+the CPU/memory cost parameter N, and the number of iterations
 is used for the parallelization parameter p.  The block size is fixed
 at 8 in the current implementation.
 
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index dff0e0b..3b37e19 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1194,7 +1194,7 @@ enum gcry_kdf_algos
     GCRY_KDF_ITERSALTED_S2K = 19,
     GCRY_KDF_PBKDF1 = 33,
     GCRY_KDF_PBKDF2 = 34,
-    GCRY_KDF_SCRYPT = 35
+    GCRY_KDF_SCRYPT = 48
   };
 
 /* Derive a key from a passphrase.  */
diff --git a/tests/t-kdf.c b/tests/t-kdf.c
index 06c0026..50deba0 100644
--- a/tests/t-kdf.c
+++ b/tests/t-kdf.c
@@ -35,6 +35,7 @@
 
 /* Program option flags.  */
 static int verbose;
+static int debug;
 static int error_count;
 
 static void
@@ -925,7 +926,7 @@ check_pbkdf2 (void)
       20,
       "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
       "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97"
-    },
+    }
   };
   int tvidx;
   gpg_error_t err;
@@ -957,11 +958,106 @@ check_pbkdf2 (void)
 }
 
 
+static void
+check_scrypt (void)
+{
+  /* Test vectors are from draft-josefsson-scrypt-kdf-01.  */
+  static struct {
+    const char *p;        /* Passphrase.  */
+    size_t plen;          /* Length of P. */
+    const char *salt;
+    size_t saltlen;
+    int parm_n;           /* CPU/memory cost.  */
+    int parm_r;           /* blocksize */
+    unsigned long parm_p; /* parallelization. */
+    int dklen;            /* Requested key length.  */
+    const char *dk;       /* Derived key.  */
+    int disabled;
+  } tv[] = {
+    {
+      "", 0,
+      "", 0,
+      16,
+      1,
+      1,
+      64,
+      "\x77\xd6\x57\x62\x38\x65\x7b\x20\x3b\x19\xca\x42\xc1\x8a\x04\x97"
+      "\xf1\x6b\x48\x44\xe3\x07\x4a\xe8\xdf\xdf\xfa\x3f\xed\xe2\x14\x42"
+      "\xfc\xd0\x06\x9d\xed\x09\x48\xf8\x32\x6a\x75\x3a\x0f\xc8\x1f\x17"
+      "\xe8\xd3\xe0\xfb\x2e\x0d\x36\x28\xcf\x35\xe2\x0c\x38\xd1\x89\x06"
+    },
+    {
+      "password", 8,
+      "NaCl", 4,
+      1024,
+      8,
+      16,
+      64,
+      "\xfd\xba\xbe\x1c\x9d\x34\x72\x00\x78\x56\xe7\x19\x0d\x01\xe9\xfe"
+      "\x7c\x6a\xd7\xcb\xc8\x23\x78\x30\xe7\x73\x76\x63\x4b\x37\x31\x62"
+      "\x2e\xaf\x30\xd9\x2e\x22\xa3\x88\x6f\xf1\x09\x27\x9d\x98\x30\xda"
+      "\xc7\x27\xaf\xb9\x4a\x83\xee\x6d\x83\x60\xcb\xdf\xa2\xcc\x06\x40"
+    },
+    {
+      "pleaseletmein", 13,
+      "SodiumChloride", 14,
+      16384,
+      8,
+      1,
+      64,
+      "\x70\x23\xbd\xcb\x3a\xfd\x73\x48\x46\x1c\x06\xcd\x81\xfd\x38\xeb"
+      "\xfd\xa8\xfb\xba\x90\x4f\x8e\x3e\xa9\xb5\x43\xf6\x54\x5d\xa1\xf2"
+      "\xd5\x43\x29\x55\x61\x3f\x0f\xcf\x62\xd4\x97\x05\x24\x2a\x9a\xf9"
+      "\xe6\x1e\x85\xdc\x0d\x65\x1e\x40\xdf\xcf\x01\x7b\x45\x57\x58\x87"
+    },
+    {
+      "pleaseletmein", 13,
+      "SodiumChloride", 14,
+      1048576,
+      8,
+      1,
+      64,
+      "\x21\x01\xcb\x9b\x6a\x51\x1a\xae\xad\xdb\xbe\x09\xcf\x70\xf8\x81"
+      "\xec\x56\x8d\x57\x4a\x2f\xfd\x4d\xab\xe5\xee\x98\x20\xad\xaa\x47"
+      "\x8e\x56\xfd\x8f\x4b\xa5\xd0\x9f\xfa\x1c\x6d\x92\x7c\x40\xf4\xc3"
+      "\x37\x30\x40\x49\xe8\xa9\x52\xfb\xcb\xf4\x5c\x6f\xa7\x7a\x41\xa4",
+      2 /* Only in debug mode.  */
+    }
+  };
+  int tvidx;
+  gpg_error_t err;
+  unsigned char outbuf[64];
+  int i;
+
+  for (tvidx=0; tvidx < DIM(tv); tvidx++)
+    {
+      if (tv[tvidx].disabled && !(tv[tvidx].disabled == 2 && debug))
+        continue;
+      if (verbose)
+        fprintf (stderr, "checking SCRYPT test vector %d\n", tvidx);
+      assert (tv[tvidx].dklen <= sizeof outbuf);
+      err = gcry_kdf_derive (tv[tvidx].p, tv[tvidx].plen,
+                             tv[tvidx].parm_r == 1 ? 41 : GCRY_KDF_SCRYPT,
+                             tv[tvidx].parm_n,
+                             tv[tvidx].salt, tv[tvidx].saltlen,
+                             tv[tvidx].parm_p, tv[tvidx].dklen, outbuf);
+      if (err)
+        fail ("scrypt test %d failed: %s\n", tvidx, gpg_strerror (err));
+      else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen))
+        {
+          fail ("scrypt test %d failed: mismatch\n", tvidx);
+          fputs ("got:", stderr);
+          for (i=0; i < tv[tvidx].dklen; i++)
+            fprintf (stderr, " %02x", outbuf[i]);
+          putc ('\n', stderr);
+        }
+    }
+}
+
+
 int
 main (int argc, char **argv)
 {
-  int debug = 0;
-
   if (argc > 1 && !strcmp (argv[1], "--verbose"))
     verbose = 1;
   else if (argc > 1 && !strcmp (argv[1], "--debug"))
@@ -977,6 +1073,7 @@ main (int argc, char **argv)
 
   check_openpgp ();
   check_pbkdf2 ();
+  check_scrypt ();
 
   return error_count ? 1 : 0;
 }

commit 855b1a8f81b5a3b5b31d0c3c303675425f58a5af
Author: Christian Grothoff <christian at grothoff.org>
Date:   Thu Apr 4 16:12:16 2013 +0200

    Add the SCRYPT KDF function
    
    * scrypt.c, scrypt.h: New files.
    * memxor.c, memxor.h: New files.
    * cipher/Makefile.am: Add new files.
    * cipher/kdf.c (gcry_kdf_derive): Support GCRY_KDF_SCRYPT.
    * src/gcrypt.h.in (GCRY_KDF_SCRYPT): New.
    --
    
    Signed-off-by: Christian Grothoff <christian at grothoff.org>
    
    I added the ChangeLog entry and the missing signed-off line.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index fcb9be5..5b016f0 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -39,7 +39,7 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES)
 libcipher_la_SOURCES = \
 cipher.c cipher-internal.h \
 cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \
-pubkey.c md.c kdf.c \
+pubkey.c md.c kdf.c scrypt.c memxor.c \
 hmac-tests.c \
 bithelp.h  \
 bufhelp.h  \
diff --git a/cipher/kdf.c b/cipher/kdf.c
index 46e8550..4ea0fb2 100644
--- a/cipher/kdf.c
+++ b/cipher/kdf.c
@@ -26,6 +26,7 @@
 #include "g10lib.h"
 #include "cipher.h"
 #include "ath.h"
+#include "scrypt.h"
 
 
 /* Transform a passphrase into a suitable key of length KEYSIZE and
@@ -267,6 +268,9 @@ gcry_kdf_derive (const void *passphrase, size_t passphraselen,
       ec = pkdf2 (passphrase, passphraselen, subalgo,
                   salt, saltlen, iterations, keysize, keybuffer);
       break;
+    case GCRY_KDF_SCRYPT:
+      ec = scrypt (passphrase, passphraselen, subalgo,
+                   salt, saltlen, iterations, keysize, keybuffer);
 
     default:
       ec = GPG_ERR_UNKNOWN_ALGORITHM;
diff --git a/cipher/memxor.c b/cipher/memxor.c
new file mode 100644
index 0000000..74307f0
--- /dev/null
+++ b/cipher/memxor.c
@@ -0,0 +1,326 @@
+/* memxor.c
+ *
+ *
+ * This file is part of Libgcrypt.
+ * Adapted from the nettle, low-level cryptographics library for
+ * libgcrypt by Christian Grothoff; original license:
+ */
+
+/*
+ * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+ * Copyright (C) 2010 Niels Möller
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+/* Implementation inspired by memcmp in glibc, contributed to the FSF
+   by Torbjorn Granlund.
+ */
+
+#include <config.h>
+#include <limits.h>
+#include <stdint.h>
+#include "memxor.h"
+
+typedef unsigned long int word_t;
+
+// FIXME: need configure test for this hack...
+#define SIZEOF_LONG 8
+
+#if SIZEOF_LONG & (SIZEOF_LONG - 1)
+#error Word size must be a power of two
+#endif
+
+#define ALIGN_OFFSET(p) ((uintptr_t) (p) % sizeof(word_t))
+
+#ifndef WORDS_BIGENDIAN
+#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
+#else
+#define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
+#endif
+
+#define WORD_T_THRESH 16
+
+/* XOR word-aligned areas. n is the number of words, not bytes. */
+static void
+memxor_common_alignment (word_t *dst, const word_t *src, size_t n)
+{
+  /* FIXME: Require n > 0? */
+  /* FIXME: Unroll four times, like memcmp? Probably not worth the
+     effort. */
+
+  if (n & 1)
+    {
+      *dst++ ^= *src++;
+      n--;
+    }
+  for (; n >= 2; dst += 2, src += 2, n -= 2)
+    {
+      dst[0] ^= src[0];
+      dst[1] ^= src[1];
+    }
+}
+
+/* XOR *un-aligned* src-area onto aligned dst area. n is number of
+   words, not bytes. Assumes we can read complete words at the start
+   and end of the src operand. */
+static void
+memxor_different_alignment (word_t *dst, const uint8_t *src, size_t n)
+{
+  size_t i;
+  int shl, shr;
+  const word_t *src_word;
+  unsigned offset = ALIGN_OFFSET (src);
+  word_t s0, s1;
+
+  shl = CHAR_BIT * offset;
+  shr = CHAR_BIT * (sizeof(word_t) - offset);
+
+  src_word = (const word_t *) ((uintptr_t) src & -SIZEOF_LONG);
+
+  /* FIXME: Unroll four times, like memcmp? */
+  i = n & 1;
+  s0 = src_word[i];
+  if (i)
+    {
+      s1 = src_word[0];
+      dst[0] ^= MERGE (s1, shl, s0, shr);
+    }
+
+  for (; i < n; i += 2)
+    {
+      s1 = src_word[i+1];
+      dst[i] ^= MERGE(s0, shl, s1, shr);
+      s0 = src_word[i+2];
+      dst[i+1] ^= MERGE(s1, shl, s0, shr);
+    }
+}
+
+/* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45
+   cycles/byte unaligned. */
+
+/* XOR LEN bytes starting at SRCADDR onto DESTADDR. Result undefined
+   if the source overlaps with the destination. Return DESTADDR. */
+uint8_t *
+memxor(uint8_t *dst, const uint8_t *src, size_t n)
+{
+  uint8_t *orig_dst = dst;
+
+  if (n >= WORD_T_THRESH)
+    {
+      /* There are at least some bytes to compare.  No need to test
+	 for N == 0 in this alignment loop.  */
+      while (ALIGN_OFFSET (dst))
+	{
+	  *dst++ ^= *src++;
+	  n--;
+	}
+      if (ALIGN_OFFSET (src))
+	memxor_different_alignment ((word_t *) dst, src, n / sizeof(word_t));
+      else
+	memxor_common_alignment ((word_t *) dst, (const word_t *) src, n / sizeof(word_t));
+
+      dst += n & -SIZEOF_LONG;
+      src += n & -SIZEOF_LONG;
+      n = n & (SIZEOF_LONG - 1);
+    }
+  for (; n > 0; n--)
+    *dst++ ^= *src++;
+
+  return orig_dst;
+}
+
+
+/* XOR word-aligned areas. n is the number of words, not bytes. */
+static void
+memxor3_common_alignment (word_t *dst,
+			  const word_t *a, const word_t *b, size_t n)
+{
+  /* FIXME: Require n > 0? */
+  while (n-- > 0)
+    dst[n] = a[n] ^ b[n];
+}
+
+static void
+memxor3_different_alignment_b (word_t *dst,
+			       const word_t *a, const uint8_t *b, unsigned offset, size_t n)
+{
+  int shl, shr;
+  const word_t *b_word;
+
+  word_t s0, s1;
+
+  shl = CHAR_BIT * offset;
+  shr = CHAR_BIT * (sizeof(word_t) - offset);
+
+  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
+
+  if (n & 1)
+    {
+      n--;
+      s1 = b_word[n];
+      s0 = b_word[n+1];
+      dst[n] = a[n] ^ MERGE (s1, shl, s0, shr);
+    }
+  else
+    s1 = b_word[n];
+
+  while (n > 0)
+    {
+      n -= 2;
+      s0 = b_word[n+1];
+      dst[n+1] = a[n+1] ^ MERGE(s0, shl, s1, shr);
+      s1 = b_word[n];
+      dst[n] = a[n] ^ MERGE(s1, shl, s0, shr);
+    }
+}
+
+static void
+memxor3_different_alignment_ab (word_t *dst,
+				const uint8_t *a, const uint8_t *b,
+				unsigned offset, size_t n)
+{
+  int shl, shr;
+  const word_t *a_word;
+  const word_t *b_word;
+
+  word_t s0, s1;
+
+  shl = CHAR_BIT * offset;
+  shr = CHAR_BIT * (sizeof(word_t) - offset);
+
+  a_word = (const word_t *) ((uintptr_t) a & -SIZEOF_LONG);
+  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
+
+  if (n & 1)
+    {
+      n--;
+      s1 = a_word[n] ^ b_word[n];
+      s0 = a_word[n+1] ^ b_word[n+1];
+      dst[n] = MERGE (s1, shl, s0, shr);
+    }
+  else
+    s1 = a_word[n] ^ b_word[n];
+
+  while (n > 0)
+    {
+      n -= 2;
+      s0 = a_word[n+1] ^ b_word[n+1];
+      dst[n+1] = MERGE(s0, shl, s1, shr);
+      s1 = a_word[n] ^ b_word[n];
+      dst[n] = MERGE(s1, shl, s0, shr);
+    }
+}
+
+static void
+memxor3_different_alignment_all (word_t *dst,
+				 const uint8_t *a, const uint8_t *b,
+				 unsigned a_offset, unsigned b_offset,
+				 size_t n)
+{
+  int al, ar, bl, br;
+  const word_t *a_word;
+  const word_t *b_word;
+
+  word_t a0, a1, b0, b1;
+
+  al = CHAR_BIT * a_offset;
+  ar = CHAR_BIT * (sizeof(word_t) - a_offset);
+  bl = CHAR_BIT * b_offset;
+  br = CHAR_BIT * (sizeof(word_t) - b_offset);
+
+  a_word = (const word_t *) ((uintptr_t) a & -SIZEOF_LONG);
+  b_word = (const word_t *) ((uintptr_t) b & -SIZEOF_LONG);
+
+  if (n & 1)
+    {
+      n--;
+      a1 = a_word[n]; a0 = a_word[n+1];
+      b1 = b_word[n]; b0 = b_word[n+1];
+
+      dst[n] = MERGE (a1, al, a0, ar) ^ MERGE (b1, bl, b0, br);
+    }
+  else
+    {
+      a1 = a_word[n];
+      b1 = b_word[n];
+    }
+
+  while (n > 0)
+    {
+      n -= 2;
+      a0 = a_word[n+1]; b0 = b_word[n+1];
+      dst[n+1] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);
+      a1 = a_word[n]; b1 = b_word[n];
+      dst[n] = MERGE(a1, al, a0, ar) ^ MERGE(b1, bl, b0, br);
+    }
+}
+
+/* Current implementation processes data in descending order, to
+   support overlapping operation with one of the sources overlapping
+   the start of the destination area. This feature is used only
+   internally by cbc decrypt, and it is not advertised or documented
+   to nettle users. */
+uint8_t *
+memxor3(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t n)
+{
+  if (n >= WORD_T_THRESH)
+    {
+      unsigned i;
+      unsigned a_offset;
+      unsigned b_offset;
+      size_t nwords;
+
+      for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
+	{
+	  n--;
+	  dst[n] = a[n] ^ b[n];
+	}
+
+      a_offset = ALIGN_OFFSET(a + n);
+      b_offset = ALIGN_OFFSET(b + n);
+
+      nwords = n / sizeof (word_t);
+      n %= sizeof (word_t);
+
+      if (a_offset == b_offset)
+	{
+	  if (!a_offset)
+	    memxor3_common_alignment((word_t *) (dst + n),
+				     (const word_t *) (a + n),
+				     (const word_t *) (b + n), nwords);
+	  else
+	    memxor3_different_alignment_ab((word_t *) (dst + n),
+					   a + n, b + n, a_offset,
+					   nwords);
+	}
+      else if (!a_offset)
+	memxor3_different_alignment_b((word_t *) (dst + n),
+				      (const word_t *) (a + n), b + n,
+				      b_offset, nwords);
+      else if (!b_offset)
+	memxor3_different_alignment_b((word_t *) (dst + n),
+				      (const word_t *) (b + n), a + n,
+				      a_offset, nwords);
+      else
+	memxor3_different_alignment_all((word_t *) (dst + n), a + n, b + n,
+					a_offset, b_offset, nwords);
+    }
+  while (n-- > 0)
+    dst[n] = a[n] ^ b[n];
+
+  return dst;
+}
diff --git a/cipher/memxor.h b/cipher/memxor.h
new file mode 100644
index 0000000..f308155
--- /dev/null
+++ b/cipher/memxor.h
@@ -0,0 +1,21 @@
+/* memxor.h
+ *
+ */
+
+#ifndef MEMXOR_H_INCLUDED
+#define MEMXOR_H_INCLUDED
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t *memxor(uint8_t *dst, const uint8_t *src, size_t n);
+uint8_t *memxor3(uint8_t *dst, const uint8_t *a, const uint8_t *b, size_t n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEMXOR_H_INCLUDED */
diff --git a/cipher/scrypt.c b/cipher/scrypt.c
new file mode 100644
index 0000000..45ab4b3
--- /dev/null
+++ b/cipher/scrypt.c
@@ -0,0 +1,284 @@
+/* scrypt.c - Scrypt password-based key derivation function.
+ *
+ * This file is part of Libgcrypt.
+ */
+
+/* Adapted from the nettle, low-level cryptographics library for
+ * libgcrypt by Christian Grothoff; original license:
+ *
+ * Copyright (C) 2012 Simon Josefsson
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "g10lib.h"
+#include "scrypt.h"
+#include "memxor.h"
+
+
+
+#define _SALSA20_INPUT_LENGTH 16
+
+#define ROTL32(n,x) (((x)<<(n)) | ((x)>>(32-(n))))
+
+
+/* Reads a 64-bit integer, in network, big-endian, byte order */
+#define READ_UINT64(p)                          \
+(  (((uint64_t) (p)[0]) << 56)                  \
+ | (((uint64_t) (p)[1]) << 48)                  \
+ | (((uint64_t) (p)[2]) << 40)                  \
+ | (((uint64_t) (p)[3]) << 32)                  \
+ | (((uint64_t) (p)[4]) << 24)                  \
+ | (((uint64_t) (p)[5]) << 16)                  \
+ | (((uint64_t) (p)[6]) << 8)                   \
+ |  ((uint64_t) (p)[7]))
+
+
+
+/* And the other, little-endian, byteorder */
+#define LE_READ_UINT64(p)                       \
+(  (((uint64_t) (p)[7]) << 56)                  \
+ | (((uint64_t) (p)[6]) << 48)                  \
+ | (((uint64_t) (p)[5]) << 40)                  \
+ | (((uint64_t) (p)[4]) << 32)                  \
+ | (((uint64_t) (p)[3]) << 24)                  \
+ | (((uint64_t) (p)[2]) << 16)                  \
+ | (((uint64_t) (p)[1]) << 8)                   \
+ |  ((uint64_t) (p)[0]))
+
+
+
+#ifdef WORDS_BIGENDIAN
+#define LE_SWAP32(v)				\
+  ((ROTL32(8,  v) & 0x00FF00FFUL) |		\
+   (ROTL32(24, v) & 0xFF00FF00UL))
+#else
+#define LE_SWAP32(v) (v)
+#endif
+
+#define QROUND(x0, x1, x2, x3) do { \
+  x1 ^= ROTL32(7, x0 + x3);	    \
+  x2 ^= ROTL32(9, x1 + x0);	    \
+  x3 ^= ROTL32(13, x2 + x1);	    \
+  x0 ^= ROTL32(18, x3 + x2);	    \
+  } while(0)
+
+
+static void
+_salsa20_core(uint32_t *dst, const uint32_t *src, unsigned rounds)
+{
+  uint32_t x[_SALSA20_INPUT_LENGTH];
+  unsigned i;
+
+  assert ( (rounds & 1) == 0);
+
+  memcpy (x, src, sizeof(x));
+  for (i = 0; i < rounds;i += 2)
+    {
+      QROUND(x[0], x[4], x[8], x[12]);
+      QROUND(x[5], x[9], x[13], x[1]);
+      QROUND(x[10], x[14], x[2], x[6]);
+      QROUND(x[15], x[3], x[7], x[11]);
+
+      QROUND(x[0], x[1], x[2], x[3]);
+      QROUND(x[5], x[6], x[7], x[4]);
+      QROUND(x[10], x[11], x[8], x[9]);
+      QROUND(x[15], x[12], x[13], x[14]);
+    }
+
+  for (i = 0; i < _SALSA20_INPUT_LENGTH; i++)
+    {
+      uint32_t t = x[i] + src[i];
+      dst[i] = LE_SWAP32 (t);
+    }
+}
+
+
+static void
+_scryptBlockMix (uint32_t r, uint8_t *B, uint8_t *tmp2)
+{
+  uint64_t i;
+  uint8_t *X = tmp2;
+  uint8_t *Y = tmp2 + 64;
+
+#if 0
+  for (i = 0; i < 2 * r; i++)
+    {
+      size_t j;
+      printf ("B[%d]: ", i);
+      for (j = 0; j < 64; j++)
+	{
+	  if (j % 4 == 0)
+	    printf (" ");
+	  printf ("%02x", B[i * 64 + j]);
+	}
+      printf ("\n");
+    }
+#endif
+
+  /* X = B[2 * r - 1] */
+  memcpy (X, &B[(2 * r - 1) * 64], 64);
+
+  /* for i = 0 to 2 * r - 1 do */
+  for (i = 0; i <= 2 * r - 1; i++)
+    {
+      /* T = X xor B[i] */
+      memxor(X, &B[i * 64], 64);
+
+      /* X = Salsa (T) */
+      _salsa20_core (X, X, 8);
+
+      /* Y[i] = X */
+      memcpy (&Y[i * 64], X, 64);
+    }
+
+  for (i = 0; i < r; i++)
+    {
+      memcpy (&B[i * 64], &Y[2 * i * 64], 64);
+      memcpy (&B[(r + i) * 64], &Y[(2 * i + 1) * 64], 64);
+    }
+
+#if 0
+  for (i = 0; i < 2 * r; i++)
+    {
+      size_t j;
+      printf ("B'[%d]: ", i);
+      for (j = 0; j < 64; j++)
+	{
+	  if (j % 4 == 0)
+	    printf (" ");
+	  printf ("%02x", B[i * 64 + j]);
+	}
+      printf ("\n");
+    }
+#endif
+}
+
+static void
+_scryptROMix (uint32_t r, uint8_t *B, uint64_t N,
+	      uint8_t *tmp1, uint8_t *tmp2)
+{
+  uint8_t *X = B, *T = B;
+  uint64_t i;
+
+#if 0
+  printf ("B: ");
+  for (i = 0; i < 128 * r; i++)
+    {
+      size_t j;
+      if (i % 4 == 0)
+	printf (" ");
+      printf ("%02x", B[i]);
+    }
+  printf ("\n");
+#endif
+
+  /* for i = 0 to N - 1 do */
+  for (i = 0; i <= N - 1; i++)
+    {
+      /* V[i] = X */
+      memcpy (&tmp1[i * 128 * r], X, 128 * r);
+
+      /* X =  ScryptBlockMix (X) */
+      _scryptBlockMix (r, X, tmp2);
+    }
+
+  /* for i = 0 to N - 1 do */
+  for (i = 0; i <= N - 1; i++)
+    {
+      uint64_t j;
+
+      /* j = Integerify (X) mod N */
+      j = LE_READ_UINT64 (&X[128 * r - 64]) % N;
+
+      /* T = X xor V[j] */
+      memxor (T, &tmp1[j * 128 * r], 128 * r);
+
+      /* X = scryptBlockMix (T) */
+      _scryptBlockMix (r, T, tmp2);
+    }
+
+#if 0
+  printf ("B': ");
+  for (i = 0; i < 128 * r; i++)
+    {
+      size_t j;
+      if (i % 4 == 0)
+	printf (" ");
+      printf ("%02x", B[i]);
+    }
+  printf ("\n");
+#endif
+}
+
+/**
+ */
+gcry_err_code_t
+scrypt (const uint8_t * passwd, size_t passwdlen,
+	int subalgo,
+	const uint8_t * salt, size_t saltlen,
+	unsigned long iterations,
+	size_t dkLen, uint8_t * DK)
+{
+  /* XXX sanity-check parameters */
+  uint64_t N = subalgo; /* CPU/memory cost paramter */
+  uint32_t r = 8; /* block size, should be sane enough */
+  uint32_t p = iterations; /* parallelization parameter */
+
+  uint32_t i;
+  uint8_t *B;
+  uint8_t *tmp1;
+  uint8_t *tmp2;
+
+
+  B = malloc (p * 128 * r);
+  if (B == NULL)
+    return GPG_ERR_ENOMEM;
+
+  tmp1 = malloc (N * 128 * r);
+  if (tmp1 == NULL)
+  {
+    free (B);
+    return GPG_ERR_ENOMEM;
+  }
+
+  tmp2 = malloc (64 + 128 * r);
+  if (tmp2 == NULL)
+  {
+    free (B);
+    free (tmp1);
+    return GPG_ERR_ENOMEM;
+  }
+
+  pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen, 1 /* iterations */, p * 128 * r, B);
+
+  for (i = 0; i < p; i++)
+    _scryptROMix (r, &B[i * 128 * r], N, tmp1, tmp2);
+
+  for (i = 0; i < p; i++)
+    pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * 128 * r, 1 /* iterations */, dkLen, DK);
+
+  free (tmp2);
+  free (tmp1);
+  free (B);
+
+  return 0;
+}
diff --git a/cipher/scrypt.h b/cipher/scrypt.h
new file mode 100644
index 0000000..e0c8df9
--- /dev/null
+++ b/cipher/scrypt.h
@@ -0,0 +1,66 @@
+/* scrypt.h - Scrypt password-based key derivation function.
+ *
+ * This file is part of Libgcrypt.
+ */
+
+/* Adapted from the nettle, low-level cryptographics library for
+ * libgcrypt by Christian Grothoff; original license:
+ *
+ * Copyright (C) 2012 Simon Josefsson
+ *
+ * The nettle library 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.
+ *
+ * The nettle library 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 the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#ifndef SCRYPT_H_INCLUDED
+#define SCRYPT_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+#include "g10lib.h"
+#include "cipher.h"
+
+
+/* Transform a passphrase into a suitable key of length KEYSIZE and
+   store this key in the caller provided buffer KEYBUFFER.  The caller
+   must provide PRFALGO which indicates the pseudorandom function to
+   use: This shall be the algorithms id of a hash algorithm; it is
+   used in HMAC mode.  SALT is a salt of length SALTLEN and ITERATIONS
+   gives the number of iterations; implemented in 'kdf.c', used by
+   scrypt.c */
+gpg_err_code_t
+pkdf2 (const void *passphrase, size_t passphraselen,
+       int hashalgo,
+       const void *salt, size_t saltlen,
+       unsigned long iterations,
+       size_t keysize, void *keybuffer);
+
+
+gcry_err_code_t
+scrypt (const uint8_t * passwd, size_t passwdlen,
+	int subalgo,
+	const uint8_t * salt, size_t saltlen,
+	unsigned long iterations,
+	size_t dkLen, uint8_t * DK);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCRYPT_H_INCLUDED */
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index bef91f7..fe040f0 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3172,6 +3172,12 @@ iteration count.
 @item GCRY_KDF_PBKDF2
 The PKCS#5 Passphrase Based Key Derivation Function number 2.
 
+ at item GCRY_KDF_SCRYPT
+The SCRYPT Key Derivation Function.  The subalgorithm is used to specify
+the CPU/memory cost paramter N, and the number of iterations
+is used for the parallelization parameter p.  The block size is fixed
+at 8 in the current implementation.
+
 @end table
 @end deftypefun
 
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 8343799..dff0e0b 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1193,7 +1193,8 @@ enum gcry_kdf_algos
     GCRY_KDF_SALTED_S2K = 17,
     GCRY_KDF_ITERSALTED_S2K = 19,
     GCRY_KDF_PBKDF1 = 33,
-    GCRY_KDF_PBKDF2 = 34
+    GCRY_KDF_PBKDF2 = 34,
+    GCRY_KDF_SCRYPT = 35
   };
 
 /* Derive a key from a passphrase.  */

commit 02e8344d3803b80b74bc9b56d718304a6588bc14
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Mar 26 21:21:41 2013 +0100

    Doc fix.
    
    --

diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index a6b585d..bef91f7 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -2359,7 +2359,8 @@ S-expression returned is:
 Where @var{r-mpi} and @var{s-mpi} are the result of the DSA sign
 operation.  For Elgamal signing (which is slow, yields large numbers
 and probably is not as secure as the other algorithms), the same format is
-used with "elg" replacing "dsa".
+used with "elg" replacing "dsa"; for ECDSA signing, the same format is used
+with "ecdsa" replacing "dsa".
 @end deftypefun
 @c end gcry_pk_sign
 

-----------------------------------------------------------------------

Summary of changes:
 NEWS                  |    3 +
 cipher/Makefile.am    |    7 +-
 cipher/kdf-internal.h |   40 ++++++
 cipher/kdf.c          |   46 +++++--
 cipher/scrypt.c       |  346 +++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac          |   43 ++++++-
 doc/gcrypt.texi       |    9 +-
 src/gcrypt.h.in       |    3 +-
 tests/t-kdf.c         |  103 ++++++++++++++-
 9 files changed, 579 insertions(+), 21 deletions(-)
 create mode 100644 cipher/kdf-internal.h
 create mode 100644 cipher/scrypt.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list