[git] GCRYPT - branch, master, updated. post-nuke-of-trailing-ws-19-g9730275

by Werner Koch cvs at cvs.gnupg.org
Wed Mar 9 18:14:52 CET 2011


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  9730275d294b4d9cbbb2453541f001c95f5f31a3 (commit)
      from  bf823c5acb713488771c9000242b36ab13649da4 (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 9730275d294b4d9cbbb2453541f001c95f5f31a3
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Mar 9 17:47:44 2011 +0100

    New function gcry_kdf_derive
    
    This allows us to factor the S2k code from gpg and gpg-agent out to
    libgcrypt.  Created a bunch of test vectors using a hacked gpg 1.4.
    
    The function also implements PBKDF2; tested against the RFC-6070 test
    vectors.

diff --git a/NEWS b/NEWS
index 979ad40..add5152 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 Noteworthy changes in version 1.5.x (unreleased)
 ------------------------------------------------
 
+ * New function gcry_kdf_derive implementing OpenPGP S2K algorithms
+   and PBKDF2.
+
  * Support for WindowsCE.
 
  * Support ECDH.
@@ -46,6 +49,7 @@ Noteworthy changes in version 1.5.x (unreleased)
  gcry_pk_get_curve          NEW.
  gcry_pk_get_param          NEW.
  GCRYCTL_DISABLE_HWF        NEW.
+ gcry_kdf_derive            NEW.
 
  * Interface changes relative to the 1.4.2 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 7e00da7..3fba314 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,7 @@
+2011-03-09  Werner Koch  <wk at g10code.com>
+
+	* kdf.c: New.
+
 2011-02-22  Werner Koch  <wk at g10code.com>
 
 	* rijndael.c (aesni_cleanup_2_4): New.
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index cdc6dfc..cbeace8 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -35,7 +35,7 @@ libcipher_la_DEPENDENCIES = $(GCRYPT_MODULES)
 libcipher_la_LIBADD = $(GCRYPT_MODULES)
 
 libcipher_la_SOURCES = \
-cipher.c pubkey.c ac.c md.c \
+cipher.c pubkey.c ac.c md.c kdf.c \
 hmac-tests.c \
 bithelp.h  \
 primegen.c  \
diff --git a/cipher/kdf.c b/cipher/kdf.c
new file mode 100644
index 0000000..d981022
--- /dev/null
+++ b/cipher/kdf.c
@@ -0,0 +1,278 @@
+/* kdf.c  - Key Derivation Functions
+ * Copyright (C) 1998, 2011 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "ath.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 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
+openpgp_s2k (const void *passphrase, size_t passphraselen,
+             int algo, 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;
+  char *key = keybuffer;
+  int pass, i;
+  int used = 0;
+  int secmode;
+
+  if ((algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K)
+      && (!salt || saltlen != 8))
+    return GPG_ERR_INV_VALUE;
+
+  secmode = gcry_is_secure (passphrase) || gcry_is_secure (keybuffer);
+
+  ec = gpg_err_code (gcry_md_open (&md, hashalgo,
+                                   secmode? GCRY_MD_FLAG_SECURE : 0));
+  if (ec)
+    return ec;
+
+  for (pass=0; used < keysize; pass++)
+    {
+      if (pass)
+        {
+          gcry_md_reset (md);
+          for (i=0; i < pass; i++) /* Preset the hash context.  */
+            gcry_md_putc (md, 0);
+	}
+
+      if (algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K)
+        {
+          int len2 = passphraselen + 8;
+          unsigned long count = len2;
+
+          if (algo == GCRY_KDF_ITERSALTED_S2K)
+            {
+              count = iterations;
+              if (count < len2)
+                count = len2;
+            }
+
+          while (count > len2)
+            {
+              gcry_md_write (md, salt, saltlen);
+              gcry_md_write (md, passphrase, passphraselen);
+              count -= len2;
+            }
+          if (count < saltlen)
+            gcry_md_write (md, salt, count);
+          else
+            {
+              gcry_md_write (md, salt, saltlen);
+              count -= saltlen;
+              gcry_md_write (md, passphrase, count);
+            }
+        }
+      else
+        gcry_md_write (md, passphrase, passphraselen);
+
+      gcry_md_final (md);
+      i = gcry_md_get_algo_dlen (hashalgo);
+      if (i > keysize - used)
+        i = keysize - used;
+      memcpy (key+used, gcry_md_read (md, hashalgo), i);
+      used += i;
+    }
+  gcry_md_close (md);
+  return 0;
+}
+
+
+/* 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.  */
+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)
+{
+  gpg_err_code_t ec;
+  gcry_md_hd_t md;
+  int secmode;
+  unsigned int dklen = keysize;
+  char *dk = keybuffer;
+  unsigned int hlen;   /* Output length of the digest function.  */
+  unsigned int l;      /* Rounded up number of blocks.  */
+  unsigned int r;      /* Number of octets in the last block.  */
+  char *sbuf;          /* Malloced buffer to concatenate salt and iter
+                          as well as space to hold TBUF and UBUF.  */
+  char *tbuf;          /* Buffer for T; ptr into SBUF, size is HLEN. */
+  char *ubuf;          /* Buffer for U; ptr into SBUF, size is HLEN. */
+  unsigned int lidx;   /* Current block number.  */
+  unsigned long iter;  /* Current iteration number.  */
+  unsigned int i;
+
+  if (!salt || !saltlen || !iterations || !dklen)
+    return GPG_ERR_INV_VALUE;
+
+  hlen = gcry_md_get_algo_dlen (hashalgo);
+  if (!hlen)
+    return GPG_ERR_DIGEST_ALGO;
+
+  secmode = gcry_is_secure (passphrase) || gcry_is_secure (keybuffer);
+
+  /* We ignore step 1 from pksc5v2.1 which demands a check that dklen
+     is not larger that 0xffffffff * hlen.  */
+
+  /* Step 2 */
+  l = ((dklen - 1)/ hlen) + 1;
+  r = dklen - (l - 1) * hlen;
+
+  /* Setup buffers and prepare a hash context.  */
+  sbuf = (secmode
+          ? gcry_malloc_secure (saltlen + 4 + hlen + hlen)
+          : gcry_malloc (saltlen + 4 + hlen + hlen));
+  if (!sbuf)
+    return gpg_err_code_from_syserror ();
+  tbuf = sbuf + saltlen + 4;
+  ubuf = tbuf + hlen;
+
+  ec = gpg_err_code (gcry_md_open (&md, hashalgo,
+                                   (GCRY_MD_FLAG_HMAC
+                                    | (secmode?GCRY_MD_FLAG_SECURE:0))));
+  if (ec)
+    {
+      gcry_free (sbuf);
+      return ec;
+    }
+
+  /* Step 3 and 4. */
+  memcpy (sbuf, salt, saltlen);
+  for (lidx = 1; lidx <= l; lidx++)
+    {
+      for (iter = 0; iter < iterations; iter++)
+        {
+          ec = gpg_err_code (gcry_md_setkey (md, passphrase, passphraselen));
+          if (ec)
+            {
+              gcry_md_close (md);
+              gcry_free (sbuf);
+              return ec;
+            }
+          if (!iter) /* Compute U_1:  */
+            {
+              sbuf[saltlen]     = (lidx >> 24);
+              sbuf[saltlen + 1] = (lidx >> 16);
+              sbuf[saltlen + 2] = (lidx >> 8);
+              sbuf[saltlen + 3] = lidx;
+              gcry_md_write (md, sbuf, saltlen + 4);
+              memcpy (ubuf, gcry_md_read (md, 0), hlen);
+              memcpy (tbuf, ubuf, hlen);
+            }
+          else /* Compute U_(2..c):  */
+            {
+              gcry_md_write (md, ubuf, hlen);
+              memcpy (ubuf, gcry_md_read (md, 0), hlen);
+              for (i=0; i < hlen; i++)
+                tbuf[i] ^= ubuf[i];
+            }
+        }
+      if (lidx == l)  /* Last block.  */
+        memcpy (dk, tbuf, r);
+      else
+        {
+          memcpy (dk, tbuf, hlen);
+          dk += hlen;
+        }
+    }
+
+  gcry_md_close (md);
+  gcry_free (sbuf);
+  return 0;
+}
+
+
+/* Derive a key from a passphrase.  KEYSIZE gives the requested size
+   of the keys in octets.  KEYBUFFER is a caller provided buffer
+   filled on success with the derived key.  The input passphrase is
+   taken from (PASSPHRASE,PASSPHRASELEN) which is an arbitrary memory
+   buffer.  ALGO specifies the KDF algorithm to use; these are the
+   constants GCRY_KDF_*.  SUBALGO specifies an algorithm used
+   internally by the KDF algorithms; this is usually a hash algorithm
+   but certain KDF algorithm may use it differently.  {SALT,SALTLEN}
+   is a salt as needed by most KDF algorithms.  ITERATIONS is a
+   positive integer parameter to most KDFs.  0 is returned on success,
+   or an error code on failure.  */
+gpg_error_t
+gcry_kdf_derive (const void *passphrase, size_t passphraselen,
+                 int algo, int subalgo,
+                 const void *salt, size_t saltlen,
+                 unsigned long iterations,
+                 size_t keysize, void *keybuffer)
+{
+  gpg_err_code_t ec;
+
+  if (!passphrase || !passphraselen)
+    {
+      ec = GPG_ERR_INV_DATA;
+      goto leave;
+    }
+  if (!keybuffer || !keysize)
+    {
+      ec = GPG_ERR_INV_VALUE;
+      goto leave;
+    }
+
+
+  switch (algo)
+    {
+    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);
+      break;
+
+    case GCRY_KDF_PBKDF1:
+      ec = GPG_ERR_UNSUPPORTED_ALGORITHM;
+      break;
+
+    case GCRY_KDF_PBKDF2:
+      ec = pkdf2 (passphrase, passphraselen, subalgo,
+                  salt, saltlen, iterations, keysize, keybuffer);
+      break;
+
+    default:
+      ec = GPG_ERR_UNKNOWN_ALGORITHM;
+      break;
+    }
+
+ leave:
+  return gpg_error (ec);
+}
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 3a0a5fc..e441263 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -12,7 +12,7 @@ This manual is for Libgcrypt
 (version @value{VERSION}, @value{UPDATED}),
 which is GNU's library of cryptographic building blocks.
 
-Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+Copyright @copyright{} 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -68,6 +68,7 @@ section entitled ``GNU General Public License''.
 * Symmetric cryptography::       How to use symmetric cryptography.
 * Public Key cryptography::      How to use public key cryptography.
 * Hashing::                      How to use hash and MAC algorithms.
+* Key Derivation::               How to derive keys from strings
 * Random Numbers::               How to work with random numbers.
 * S-expressions::                How to manage S-expressions.
 * MPI library::                  How to work with multi-precision-integers.
@@ -3930,6 +3931,65 @@ does implicitly stop debugging.
 @end deftypefun
 
 
+ at c *******************************************************
+ at c *******************  KDF  *****************************
+ at c *******************************************************
+ at node Key Derivation
+ at chapter Key Derivation
+
+ at acronym{Libgcypt} provides a general purpose function to derive keys
+from strings.
+
+ at deftypefun gpg_error_t gcry_kdf_derive ( @
+            @w{const void *@var{passphrase}}, @w{size_t @var{passphraselen}}, @
+            @w{int @var{algo}}, @w{int @var{subalgo}}, @
+            @w{const void *@var{salt}}, @w{size_t @var{saltlen}}, @
+            @w{unsigned long @var{iterations}}, @
+            @w{size_t @var{keysize}}, @w{void *@var{keybuffer}} )
+
+
+Derive a key from a passphrase.  @var{keysize} gives the requested
+size of the keys in octets.  @var{keybuffer} is a caller provided
+buffer filled on success with the derived key.  The input passphrase
+is taken from @var{passphrase} which is an arbitrary memory buffer of
+ at var{passphraselen} octets.  @var{algo} specifies the KDF algorithm to
+use; see below.  @var{subalgo} specifies an algorithm used internally
+by the KDF algorithms; this is usually a hash algorithm but certain
+KDF algorithms may use it differently.  @var{salt} is a salt of length
+ at var{saltlen} octets, as needed by most KDF algorithms.
+ at var{iterations} is a positive integer parameter to most KDFs.
+
+ at noindent
+On success 0 is returned; on failure an error code.
+
+ at noindent
+Currently supported KDFs (parameter @var{algo}):
+
+ at table @code
+ at item GCRY_KDF_SIMPLE_S2K
+The OpenPGP simple S2K algorithm (cf. RFC4880).  Its use is strongly
+deprecated.  @var{salt} and @var{iterations} are not needed and may be
+passed as @code{NULL}/@code{0}.
+
+ at item GCRY_KDF_SALTED_S2K
+The OpenPGP salted S2K algorithm (cf. RFC4880).  Usually not used.
+ at var{iterations} is not needed and may be passed as @code{0}.  @var{saltlen}
+must be given as 8.
+
+ at item GCRY_KDF_ITERSALTED_S2K
+The OpenPGP iterated+salted S2K algorithm (cf. RFC4880).  This is the
+default for most OpenPGP applications.  @var{saltlen} must be given as
+8.  Note that OpenPGP defines a special encoding of the
+ at var{iterations}; however this function takes the plain decoded
+iteration count.
+
+ at item GCRY_KDF_PBKDF2
+The PKCS#5 Passphrase Based Key Derivation Function number 2.
+
+ at end table
+ at end deftypefun
+
+
 @c **********************************************************
 @c *******************  Random  *****************************
 @c **********************************************************
diff --git a/src/ChangeLog b/src/ChangeLog
index 98f38db..9ef6c5d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2011-03-09  Werner Koch  <wk at g10code.com>
+
+	* gcrypt.h.in (gcry_kdf_algos): New.
+	(gcry_kdf_derive): New.
+	* visibility.c (gcry_kdf_derive): New.
+	* visibility.h, libgcrypt.vers, libgcrypt.def: Add gcry_kdf_derive.
+
 2011-02-23  Werner Koch  <wk at g10code.com>
 
 	* libgcrypt-config.in: Add option --host.
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 3cd8e7f..f67c19a 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1658,6 +1658,33 @@ gcry_error_t gcry_ac_name_to_id (const char *name,
 #endif /*GCRYPT_NO_DEPRECATED*/
 
 
+/******************************
+ *                            *
+ *  Key Derivation Functions  *
+ *                            *
+ ******************************/
+
+/* Algorithm IDs for the KDFs.  */
+enum gcry_kdf_algos
+  {
+    GCRY_KDF_NONE = 0,
+    GCRY_KDF_SIMPLE_S2K = 16,
+    GCRY_KDF_SALTED_S2K = 17,
+    GCRY_KDF_ITERSALTED_S2K = 19,
+    GCRY_KDF_PBKDF1 = 33,
+    GCRY_KDF_PBKDF2 = 34
+  };
+
+/* Derive a key from a passphrase.  */
+gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen,
+                             int algo, int subalgo,
+                             const void *salt, size_t saltlen,
+                             unsigned long iterations,
+                             size_t keysize, void *keybuffer);
+
+
+
+
 /************************************
  *                                  *
  *   Random Generating Functions    *
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index ac3d575..031b941 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -235,3 +235,5 @@ EXPORTS
 
       gcry_pk_get_curve     @192
       gcry_pk_get_param     @193
+
+      gcry_kdf_derive       @194
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index fbeb47b..5a617cc 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -75,6 +75,8 @@ GCRYPT_1.2 {
     gcry_ac_data_to_sexp; gcry_ac_data_from_sexp;
     gcry_ac_io_init; gcry_ac_io_init_va;
 
+    gcry_kdf_derive;
+
     gcry_prime_check; gcry_prime_generate;
     gcry_prime_group_generator; gcry_prime_release_factors;
 
diff --git a/src/visibility.c b/src/visibility.c
index 2d203f9..2fccb01 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1210,6 +1210,17 @@ gcry_ac_name_to_id (const char *name, gcry_ac_id_t *algorithm)
   return 0;
 }
 
+gpg_error_t
+gcry_kdf_derive (const void *passphrase, size_t passphraselen,
+                 int algo, int hashalgo,
+                 const void *salt, size_t saltlen,
+                 unsigned long iterations,
+                 size_t keysize, void *keybuffer)
+{
+  return _gcry_kdf_derive (passphrase, passphraselen, algo, hashalgo,
+                           salt, saltlen, iterations, keysize, keybuffer);
+}
+
 void
 gcry_randomize (void *buffer, size_t length, enum gcry_random_level level)
 {
diff --git a/src/visibility.h b/src/visibility.h
index ea00b89..3c1e8aa 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -153,6 +153,8 @@
 #define gcry_ac_io_init             _gcry_ac_io_init
 #define gcry_ac_io_init_va          _gcry_ac_io_init_va
 
+#define gcry_kdf_derive             _gcry_kdf_derive
+
 #define gcry_prime_check            _gcry_prime_check
 #define gcry_prime_generate         _gcry_prime_generate
 #define gcry_prime_group_generator  _gcry_prime_group_generator
@@ -501,6 +503,8 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
 #undef gcry_ac_io_init
 #undef gcry_ac_io_init_va
 
+#undef gcry_kdf_derive
+
 #undef gcry_prime_check
 #undef gcry_prime_generate
 #undef gcry_prime_group_generator
@@ -715,6 +719,8 @@ MARK_VISIBLE (gcry_ac_data_from_sexp)
 MARK_VISIBLE (gcry_ac_io_init)
 MARK_VISIBLE (gcry_ac_io_init_va)
 
+MARK_VISIBLE (gcry_kdf_derive)
+
 MARK_VISIBLE (gcry_prime_check)
 MARK_VISIBLE (gcry_prime_generate)
 MARK_VISIBLE (gcry_prime_group_generator)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bf26f68..c34bb96 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,7 +20,7 @@
 
 TESTS = version t-mpi-bit prime register ac ac-schemes ac-data basic \
         mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap \
-	curves
+	curves t-kdf
 
 
 # random.c uses fork() thus a test for W32 does not make any sense.
diff --git a/tests/t-kdf.c b/tests/t-kdf.c
new file mode 100644
index 0000000..7209525
--- /dev/null
+++ b/tests/t-kdf.c
@@ -0,0 +1,974 @@
+/* t-kdf.c -  KDF regression tests
+ * Copyright (C) 2011 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "../src/gcrypt.h"
+
+#ifndef DIM
+# define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#endif
+
+/* Program option flags.  */
+static int verbose;
+static int error_count;
+
+static void
+fail (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  exit (1);
+}
+
+
+static void
+check_openpgp (void)
+{
+  /* Test vectors manually created with gpg 1.4 derived code: In
+     passphrase.c:hash_passpharse, add this code to the end of the
+     function:
+
+       ===8<===
+       printf ("{\n"
+               "  \"");
+       for (i=0; i < pwlen; i++)
+         {
+           if (i && !(i%16))
+             printf ("\"\n  \"");
+           printf ("\\x%02x", ((const unsigned char *)pw)[i]);
+         }
+       printf ("\", %d,\n", pwlen);
+
+       printf ("  %s, %s,\n",
+               s2k->mode == 0? "GCRY_KDF_SIMPLE_S2K":
+               s2k->mode == 1? "GCRY_KDF_SALTED_S2K":
+               s2k->mode == 3? "GCRY_KDF_ITERSALTED_S2K":"?",
+               s2k->hash_algo == DIGEST_ALGO_MD5   ? "GCRY_MD_MD5" :
+               s2k->hash_algo == DIGEST_ALGO_SHA1  ? "GCRY_MD_SHA1" :
+               s2k->hash_algo == DIGEST_ALGO_RMD160? "GCRY_MD_RMD160" :
+               s2k->hash_algo == DIGEST_ALGO_SHA256? "GCRY_MD_SHA256" :
+               s2k->hash_algo == DIGEST_ALGO_SHA384? "GCRY_MD_SHA384" :
+               s2k->hash_algo == DIGEST_ALGO_SHA512? "GCRY_MD_SHA512" :
+               s2k->hash_algo == DIGEST_ALGO_SHA224? "GCRY_MD_SHA224" : "?");
+
+       if (s2k->mode == 0)
+         printf ("  NULL, 0,\n");
+       else
+         {
+           printf ("  \"");
+           for (i=0; i < 8; i++)
+             printf ("\\x%02x", (unsigned int)s2k->salt[i]);
+           printf ("\", %d,\n", 8);
+         }
+
+       if (s2k->mode == 3)
+         printf ("  %lu,\n", (unsigned long)S2K_DECODE_COUNT(s2k->count));
+       else
+         printf ("  0,\n");
+
+       printf ("  %d,\n", (int)dek->keylen);
+
+       printf ("  \"");
+       for (i=0; i < dek->keylen; i++)
+         {
+           if (i && !(i%16))
+             printf ("\"\n  \"");
+           printf ("\\x%02x", ((unsigned char *)dek->key)[i]);
+         }
+       printf ("\"\n},\n");
+       ===>8===
+
+     Then prepare a file x.inp with utf8 encoding:
+
+       ===8<===
+       0 aes    md5 1024 a
+       0 aes    md5 1024 ab
+       0 aes    md5 1024 abc
+       0 aes    md5 1024 abcd
+       0 aes    md5 1024 abcde
+       0 aes    md5 1024 abcdef
+       0 aes    md5 1024 abcdefg
+       0 aes    md5 1024 abcdefgh
+       0 aes    md5 1024 abcdefghi
+       0 aes    md5 1024 abcdefghijklmno
+       0 aes    md5 1024 abcdefghijklmnop
+       0 aes    md5 1024 abcdefghijklmnopq
+       0 aes    md5 1024 Long_sentence_used_as_passphrase
+       0 aes    md5 1024 With_utf8_umlauts:äüÖß
+       0 aes    sha1 1024 a
+       0 aes    sha1 1024 ab
+       0 aes    sha1 1024 abc
+       0 aes    sha1 1024 abcd
+       0 aes    sha1 1024 abcde
+       0 aes    sha1 1024 abcdef
+       0 aes    sha1 1024 abcdefg
+       0 aes    sha1 1024 abcdefgh
+       0 aes    sha1 1024 abcdefghi
+       0 aes    sha1 1024 abcdefghijklmno
+       0 aes    sha1 1024 abcdefghijklmnop
+       0 aes    sha1 1024 abcdefghijklmnopq
+       0 aes    sha1 1024 abcdefghijklmnopqr
+       0 aes    sha1 1024 abcdefghijklmnopqrs
+       0 aes    sha1 1024 abcdefghijklmnopqrst
+       0 aes    sha1 1024 abcdefghijklmnopqrstu
+       0 aes    sha1 1024 Long_sentence_used_as_passphrase
+       0 aes256 sha1 1024 Long_sentence_used_as_passphrase
+       0 aes    sha1 1024 With_utf8_umlauts:äüÖß
+       3 aes    sha1 1024 a
+       3 aes    sha1 1024 ab
+       3 aes    sha1 1024 abc
+       3 aes    sha1 1024 abcd
+       3 aes    sha1 1024 abcde
+       3 aes    sha1 1024 abcdef
+       3 aes    sha1 1024 abcdefg
+       3 aes    sha1 1024 abcdefgh
+       3 aes    sha1 1024 abcdefghi
+       3 aes    sha1 1024 abcdefghijklmno
+       3 aes    sha1 1024 abcdefghijklmnop
+       3 aes    sha1 1024 abcdefghijklmnopq
+       3 aes    sha1 1024 abcdefghijklmnopqr
+       3 aes    sha1 1024 abcdefghijklmnopqrs
+       3 aes    sha1 1024 abcdefghijklmnopqrst
+       3 aes    sha1 1024 abcdefghijklmnopqrstu
+       3 aes    sha1 1024 With_utf8_umlauts:äüÖß
+       3 aes    sha1 1024 Long_sentence_used_as_passphrase
+       3 aes    sha1 10240 Long_sentence_used_as_passphrase
+       3 aes    sha1 102400 Long_sentence_used_as_passphrase
+       3 aes192 sha1 1024 a
+       3 aes192 sha1 1024 abcdefg
+       3 aes192 sha1 1024 abcdefghi
+       3 aes192 sha1 1024 abcdefghi
+       3 aes192 sha1 1024 Long_sentence_used_as_passphrase
+       3 aes256 sha1 1024 a
+       3 aes256 sha1 1024 abcdefg
+       3 aes256 sha1 1024 abcdefghi
+       3 aes256 sha1 1024 abcdefghi
+       3 aes256 sha1 1024 Long_sentence_used_as_passphrase
+       0 aes    sha256 1024 Long_sentence_used_as_passphrase
+       1 aes    sha256 1024 Long_sentence_used_as_passphrase
+       3 aes    sha256 1024 Long_sentence_used_as_passphrase
+       3 aes    sha256 10240 Long_sentence_used_as_passphrase
+       3 aes    sha384 1024 Long_sentence_used_as_passphrase
+       3 aes    sha512 1024 Long_sentence_used_as_passphrase
+       3 aes256 sha512 1024 Long_sentence_used_as_passphrase
+       3 3des   sha512 1024 Long_sentence_used_as_passphrase
+       ===>8===
+
+    and finally using a proper utf-8 enabled shell, run:
+
+       cat x.inp | while read mode cipher digest count pass dummy; do \
+         ./gpg </dev/null -o /dev/null -c  --passphrase "$pass" \
+           --s2k-mode $mode --s2k-digest $digest --s2k-count $count \
+           --cipher-algo $cipher ; done >x.out
+  */
+  static struct {
+    const char *p;   /* Passphrase.  */
+    size_t plen;     /* Length of P. */
+    int algo;
+    int hashalgo;
+    const char *salt;
+    size_t saltlen;
+    unsigned long c; /* Iterations.  */
+    int dklen;       /* Requested key length.  */
+    const char *dk;  /* Derived key.  */
+    int disabled;
+  } tv[] = {
+    {
+      "\x61", 1,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8\x31\xc3\x99\xe2\x69\x77\x26\x61"
+    },
+    {
+      "\x61\x62", 2,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x18\x7e\xf4\x43\x61\x22\xd1\xcc\x2f\x40\xdc\x2b\x92\xf0\xeb\xa0"
+    },
+    {
+      "\x61\x62\x63", 3,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+    },
+    {
+      "\x61\x62\x63\x64", 4,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\xe2\xfc\x71\x4c\x47\x27\xee\x93\x95\xf3\x24\xcd\x2e\x7f\x33\x1f"
+    },
+    {
+      "\x61\x62\x63\x64\x65", 5,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\xab\x56\xb4\xd9\x2b\x40\x71\x3a\xcc\x5a\xf8\x99\x85\xd4\xb7\x86"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66", 6,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\xe8\x0b\x50\x17\x09\x89\x50\xfc\x58\xaa\xd8\x3c\x8c\x14\x97\x8e"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67", 7,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x7a\xc6\x6c\x0f\x14\x8d\xe9\x51\x9b\x8b\xd2\x64\x31\x2c\x4d\x64"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68", 8,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\xe8\xdc\x40\x81\xb1\x34\x34\xb4\x51\x89\xa7\x20\xb7\x7b\x68\x18"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x8a\xa9\x9b\x1f\x43\x9f\xf7\x12\x93\xe9\x53\x57\xba\xc6\xfd\x94"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f", 15,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x8a\x73\x19\xdb\xf6\x54\x4a\x74\x22\xc9\xe2\x54\x52\x58\x0e\xa5"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70", 16,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x1d\x64\xdc\xe2\x39\xc4\x43\x7b\x77\x36\x04\x1d\xb0\x89\xe1\xb9"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71", 17,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x9a\x8d\x98\x45\xa6\xb4\xd8\x2d\xfc\xb2\xc2\xe3\x51\x62\xc8\x30"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x35\x2a\xf0\xfc\xdf\xe9\xbb\x62\x16\xfc\x99\x9d\x8d\x58\x05\xcb"
+    },
+    {
+      "\x57\x69\x74\x68\x5f\x75\x74\x66\x38\x5f\x75\x6d\x6c\x61\x75\x74"
+      "\x73\x3a\xc3\xa4\xc3\xbc\xc3\x96\xc3\x9f", 26,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_MD5,
+      NULL, 0,
+      0,
+      16,
+      "\x21\xa4\xeb\xd8\xfd\xf0\x59\x25\xd1\x32\x31\xdb\xe7\xf2\x13\x5d"
+    },
+    {
+      "\x61", 1,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x86\xf7\xe4\x37\xfa\xa5\xa7\xfc\xe1\x5d\x1d\xdc\xb9\xea\xea\xea"
+    },
+    {
+      "\x61\x62", 2,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xda\x23\x61\x4e\x02\x46\x9a\x0d\x7c\x7b\xd1\xbd\xab\x5c\x9c\x47"
+    },
+    {
+      "\x61\x62\x63", 3,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e\x25\x71\x78\x50\xc2\x6c"
+    },
+    {
+      "\x61\x62\x63\x64", 4,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x81\xfe\x8b\xfe\x87\x57\x6c\x3e\xcb\x22\x42\x6f\x8e\x57\x84\x73"
+    },
+    {
+      "\x61\x62\x63\x64\x65", 5,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x03\xde\x6c\x57\x0b\xfe\x24\xbf\xc3\x28\xcc\xd7\xca\x46\xb7\x6e"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66", 6,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x1f\x8a\xc1\x0f\x23\xc5\xb5\xbc\x11\x67\xbd\xa8\x4b\x83\x3e\x5c"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67", 7,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x2f\xb5\xe1\x34\x19\xfc\x89\x24\x68\x65\xe7\xa3\x24\xf4\x76\xec"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68", 8,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x42\x5a\xf1\x2a\x07\x43\x50\x2b\x32\x2e\x93\xa0\x15\xbc\xf8\x68"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xc6\x3b\x19\xf1\xe4\xc8\xb5\xf7\x6b\x25\xc4\x9b\x8b\x87\xf5\x7d"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f", 15,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x29\x38\xdc\xc2\xe3\xaa\x77\x98\x7c\x7e\x5d\x4a\x0f\x26\x96\x67"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70", 16,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x14\xf3\x99\x52\x88\xac\xd1\x89\xe6\xe5\x0a\x7a\xf4\x7e\xe7\x09"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71", 17,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xd8\x3d\x62\x1f\xcd\x2d\x4d\x29\x85\x54\x70\x43\xa7\xa5\xfd\x4d"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72", 18,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xe3\x81\xfe\x42\xc5\x7e\x48\xa0\x82\x17\x86\x41\xef\xfd\x1c\xb9"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73", 19,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x89\x3e\x69\xff\x01\x09\xf3\x45\x9c\x42\x43\x01\x3b\x3d\xe8\xb1"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73\x74", 20,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x14\xa2\x3a\xd7\x0f\x2a\x5d\xd7\x25\x57\x5d\xe6\xc4\x3e\x1c\xdd"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73\x74\x75", 21,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xec\xa9\x86\xb9\x5d\x58\x7f\x34\xd7\x1c\xa7\x75\x2a\x4e\x00\x10"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\x3e\x1b\x9a\x50\x7d\x6e\x9a\xd8\x93\x64\x96\x7a\x3f\xcb\x27\x3f"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      32,
+      "\x3e\x1b\x9a\x50\x7d\x6e\x9a\xd8\x93\x64\x96\x7a\x3f\xcb\x27\x3f"
+      "\xc3\x7b\x3a\xb2\xef\x4d\x68\xaa\x9c\xd7\xe4\x88\xee\xd1\x5e\x70"
+    },
+    {
+      "\x57\x69\x74\x68\x5f\x75\x74\x66\x38\x5f\x75\x6d\x6c\x61\x75\x74"
+      "\x73\x3a\xc3\xa4\xc3\xbc\xc3\x96\xc3\x9f", 26,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA1,
+      NULL, 0,
+      0,
+      16,
+      "\xe0\x4e\x1e\xe3\xad\x0b\x49\x7c\x7a\x5f\x37\x3b\x4d\x90\x3c\x2e"
+    },
+    {
+      "\x61", 1,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x6d\x47\xe3\x68\x5d\x2c\x36\x16", 8,
+      1024,
+      16,
+      "\x41\x9f\x48\x6e\xbf\xe6\xdd\x05\x9a\x72\x23\x17\x44\xd8\xd3\xf3"
+    },
+    {
+      "\x61\x62", 2,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x7c\x34\x78\xfb\x28\x2d\x25\xc7", 8,
+      1024,
+      16,
+      "\x0a\x9d\x09\x06\x43\x3d\x4f\xf9\x87\xd6\xf7\x48\x90\xde\xd1\x1c"
+    },
+    {
+      "\x61\x62\x63", 3,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xc3\x16\x37\x2e\x27\xf6\x9f\x6f", 8,
+      1024,
+      16,
+      "\xf8\x27\xa0\x07\xc6\xcb\xdd\xf1\xfe\x5c\x88\x3a\xfc\xcd\x84\x4d"
+    },
+    {
+      "\x61\x62\x63\x64", 4,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xf0\x0c\x73\x38\xb7\xc3\xd5\x14", 8,
+      1024,
+      16,
+      "\x9b\x5f\x26\xba\x52\x3b\xcd\xd9\xa5\x2a\xef\x3c\x03\x4d\xd1\x52"
+    },
+    {
+      "\x61\x62\x63\x64\x65", 5,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xe1\x7d\xa2\x36\x09\x59\xee\xc5", 8,
+      1024,
+      16,
+      "\x94\x9d\x5b\x1a\x5a\x66\x8c\xfa\x8f\x6f\x22\xaf\x8b\x60\x9f\xaf"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66", 6,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xaf\xa7\x0c\x68\xdf\x7e\xaa\x27", 8,
+      1024,
+      16,
+      "\xe5\x38\xf4\x39\x62\x27\xcd\xcc\x91\x37\x7f\x1b\xdc\x58\x64\x27"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67", 7,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x40\x57\xb2\x9d\x5f\xbb\x11\x4f", 8,
+      1024,
+      16,
+      "\xad\xa2\x33\xd9\xdd\xe0\xfb\x94\x8e\xcc\xec\xcc\xb3\xa8\x3a\x9e"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68", 8,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x38\xf5\x65\xc5\x0f\x8c\x19\x61", 8,
+      1024,
+      16,
+      "\xa0\xb0\x3e\x29\x76\xe6\x8f\xa0\xd8\x34\x8f\xa4\x2d\xfd\x65\xee"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xc3\xb7\x99\xcc\xda\x2d\x05\x7b", 8,
+      1024,
+      16,
+      "\x27\x21\xc8\x99\x5f\xcf\x20\xeb\xf2\xd9\xff\x6a\x69\xff\xad\xe8"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f", 15,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x7d\xd8\x68\x8a\x1c\xc5\x47\x22", 8,
+      1024,
+      16,
+      "\x0f\x96\x7a\x12\x23\x54\xf6\x92\x61\x67\x07\xb4\x68\x17\xb8\xaa"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70", 16,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x8a\x95\xd4\x88\x0b\xb8\xe9\x9d", 8,
+      1024,
+      16,
+      "\xcc\xe4\xc8\x82\x53\x32\xf1\x93\x5a\x00\xd4\x7f\xd4\x46\xfa\x07"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71", 17,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xb5\x22\x48\xa6\xc4\xad\x74\x67", 8,
+      1024,
+      16,
+      "\x0c\xe3\xe0\xee\x3d\x8f\x35\xd2\x35\x14\x14\x29\x0c\xf1\xe3\x34"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72", 18,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xac\x9f\x04\x63\x83\x0e\x3c\x95", 8,
+      1024,
+      16,
+      "\x49\x0a\x04\x68\xa8\x2a\x43\x6f\xb9\x73\x94\xb4\x85\x9a\xaa\x0e"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73", 19,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x03\x6f\x60\x30\x3a\x19\x61\x0d", 8,
+      1024,
+      16,
+      "\x15\xe5\x9b\xbf\x1c\xf0\xbe\x74\x95\x1a\xb2\xc4\xda\x09\xcd\x99"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73\x74", 20,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x51\x40\xa5\x57\xf5\x28\xfd\x03", 8,
+      1024,
+      16,
+      "\xa6\xf2\x7e\x6b\x30\x4d\x8d\x67\xd4\xa2\x7f\xa2\x57\x27\xab\x96"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+      "\x71\x72\x73\x74\x75", 21,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x4c\xf1\x10\x11\x04\x70\xd3\x6e", 8,
+      1024,
+      16,
+      "\x2c\x50\x79\x8d\x83\x23\xac\xd6\x22\x29\x37\xaf\x15\x0d\xdd\x8f"
+    },
+    {
+      "\x57\x69\x74\x68\x5f\x75\x74\x66\x38\x5f\x75\x6d\x6c\x61\x75\x74"
+      "\x73\x3a\xc3\xa4\xc3\xbc\xc3\x96\xc3\x9f", 26,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xfe\x3a\x25\xcb\x78\xef\xe1\x21", 8,
+      1024,
+      16,
+      "\x2a\xb0\x53\x08\xf3\x2f\xd4\x6e\xeb\x01\x49\x5d\x87\xf6\x27\xf6"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x04\x97\xd0\x02\x6a\x44\x2d\xde", 8,
+      1024,
+      16,
+      "\x57\xf5\x70\x41\xa0\x9b\x8c\x09\xca\x74\xa9\x22\xa5\x82\x2d\x17"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xdd\xf3\x31\x7c\xce\xf4\x81\x26", 8,
+      10240,
+      16,
+      "\xc3\xdd\x01\x6d\xaf\xf6\x58\xc8\xd7\x79\xb4\x40\x00\xb5\xe8\x0b"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x95\xd6\x72\x4e\xfb\xe1\xc3\x1a", 8,
+      102400,
+      16,
+      "\xf2\x3f\x36\x7f\xb4\x6a\xd0\x3a\x31\x9e\x65\x11\x8e\x2b\x99\x9b"
+    },
+    {
+      "\x61", 1,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x6d\x69\x15\x18\xe4\x13\x42\x82", 8,
+      1024,
+      24,
+      "\x28\x0c\x7e\xf2\x31\xf6\x1c\x6b\x5c\xef\x6a\xd5\x22\x64\x97\x91"
+      "\xe3\x5e\x37\xfd\x50\xe2\xfc\x6c"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67", 7,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x9b\x76\x5e\x81\xde\x13\xdf\x15", 8,
+      1024,
+      24,
+      "\x91\x1b\xa1\xc1\x7b\x4f\xc3\xb1\x80\x61\x26\x08\xbe\x53\xe6\x50"
+      "\x40\x6f\x28\xed\xc6\xe6\x67\x55"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x7a\xac\xcc\x6e\x15\x56\xbd\xa1", 8,
+      1024,
+      24,
+      "\xfa\x7e\x20\x07\xb6\x47\xb0\x09\x46\xb8\x38\xfb\xa1\xaf\xf7\x75"
+      "\x2a\xfa\x77\x14\x06\x54\xcb\x34"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x1c\x68\xf8\xfb\x98\xf7\x8c\x39", 8,
+      1024,
+      24,
+      "\xcb\x1e\x86\xf5\xe0\xe4\xfb\xbf\x71\x34\x99\x24\xf4\x39\x8c\xc2"
+      "\x8e\x25\x1c\x4c\x96\x47\x22\xe8"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x10\xa9\x4e\xc1\xa5\xec\x17\x52", 8,
+      1024,
+      24,
+      "\x0f\x83\xa2\x77\x92\xbb\xe4\x58\x68\xc5\xf2\x14\x6e\x6e\x2e\x6b"
+      "\x98\x17\x70\x92\x07\x44\xe0\x51"
+    },
+    {
+      "\x61", 1,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xef\x8f\x37\x61\x8f\xab\xae\x4f", 8,
+      1024,
+      32,
+      "\x6d\x65\xae\x86\x23\x91\x39\x98\xec\x1c\x23\x44\xb6\x0d\xad\x32"
+      "\x54\x46\xc7\x23\x26\xbb\xdf\x4b\x54\x6e\xd4\xc2\xfa\xc6\x17\x17"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67", 7,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xaa\xfb\xd9\x06\x7d\x7c\x40\xaf", 8,
+      1024,
+      32,
+      "\x7d\x10\x54\x13\x3c\x43\x7a\xb3\x54\x1f\x38\xd4\x8f\x70\x0a\x09"
+      "\xe2\xfa\xab\x97\x9a\x70\x16\xef\x66\x68\xca\x34\x2e\xce\xfa\x1f"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x58\x03\x4f\x56\x8b\x97\xd4\x98", 8,
+      1024,
+      32,
+      "\xf7\x40\xb1\x25\x86\x0d\x35\x8f\x9f\x91\x2d\xce\x04\xee\x5a\x04"
+      "\x9d\xbd\x44\x23\x4c\xa6\xbb\xab\xb0\xd0\x56\x82\xa9\xda\x47\x16"
+    },
+    {
+      "\x61\x62\x63\x64\x65\x66\x67\x68\x69", 9,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\x5d\x41\x3d\xa3\xa7\xfc\x5d\x0c", 8,
+      1024,
+      32,
+      "\x4c\x7a\x86\xed\x81\x8a\x94\x99\x7d\x4a\xc4\xf7\x1c\xf8\x08\xdb"
+      "\x09\x35\xd9\xa3\x2d\x22\xde\x32\x2d\x74\x38\xe5\xc8\xf2\x50\x6e"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
+      "\xca\xa7\xdc\x59\xce\x31\xe7\x49", 8,
+      1024,
+      32,
+      "\x67\xe9\xd6\x29\x49\x1c\xb6\xa0\x85\xe8\xf9\x8b\x85\x47\x3a\x7e"
+      "\xa7\xee\x89\x52\x6f\x19\x00\x53\x93\x07\x0a\x8b\xb9\xa8\x86\x94"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_SIMPLE_S2K, GCRY_MD_SHA256,
+      NULL, 0,
+      0,
+      16,
+      "\x88\x36\x78\x6b\xd9\x5a\x62\xff\x47\xd3\xfb\x79\xc9\x08\x70\x56"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_SALTED_S2K, GCRY_MD_SHA256,
+      "\x05\x8b\xfe\x31\xaa\xf3\x29\x11", 8,
+      0,
+      16,
+      "\xb2\x42\xfe\x5e\x09\x02\xd9\x62\xb9\x35\xf3\xa8\x43\x80\x9f\xb1"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA256,
+      "\xd3\x4a\xea\xc9\x97\x1b\xcc\x83", 8,
+      1024,
+      16,
+      "\x35\x37\x99\x62\x07\x26\x68\x23\x05\x47\xb2\xa0\x0b\x2b\x2b\x8d"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA256,
+      "\x5e\x71\xbd\x00\x5f\x96\xc4\x23", 8,
+      10240,
+      16,
+      "\xa1\x6a\xee\xba\xde\x73\x25\x25\xd1\xab\xa0\xc5\x7e\xc6\x39\xa7"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA384,
+      "\xc3\x08\xeb\x17\x62\x08\x89\xef", 8,
+      1024,
+      16,
+      "\x9b\x7f\x0c\x81\x6f\x71\x59\x9b\xd5\xf6\xbf\x3a\x86\x20\x16\x33"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA512,
+      "\xe6\x7d\x13\x6b\x39\xe3\x44\x05", 8,
+      1024,
+      16,
+      "\xc8\xcd\x4b\xa4\xf3\xf1\xd5\xb0\x59\x06\xf0\xbb\x89\x34\x6a\xad"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA512,
+      "\xed\x7d\x30\x47\xe4\xc3\xf8\xb6", 8,
+      1024,
+      32,
+      "\x89\x7a\xef\x70\x97\xe7\x10\xdb\x75\xcc\x20\x22\xab\x7b\xf3\x05"
+      "\x4b\xb6\x2e\x17\x11\x9f\xd6\xeb\xbf\xdf\x4d\x70\x59\xf0\xf9\xe5"
+    },
+    {
+      "\x4c\x6f\x6e\x67\x5f\x73\x65\x6e\x74\x65\x6e\x63\x65\x5f\x75\x73"
+      "\x65\x64\x5f\x61\x73\x5f\x70\x61\x73\x73\x70\x68\x72\x61\x73\x65", 32,
+      GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA512,
+      "\xbb\x1a\x45\x30\x68\x62\x6d\x63", 8,
+      1024,
+      24,
+      "\xde\x5c\xb8\xd5\x75\xf6\xad\x69\x5b\xc9\xf6\x2f\xba\xeb\xfb\x36"
+      "\x34\xf2\xb8\xee\x3b\x37\x21\xb7"
+    }
+  };
+  int tvidx;
+  gpg_error_t err;
+  unsigned char outbuf[32];
+  int i;
+
+  for (tvidx=0; tvidx < DIM(tv); tvidx++)
+    {
+      if (tv[tvidx].disabled)
+        continue;
+      if (verbose)
+        fprintf (stderr, "checking S2K test vector %d\n", tvidx);
+      assert (tv[tvidx].dklen <= sizeof outbuf);
+      err = gcry_kdf_derive (tv[tvidx].p, tv[tvidx].plen,
+                             tv[tvidx].algo, tv[tvidx].hashalgo,
+                             tv[tvidx].salt, tv[tvidx].saltlen,
+                             tv[tvidx].c, tv[tvidx].dklen, outbuf);
+      if (err)
+        fail ("s2k test %d failed: %s\n", tvidx, gpg_strerror (err));
+      else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen))
+        {
+          fail ("s2k 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);
+        }
+    }
+}
+
+
+static void
+check_pbkdf2 (void)
+{
+  /* Test vectors are from RFC-6070.  */
+  static struct {
+    const char *p;   /* Passphrase.  */
+    size_t plen;     /* Length of P. */
+    const char *salt;
+    size_t saltlen;
+    unsigned long c; /* Iterations.  */
+    int dklen;       /* Requested key length.  */
+    const char *dk;  /* Derived key.  */
+    int disabled;
+  } tv[] = {
+    {
+      "password", 8,
+      "salt", 4,
+      1,
+      20,
+      "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
+      "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"
+    },
+    {
+      "password", 8,
+      "salt", 4,
+      2,
+      20,
+      "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
+      "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57"
+    },
+    {
+      "password", 8,
+      "salt", 4,
+      4096,
+      20,
+      "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
+      "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1"
+    },
+    {
+      "password", 8,
+      "salt", 4,
+      16777216,
+      20,
+      "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
+      "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84",
+      1 /* This test takes too long.  */
+    },
+    {
+      "passwordPASSWORDpassword", 24,
+      "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
+      4096,
+      25,
+      "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
+      "\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
+      "\x4c\xf2\xf0\x70\x38"
+    },
+    {
+      "pass\0word", 9,
+      "sa\0lt", 5,
+      4096,
+      16,
+      "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
+      "\xd7\xf0\x34\x25\xe0\xc3"
+    }
+  };
+  int tvidx;
+  gpg_error_t err;
+  unsigned char outbuf[32];
+  int i;
+
+  for (tvidx=0; tvidx < DIM(tv); tvidx++)
+    {
+      if (tv[tvidx].disabled)
+        continue;
+      if (verbose)
+        fprintf (stderr, "checking PBKDF2 test vector %d\n", tvidx);
+      assert (tv[tvidx].dklen <= sizeof outbuf);
+      err = gcry_kdf_derive (tv[tvidx].p, tv[tvidx].plen,
+                             GCRY_KDF_PBKDF2, GCRY_MD_SHA1,
+                             tv[tvidx].salt, tv[tvidx].saltlen,
+                             tv[tvidx].c, tv[tvidx].dklen, outbuf);
+      if (err)
+        fail ("pbkdf2 test %d failed: %s\n", tvidx, gpg_strerror (err));
+      else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen))
+        {
+          fail ("pbkdf2 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"))
+    verbose = debug = 1;
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+
+  check_openpgp ();
+  check_pbkdf2 ();
+
+  return error_count ? 1 : 0;
+}

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

Summary of changes:
 NEWS               |    4 +
 cipher/ChangeLog   |    4 +
 cipher/Makefile.am |    2 +-
 cipher/kdf.c       |  278 +++++++++++++++
 doc/gcrypt.texi    |   62 ++++-
 src/ChangeLog      |    7 +
 src/gcrypt.h.in    |   27 ++
 src/libgcrypt.def  |    2 +
 src/libgcrypt.vers |    2 +
 src/visibility.c   |   11 +
 src/visibility.h   |    6 +
 tests/Makefile.am  |    2 +-
 tests/t-kdf.c      |  974 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 1378 insertions(+), 3 deletions(-)
 create mode 100644 cipher/kdf.c
 create mode 100644 tests/t-kdf.c


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




More information about the Gnupg-commits mailing list