gsasl-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gsasl branch, master, updated. gsasl-1-2-72-g624e503


From: Simon Josefsson
Subject: [SCM] GNU gsasl branch, master, updated. gsasl-1-2-72-g624e503
Date: Thu, 10 Sep 2009 12:53:29 +0000

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 "GNU gsasl".

http://git.savannah.gnu.org/cgit/gsasl.git/commit/?id=624e503864ac13347e5f8009af00ab64b8b80e99

The branch, master has been updated
       via  624e503864ac13347e5f8009af00ab64b8b80e99 (commit)
       via  6fef45cf0676b4f53240a39804782a8883803d75 (commit)
       via  cddf7a106c3c36961c9229ee5c6cf48470291d49 (commit)
       via  5c146660cdc6d204e395af5db1ed2b3b381c2200 (commit)
       via  36b3c180eb3bd76e9c971a4a37a92a0870b0804c (commit)
       via  1f6a7e68a49efb6b631d097f9cdbe11b8a565705 (commit)
       via  571e45edac17279179e74897993b9aa98f44fa98 (commit)
      from  605fe234954cd3068e4566012d2ba762df735174 (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 624e503864ac13347e5f8009af00ab64b8b80e99
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:53:23 2009 +0200

    Add crypto/gc-pbkdf2-sha1 gnulib module.

commit 6fef45cf0676b4f53240a39804782a8883803d75
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:42:24 2009 +0200

    Check errors.

commit cddf7a106c3c36961c9229ee5c6cf48470291d49
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:41:21 2009 +0200

    SCRAM: Compare nonces.

commit 5c146660cdc6d204e395af5db1ed2b3b381c2200
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:32:22 2009 +0200

    SCRAM: Correct cbind in client final.

commit 36b3c180eb3bd76e9c971a4a37a92a0870b0804c
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:11:49 2009 +0200

    SCRAM: Print/parse authzid.

commit 1f6a7e68a49efb6b631d097f9cdbe11b8a565705
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 14:02:01 2009 +0200

    Test iter/salt too.

commit 571e45edac17279179e74897993b9aa98f44fa98
Author: Simon Josefsson <address@hidden>
Date:   Thu Sep 10 13:59:32 2009 +0200

    SCRAM: Use printable salt.  Fix mem leak

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

Summary of changes:
 lib/gl/Makefile.am                                 |   20 +-
 lib/gl/gc-pbkdf2-sha1.c                            |  186 +++++++++
 lib/gl/{hmac-md5.c => hmac-sha1.c}                 |   42 +-
 lib/gl/m4/{gc-hmac-md5.m4 => gc-hmac-sha1.m4}      |    8 +-
 lib/gl/m4/{hmac-md5.m4 => gc-pbkdf2-sha1.m4}       |    6 +-
 lib/gl/m4/gnulib-cache.m4                          |    3 +-
 lib/gl/m4/gnulib-comp.m4                           |   13 +
 lib/gl/m4/{hmac-md5.m4 => hmac-sha1.m4}            |    6 +-
 lib/gl/m4/{md5.m4 => sha1.m4}                      |    8 +-
 lib/gl/sha1.c                                      |  420 ++++++++++++++++++++
 lib/gl/sha1.h                                      |   92 +++++
 lib/gltests/Makefile.am                            |   18 +
 .../{test-gc-hmac-md5.c => test-gc-hmac-sha1.c}    |   19 +-
 lib/gltests/test-gc-pbkdf2-sha1.c                  |  109 +++++
 lib/scram/client.c                                 |   42 ++-
 lib/scram/parser.c                                 |   25 +-
 lib/scram/server.c                                 |   44 ++-
 tests/scram.c                                      |   28 ++-
 18 files changed, 1005 insertions(+), 84 deletions(-)
 create mode 100644 lib/gl/gc-pbkdf2-sha1.c
 copy lib/gl/{hmac-md5.c => hmac-sha1.c} (64%)
 copy lib/gl/m4/{gc-hmac-md5.m4 => gc-hmac-sha1.m4} (80%)
 copy lib/gl/m4/{hmac-md5.m4 => gc-pbkdf2-sha1.m4} (74%)
 copy lib/gl/m4/{hmac-md5.m4 => hmac-sha1.m4} (77%)
 copy lib/gl/m4/{md5.m4 => sha1.m4} (78%)
 create mode 100644 lib/gl/sha1.c
 create mode 100644 lib/gl/sha1.h
 copy lib/gltests/{test-gc-hmac-md5.c => test-gc-hmac-sha1.c} (77%)
 create mode 100644 lib/gltests/test-gc-pbkdf2-sha1.c

diff --git a/lib/gl/Makefile.am b/lib/gl/Makefile.am
index 3f3adc1..fe20fb0 100644
--- a/lib/gl/Makefile.am
+++ b/lib/gl/Makefile.am
@@ -9,7 +9,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl/override 
--lib=libgl --source-base=gl --m4-base=gl/m4 --doc-base=doc 
--tests-base=gltests --aux-dir=build-aux --with-tests 
--avoid=vc-list-files-tests --lgpl=2 --libtool --macro-prefix=gl --no-vc-files 
base64 crypto/gc crypto/gc-hmac-md5 crypto/gc-hmac-md5-tests crypto/gc-md5 
crypto/gc-md5-tests crypto/gc-random crypto/gc-tests getline gettext 
lib-msvc-compat lib-symbol-versions lib-symbol-visibility maintainer-makefile 
minmax strchrnul strverscmp vasprintf
+# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl/override 
--lib=libgl --source-base=gl --m4-base=gl/m4 --doc-base=doc 
--tests-base=gltests --aux-dir=build-aux --with-tests 
--avoid=vc-list-files-tests --lgpl=2 --libtool --macro-prefix=gl --no-vc-files 
base64 crypto/gc crypto/gc-hmac-md5 crypto/gc-hmac-md5-tests crypto/gc-md5 
crypto/gc-md5-tests crypto/gc-pbkdf2-sha1 crypto/gc-random crypto/gc-tests 
getline gettext lib-msvc-compat lib-symbol-versions lib-symbol-visibility 
maintainer-makefile minmax strchrnul strverscmp vasprintf
 
 AUTOMAKE_OPTIONS = 1.5 gnits
 
@@ -83,6 +83,15 @@ EXTRA_libgl_la_SOURCES += hmac-md5.c md5.c memxor.c
 
 ## end   gnulib module crypto/gc-hmac-md5
 
+## begin gnulib module crypto/gc-hmac-sha1
+
+
+EXTRA_DIST += hmac-sha1.c hmac.h memxor.c memxor.h sha1.c sha1.h
+
+EXTRA_libgl_la_SOURCES += hmac-sha1.c memxor.c sha1.c
+
+## end   gnulib module crypto/gc-hmac-sha1
+
 ## begin gnulib module crypto/gc-md5
 
 libgl_la_SOURCES += md5.h
@@ -93,6 +102,15 @@ EXTRA_libgl_la_SOURCES += md5.c
 
 ## end   gnulib module crypto/gc-md5
 
+## begin gnulib module crypto/gc-pbkdf2-sha1
+
+
+EXTRA_DIST += gc-pbkdf2-sha1.c
+
+EXTRA_libgl_la_SOURCES += gc-pbkdf2-sha1.c
+
+## end   gnulib module crypto/gc-pbkdf2-sha1
+
 ## begin gnulib module errno
 
 BUILT_SOURCES += $(ERRNO_H)
diff --git a/lib/gl/gc-pbkdf2-sha1.c b/lib/gl/gc-pbkdf2-sha1.c
new file mode 100644
index 0000000..364bf1d
--- /dev/null
+++ b/lib/gl/gc-pbkdf2-sha1.c
@@ -0,0 +1,186 @@
+/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5
+   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+
+   This program 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, or (at your option)
+   any later version.
+
+   This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Simon Josefsson.  The comments in this file are taken
+   from RFC 2898.  */
+
+#include <config.h>
+
+#include "gc.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * 5.2 PBKDF2
+ *
+ *  PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
+ *  example) to derive keys. The length of the derived key is essentially
+ *  unbounded. (However, the maximum effective search space for the
+ *  derived key may be limited by the structure of the underlying
+ *  pseudorandom function. See Appendix B.1 for further discussion.)
+ *  PBKDF2 is recommended for new applications.
+ *
+ *  PBKDF2 (P, S, c, dkLen)
+ *
+ *  Options:        PRF        underlying pseudorandom function (hLen
+ *                             denotes the length in octets of the
+ *                             pseudorandom function output)
+ *
+ *  Input:          P          password, an octet string (ASCII or UTF-8)
+ *                  S          salt, an octet string
+ *                  c          iteration count, a positive integer
+ *                  dkLen      intended length in octets of the derived
+ *                             key, a positive integer, at most
+ *                             (2^32 - 1) * hLen
+ *
+ *  Output:         DK         derived key, a dkLen-octet string
+ */
+
+Gc_rc
+gc_pbkdf2_sha1 (const char *P, size_t Plen,
+               const char *S, size_t Slen,
+               unsigned int c,
+               char *DK, size_t dkLen)
+{
+  unsigned int hLen = 20;
+  char U[20];
+  char T[20];
+  unsigned int u;
+  unsigned int l;
+  unsigned int r;
+  unsigned int i;
+  unsigned int k;
+  int rc;
+  char *tmp;
+  size_t tmplen = Slen + 4;
+
+  if (c == 0)
+    return GC_PKCS5_INVALID_ITERATION_COUNT;
+
+  if (dkLen == 0)
+    return GC_PKCS5_INVALID_DERIVED_KEY_LENGTH;
+
+  /*
+   *
+   *  Steps:
+   *
+   *     1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
+   *        stop.
+   */
+
+  if (dkLen > 4294967295U)
+    return GC_PKCS5_DERIVED_KEY_TOO_LONG;
+
+  /*
+   *     2. Let l be the number of hLen-octet blocks in the derived key,
+   *        rounding up, and let r be the number of octets in the last
+   *        block:
+   *
+   *                  l = CEIL (dkLen / hLen) ,
+   *                  r = dkLen - (l - 1) * hLen .
+   *
+   *        Here, CEIL (x) is the "ceiling" function, i.e. the smallest
+   *        integer greater than, or equal to, x.
+   */
+
+  l = ((dkLen - 1) / hLen) + 1;
+  r = dkLen - (l - 1) * hLen;
+
+  /*
+   *     3. For each block of the derived key apply the function F defined
+   *        below to the password P, the salt S, the iteration count c, and
+   *        the block index to compute the block:
+   *
+   *                  T_1 = F (P, S, c, 1) ,
+   *                  T_2 = F (P, S, c, 2) ,
+   *                  ...
+   *                  T_l = F (P, S, c, l) ,
+   *
+   *        where the function F is defined as the exclusive-or sum of the
+   *        first c iterates of the underlying pseudorandom function PRF
+   *        applied to the password P and the concatenation of the salt S
+   *        and the block index i:
+   *
+   *                  F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
+   *
+   *        where
+   *
+   *                  U_1 = PRF (P, S || INT (i)) ,
+   *                  U_2 = PRF (P, U_1) ,
+   *                  ...
+   *                  U_c = PRF (P, U_{c-1}) .
+   *
+   *        Here, INT (i) is a four-octet encoding of the integer i, most
+   *        significant octet first.
+   *
+   *     4. Concatenate the blocks and extract the first dkLen octets to
+   *        produce a derived key DK:
+   *
+   *                  DK = T_1 || T_2 ||  ...  || T_l<0..r-1>
+   *
+   *     5. Output the derived key DK.
+   *
+   *  Note. The construction of the function F follows a "belt-and-
+   *  suspenders" approach. The iterates U_i are computed recursively to
+   *  remove a degree of parallelism from an opponent; they are exclusive-
+   *  ored together to reduce concerns about the recursion degenerating
+   *  into a small set of values.
+   *
+   */
+
+  tmp = malloc (tmplen);
+  if (tmp == NULL)
+    return GC_MALLOC_ERROR;
+
+  memcpy (tmp, S, Slen);
+
+  for (i = 1; i <= l; i++)
+    {
+      memset (T, 0, hLen);
+
+      for (u = 1; u <= c; u++)
+       {
+         if (u == 1)
+           {
+             tmp[Slen + 0] = (i & 0xff000000) >> 24;
+             tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
+             tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
+             tmp[Slen + 3] = (i & 0x000000ff) >> 0;
+
+             rc = gc_hmac_sha1 (P, Plen, tmp, tmplen, U);
+           }
+         else
+           rc = gc_hmac_sha1 (P, Plen, U, hLen, U);
+
+         if (rc != GC_OK)
+           {
+             free (tmp);
+             return rc;
+           }
+
+         for (k = 0; k < hLen; k++)
+           T[k] ^= U[k];
+       }
+
+      memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
+    }
+
+  free (tmp);
+
+  return GC_OK;
+}
diff --git a/lib/gl/hmac-md5.c b/lib/gl/hmac-sha1.c
similarity index 64%
copy from lib/gl/hmac-md5.c
copy to lib/gl/hmac-sha1.c
index 51cd9e0..93d0aba 100644
--- a/lib/gl/hmac-md5.c
+++ b/lib/gl/hmac-sha1.c
@@ -1,4 +1,4 @@
-/* hmac-md5.c -- hashed message authentication codes
+/* hmac-sha1.c -- hashed message authentication codes
    Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 #include "hmac.h"
 
 #include "memxor.h"
-#include "md5.h"
+#include "sha1.h"
 
 #include <string.h>
 
@@ -30,52 +30,52 @@
 #define OPAD 0x5c
 
 int
-hmac_md5 (const void *key, size_t keylen,
-         const void *in, size_t inlen, void *resbuf)
+hmac_sha1 (const void *key, size_t keylen,
+          const void *in, size_t inlen, void *resbuf)
 {
-  struct md5_ctx inner;
-  struct md5_ctx outer;
-  char optkeybuf[16];
+  struct sha1_ctx inner;
+  struct sha1_ctx outer;
+  char optkeybuf[20];
   char block[64];
-  char innerhash[16];
+  char innerhash[20];
 
   /* Reduce the key's size, so that it becomes <= 64 bytes large.  */
 
   if (keylen > 64)
     {
-      struct md5_ctx keyhash;
+      struct sha1_ctx keyhash;
 
-      md5_init_ctx (&keyhash);
-      md5_process_bytes (key, keylen, &keyhash);
-      md5_finish_ctx (&keyhash, optkeybuf);
+      sha1_init_ctx (&keyhash);
+      sha1_process_bytes (key, keylen, &keyhash);
+      sha1_finish_ctx (&keyhash, optkeybuf);
 
       key = optkeybuf;
-      keylen = 16;
+      keylen = 20;
     }
 
   /* Compute INNERHASH from KEY and IN.  */
 
-  md5_init_ctx (&inner);
+  sha1_init_ctx (&inner);
 
   memset (block, IPAD, sizeof (block));
   memxor (block, key, keylen);
 
-  md5_process_block (block, 64, &inner);
-  md5_process_bytes (in, inlen, &inner);
+  sha1_process_block (block, 64, &inner);
+  sha1_process_bytes (in, inlen, &inner);
 
-  md5_finish_ctx (&inner, innerhash);
+  sha1_finish_ctx (&inner, innerhash);
 
   /* Compute result from KEY and INNERHASH.  */
 
-  md5_init_ctx (&outer);
+  sha1_init_ctx (&outer);
 
   memset (block, OPAD, sizeof (block));
   memxor (block, key, keylen);
 
-  md5_process_block (block, 64, &outer);
-  md5_process_bytes (innerhash, 16, &outer);
+  sha1_process_block (block, 64, &outer);
+  sha1_process_bytes (innerhash, 20, &outer);
 
-  md5_finish_ctx (&outer, resbuf);
+  sha1_finish_ctx (&outer, resbuf);
 
   return 0;
 }
diff --git a/lib/gl/m4/gc-hmac-md5.m4 b/lib/gl/m4/gc-hmac-sha1.m4
similarity index 80%
copy from lib/gl/m4/gc-hmac-md5.m4
copy to lib/gl/m4/gc-hmac-sha1.m4
index 9ee5680..9d4b9dc 100644
--- a/lib/gl/m4/gc-hmac-md5.m4
+++ b/lib/gl/m4/gc-hmac-sha1.m4
@@ -1,15 +1,15 @@
-# gc-hmac-md5.m4 serial 2
+# gc-hmac-sha1.m4 serial 2
 dnl Copyright (C) 2005, 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_GC_HMAC_MD5],
+AC_DEFUN([gl_GC_HMAC_SHA1],
 [
   AC_REQUIRE([gl_GC])
   if test "$ac_cv_libgcrypt" != yes; then
-    gl_MD5
-    gl_HMAC_MD5
+    gl_SHA1
+    gl_HMAC_SHA1
     gl_MEMXOR
   fi
 ])
diff --git a/lib/gl/m4/hmac-md5.m4 b/lib/gl/m4/gc-pbkdf2-sha1.m4
similarity index 74%
copy from lib/gl/m4/hmac-md5.m4
copy to lib/gl/m4/gc-pbkdf2-sha1.m4
index 729c6bf..05fc881 100644
--- a/lib/gl/m4/hmac-md5.m4
+++ b/lib/gl/m4/gc-pbkdf2-sha1.m4
@@ -1,10 +1,10 @@
-# hmac-md5.m4 serial 2
+# gc-pbkdf2-sha1.m4 serial 2
 dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_HMAC_MD5],
+AC_DEFUN([gl_GC_PBKDF2_SHA1],
 [
-  AC_LIBOBJ([hmac-md5])
+  AC_LIBOBJ([gc-pbkdf2-sha1])
 ])
diff --git a/lib/gl/m4/gnulib-cache.m4 b/lib/gl/m4/gnulib-cache.m4
index da5c1a7..0fb1947 100644
--- a/lib/gl/m4/gnulib-cache.m4
+++ b/lib/gl/m4/gnulib-cache.m4
@@ -15,7 +15,7 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --local-dir=gl/override --lib=libgl 
--source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gltests 
--aux-dir=build-aux --with-tests --avoid=vc-list-files-tests --lgpl=2 --libtool 
--macro-prefix=gl --no-vc-files base64 crypto/gc crypto/gc-hmac-md5 
crypto/gc-hmac-md5-tests crypto/gc-md5 crypto/gc-md5-tests crypto/gc-random 
crypto/gc-tests getline gettext lib-msvc-compat lib-symbol-versions 
lib-symbol-visibility maintainer-makefile minmax strchrnul strverscmp vasprintf
+#   gnulib-tool --import --dir=. --local-dir=gl/override --lib=libgl 
--source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=gltests 
--aux-dir=build-aux --with-tests --avoid=vc-list-files-tests --lgpl=2 --libtool 
--macro-prefix=gl --no-vc-files base64 crypto/gc crypto/gc-hmac-md5 
crypto/gc-hmac-md5-tests crypto/gc-md5 crypto/gc-md5-tests 
crypto/gc-pbkdf2-sha1 crypto/gc-random crypto/gc-tests getline gettext 
lib-msvc-compat lib-symbol-versions lib-symbol-visibility maintainer-makefile 
minmax strchrnul strverscmp vasprintf
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([gl/override])
@@ -26,6 +26,7 @@ gl_MODULES([
   crypto/gc-hmac-md5-tests
   crypto/gc-md5
   crypto/gc-md5-tests
+  crypto/gc-pbkdf2-sha1
   crypto/gc-random
   crypto/gc-tests
   getline
diff --git a/lib/gl/m4/gnulib-comp.m4 b/lib/gl/m4/gnulib-comp.m4
index ef5a819..a4ec967 100644
--- a/lib/gl/m4/gnulib-comp.m4
+++ b/lib/gl/m4/gnulib-comp.m4
@@ -50,8 +50,11 @@ AC_DEFUN([gl_INIT],
   fi
   gl_GC_HMAC_MD5
   gl_MODULE_INDICATOR([gc-hmac-md5])
+  gl_GC_HMAC_SHA1
+  gl_MODULE_INDICATOR([gc-hmac-sha1])
   gl_GC_MD5
   gl_MODULE_INDICATOR([gc-md5])
+  gl_GC_PBKDF2_SHA1
   gl_GC_RANDOM
   gl_MODULE_INDICATOR([gc-random])
   gl_HEADER_ERRNO_H
@@ -253,12 +256,14 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/float.in.h
   lib/gc-gnulib.c
   lib/gc-libgcrypt.c
+  lib/gc-pbkdf2-sha1.c
   lib/gc.h
   lib/getdelim.c
   lib/getline.c
   lib/getpagesize.c
   lib/gettext.h
   lib/hmac-md5.c
+  lib/hmac-sha1.c
   lib/hmac.h
   lib/md5.c
   lib/md5.h
@@ -274,6 +279,8 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/rawmemchr.c
   lib/rawmemchr.valgrind
   lib/realloc.c
+  lib/sha1.c
+  lib/sha1.h
   lib/size_max.h
   lib/stdbool.in.h
   lib/stddef.in.h
@@ -299,7 +306,9 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/extensions.m4
   m4/float_h.m4
   m4/gc-hmac-md5.m4
+  m4/gc-hmac-sha1.m4
   m4/gc-md5.m4
+  m4/gc-pbkdf2-sha1.m4
   m4/gc-random.m4
   m4/gc.m4
   m4/getdelim.m4
@@ -310,6 +319,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/glibc21.m4
   m4/gnulib-common.m4
   m4/hmac-md5.m4
+  m4/hmac-sha1.m4
   m4/iconv.m4
   m4/include_next.m4
   m4/intdiv0.m4
@@ -341,6 +351,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/progtest.m4
   m4/rawmemchr.m4
   m4/realloc.m4
+  m4/sha1.m4
   m4/size_max.m4
   m4/stdbool.m4
   m4/stddef_h.m4
@@ -365,7 +376,9 @@ AC_DEFUN([gl_FILE_LIST], [
   tests/test-base64.c
   tests/test-errno.c
   tests/test-gc-hmac-md5.c
+  tests/test-gc-hmac-sha1.c
   tests/test-gc-md5.c
+  tests/test-gc-pbkdf2-sha1.c
   tests/test-gc.c
   tests/test-getdelim.c
   tests/test-getline.c
diff --git a/lib/gl/m4/hmac-md5.m4 b/lib/gl/m4/hmac-sha1.m4
similarity index 77%
copy from lib/gl/m4/hmac-md5.m4
copy to lib/gl/m4/hmac-sha1.m4
index 729c6bf..74c9366 100644
--- a/lib/gl/m4/hmac-md5.m4
+++ b/lib/gl/m4/hmac-sha1.m4
@@ -1,10 +1,10 @@
-# hmac-md5.m4 serial 2
+# hmac-sha1.m4 serial 2
 dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_HMAC_MD5],
+AC_DEFUN([gl_HMAC_SHA1],
 [
-  AC_LIBOBJ([hmac-md5])
+  AC_LIBOBJ([hmac-sha1])
 ])
diff --git a/lib/gl/m4/md5.m4 b/lib/gl/m4/sha1.m4
similarity index 78%
copy from lib/gl/m4/md5.m4
copy to lib/gl/m4/sha1.m4
index 57b193f..b94c34d 100644
--- a/lib/gl/m4/md5.m4
+++ b/lib/gl/m4/sha1.m4
@@ -1,14 +1,14 @@
-# md5.m4 serial 11
+# sha1.m4 serial 9
 dnl Copyright (C) 2002, 2003, 2004, 2005, 2006, 2008, 2009 Free Software 
Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_MD5],
+AC_DEFUN([gl_SHA1],
 [
-  AC_LIBOBJ([md5])
+  AC_LIBOBJ([sha1])
 
-  dnl Prerequisites of lib/md5.c.
+  dnl Prerequisites of lib/sha1.c.
   AC_REQUIRE([gl_BIGENDIAN])
   AC_REQUIRE([AC_C_INLINE])
   :
diff --git a/lib/gl/sha1.c b/lib/gl/sha1.c
new file mode 100644
index 0000000..62c96ec
--- /dev/null
+++ b/lib/gl/sha1.c
@@ -0,0 +1,420 @@
+/* sha1.c - Functions to compute SHA1 message digest of files or
+   memory blocks according to the NIST specification FIPS-180-1.
+
+   Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2008 Free Software
+   Foundation, Inc.
+
+   This program 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, or (at your option) any
+   later version.
+
+   This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Scott G. Miller
+   Credits:
+      Robert Klep <address@hidden>  -- Expansion function fix
+*/
+
+#include <config.h>
+
+#include "sha1.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) (n)
+#else
+# define SWAP(n) \
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#endif
+
+#define BLOCKSIZE 4096
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/* Take a pointer to a 160 bit block of data (five 32 bit ints) and
+   initialize it to the start constants of the SHA1 algorithm.  This
+   must be called before using hash in the call to sha1_hash.  */
+void
+sha1_init_ctx (struct sha1_ctx *ctx)
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+  ctx->E = 0xc3d2e1f0;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Copy the 4 byte value from v into the memory location pointed to by *cp,
+   If your architecture allows unaligned access this is equivalent to
+   * (uint32_t *) cp = v  */
+static inline void
+set_uint32 (char *cp, uint32_t v)
+{
+  memcpy (cp, &v, sizeof v);
+}
+
+/* Put result from CTX in first 20 bytes following RESBUF.  The result
+   must be in little endian byte order.  */
+void *
+sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf)
+{
+  char *r = resbuf;
+  set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A));
+  set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B));
+  set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C));
+  set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D));
+  set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E));
+
+  return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.  */
+void *
+sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
+{
+  /* Take yet unprocessed bytes into account.  */
+  uint32_t bytes = ctx->buflen;
+  size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
+  ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3);
+
+  memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
+
+  /* Process last bytes.  */
+  sha1_process_block (ctx->buffer, size * 4, ctx);
+
+  return sha1_read_ctx (ctx, resbuf);
+}
+
+/* Compute SHA1 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+sha1_stream (FILE *stream, void *resblock)
+{
+  struct sha1_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  sha1_init_ctx (&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+        computation function processes the whole buffer so that with the
+        next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      while (1)
+       {
+         n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+         sum += n;
+
+         if (sum == BLOCKSIZE)
+           break;
+
+         if (n == 0)
+           {
+             /* Check for the error flag IFF N == 0, so that we don't
+                exit the loop after a partial read due to e.g., EAGAIN
+                or EWOULDBLOCK.  */
+             if (ferror (stream))
+               return 1;
+             goto process_partial_block;
+           }
+
+         /* We've read at least one byte, so ignore errors.  But always
+            check for EOF, since feof may be true even though N > 0.
+            Otherwise, we could end up calling fread after EOF.  */
+         if (feof (stream))
+           goto process_partial_block;
+       }
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+                       BLOCKSIZE % 64 == 0
+       */
+      sha1_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+ process_partial_block:;
+
+  /* Process any remaining bytes.  */
+  if (sum > 0)
+    sha1_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  sha1_finish_ctx (&ctx, resblock);
+  return 0;
+}
+
+/* Compute SHA1 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+sha1_buffer (const char *buffer, size_t len, void *resblock)
+{
+  struct sha1_ctx ctx;
+
+  /* Initialize the computation context.  */
+  sha1_init_ctx (&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  sha1_process_bytes (buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return sha1_finish_ctx (&ctx, resblock);
+}
+
+void
+sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+      memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
+      ctx->buflen += add;
+
+      if (ctx->buflen > 64)
+       {
+         sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+         ctx->buflen &= 63;
+         /* The regions in the following copy operation cannot overlap.  */
+         memcpy (ctx->buffer,
+                 &((char *) ctx->buffer)[(left_over + add) & ~63],
+                 ctx->buflen);
+       }
+
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
+
+  /* Process available complete blocks.  */
+  if (len >= 64)
+    {
+#if !_STRING_ARCH_unaligned
+# define alignof(type) offsetof (struct { char c; type x; }, x)
+# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0)
+      if (UNALIGNED_P (buffer))
+       while (len > 64)
+         {
+           sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+           buffer = (const char *) buffer + 64;
+           len -= 64;
+         }
+      else
+#endif
+       {
+         sha1_process_block (buffer, len & ~63, ctx);
+         buffer = (const char *) buffer + (len & ~63);
+         len &= 63;
+       }
+    }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      size_t left_over = ctx->buflen;
+
+      memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
+      left_over += len;
+      if (left_over >= 64)
+       {
+         sha1_process_block (ctx->buffer, 64, ctx);
+         left_over -= 64;
+         memcpy (ctx->buffer, &ctx->buffer[16], left_over);
+       }
+      ctx->buflen = left_over;
+    }
+}
+
+/* --- Code below is the primary difference between md5.c and sha1.c --- */
+
+/* SHA1 round constants */
+#define K1 0x5a827999
+#define K2 0x6ed9eba1
+#define K3 0x8f1bbcdc
+#define K4 0xca62c1d6
+
+/* Round functions.  Note that F2 is the same as F4.  */
+#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
+#define F2(B,C,D) (B ^ C ^ D)
+#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
+#define F4(B,C,D) (B ^ C ^ D)
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.
+   Most of this code comes from GnuPG's cipher/sha1.c.  */
+
+void
+sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx)
+{
+  const uint32_t *words = buffer;
+  size_t nwords = len / sizeof (uint32_t);
+  const uint32_t *endp = words + nwords;
+  uint32_t x[16];
+  uint32_t a = ctx->A;
+  uint32_t b = ctx->B;
+  uint32_t c = ctx->C;
+  uint32_t d = ctx->D;
+  uint32_t e = ctx->E;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n))))
+
+#define M(I) ( tm =   x[I&0x0f] ^ x[(I-14)&0x0f] \
+                   ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
+              , (x[I&0x0f] = rol(tm, 1)) )
+
+#define R(A,B,C,D,E,F,K,M)  do { E += rol( A, 5 )     \
+                                     + F( B, C, D )  \
+                                     + K             \
+                                     + M;            \
+                                B = rol( B, 30 );    \
+                              } while(0)
+
+  while (words < endp)
+    {
+      uint32_t tm;
+      int t;
+      for (t = 0; t < 16; t++)
+       {
+         x[t] = SWAP (*words);
+         words++;
+       }
+
+      R( a, b, c, d, e, F1, K1, x[ 0] );
+      R( e, a, b, c, d, F1, K1, x[ 1] );
+      R( d, e, a, b, c, F1, K1, x[ 2] );
+      R( c, d, e, a, b, F1, K1, x[ 3] );
+      R( b, c, d, e, a, F1, K1, x[ 4] );
+      R( a, b, c, d, e, F1, K1, x[ 5] );
+      R( e, a, b, c, d, F1, K1, x[ 6] );
+      R( d, e, a, b, c, F1, K1, x[ 7] );
+      R( c, d, e, a, b, F1, K1, x[ 8] );
+      R( b, c, d, e, a, F1, K1, x[ 9] );
+      R( a, b, c, d, e, F1, K1, x[10] );
+      R( e, a, b, c, d, F1, K1, x[11] );
+      R( d, e, a, b, c, F1, K1, x[12] );
+      R( c, d, e, a, b, F1, K1, x[13] );
+      R( b, c, d, e, a, F1, K1, x[14] );
+      R( a, b, c, d, e, F1, K1, x[15] );
+      R( e, a, b, c, d, F1, K1, M(16) );
+      R( d, e, a, b, c, F1, K1, M(17) );
+      R( c, d, e, a, b, F1, K1, M(18) );
+      R( b, c, d, e, a, F1, K1, M(19) );
+      R( a, b, c, d, e, F2, K2, M(20) );
+      R( e, a, b, c, d, F2, K2, M(21) );
+      R( d, e, a, b, c, F2, K2, M(22) );
+      R( c, d, e, a, b, F2, K2, M(23) );
+      R( b, c, d, e, a, F2, K2, M(24) );
+      R( a, b, c, d, e, F2, K2, M(25) );
+      R( e, a, b, c, d, F2, K2, M(26) );
+      R( d, e, a, b, c, F2, K2, M(27) );
+      R( c, d, e, a, b, F2, K2, M(28) );
+      R( b, c, d, e, a, F2, K2, M(29) );
+      R( a, b, c, d, e, F2, K2, M(30) );
+      R( e, a, b, c, d, F2, K2, M(31) );
+      R( d, e, a, b, c, F2, K2, M(32) );
+      R( c, d, e, a, b, F2, K2, M(33) );
+      R( b, c, d, e, a, F2, K2, M(34) );
+      R( a, b, c, d, e, F2, K2, M(35) );
+      R( e, a, b, c, d, F2, K2, M(36) );
+      R( d, e, a, b, c, F2, K2, M(37) );
+      R( c, d, e, a, b, F2, K2, M(38) );
+      R( b, c, d, e, a, F2, K2, M(39) );
+      R( a, b, c, d, e, F3, K3, M(40) );
+      R( e, a, b, c, d, F3, K3, M(41) );
+      R( d, e, a, b, c, F3, K3, M(42) );
+      R( c, d, e, a, b, F3, K3, M(43) );
+      R( b, c, d, e, a, F3, K3, M(44) );
+      R( a, b, c, d, e, F3, K3, M(45) );
+      R( e, a, b, c, d, F3, K3, M(46) );
+      R( d, e, a, b, c, F3, K3, M(47) );
+      R( c, d, e, a, b, F3, K3, M(48) );
+      R( b, c, d, e, a, F3, K3, M(49) );
+      R( a, b, c, d, e, F3, K3, M(50) );
+      R( e, a, b, c, d, F3, K3, M(51) );
+      R( d, e, a, b, c, F3, K3, M(52) );
+      R( c, d, e, a, b, F3, K3, M(53) );
+      R( b, c, d, e, a, F3, K3, M(54) );
+      R( a, b, c, d, e, F3, K3, M(55) );
+      R( e, a, b, c, d, F3, K3, M(56) );
+      R( d, e, a, b, c, F3, K3, M(57) );
+      R( c, d, e, a, b, F3, K3, M(58) );
+      R( b, c, d, e, a, F3, K3, M(59) );
+      R( a, b, c, d, e, F4, K4, M(60) );
+      R( e, a, b, c, d, F4, K4, M(61) );
+      R( d, e, a, b, c, F4, K4, M(62) );
+      R( c, d, e, a, b, F4, K4, M(63) );
+      R( b, c, d, e, a, F4, K4, M(64) );
+      R( a, b, c, d, e, F4, K4, M(65) );
+      R( e, a, b, c, d, F4, K4, M(66) );
+      R( d, e, a, b, c, F4, K4, M(67) );
+      R( c, d, e, a, b, F4, K4, M(68) );
+      R( b, c, d, e, a, F4, K4, M(69) );
+      R( a, b, c, d, e, F4, K4, M(70) );
+      R( e, a, b, c, d, F4, K4, M(71) );
+      R( d, e, a, b, c, F4, K4, M(72) );
+      R( c, d, e, a, b, F4, K4, M(73) );
+      R( b, c, d, e, a, F4, K4, M(74) );
+      R( a, b, c, d, e, F4, K4, M(75) );
+      R( e, a, b, c, d, F4, K4, M(76) );
+      R( d, e, a, b, c, F4, K4, M(77) );
+      R( c, d, e, a, b, F4, K4, M(78) );
+      R( b, c, d, e, a, F4, K4, M(79) );
+
+      a = ctx->A += a;
+      b = ctx->B += b;
+      c = ctx->C += c;
+      d = ctx->D += d;
+      e = ctx->E += e;
+    }
+}
diff --git a/lib/gl/sha1.h b/lib/gl/sha1.h
new file mode 100644
index 0000000..c214e1d
--- /dev/null
+++ b/lib/gl/sha1.h
@@ -0,0 +1,92 @@
+/* Declarations of functions and data types used for SHA1 sum
+   library functions.
+   Copyright (C) 2000, 2001, 2003, 2005, 2006, 2008, 2009
+   Free Software Foundation, Inc.
+
+   This program 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, or (at your option) any
+   later version.
+
+   This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef SHA1_H
+# define SHA1_H 1
+
+# include <stdio.h>
+# include <stdint.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+#define SHA1_DIGEST_SIZE 20
+
+/* Structure to save state of computation between the single steps.  */
+struct sha1_ctx
+{
+  uint32_t A;
+  uint32_t B;
+  uint32_t C;
+  uint32_t D;
+  uint32_t E;
+
+  uint32_t total[2];
+  uint32_t buflen;
+  uint32_t buffer[32];
+};
+
+
+/* Initialize structure containing state of computation. */
+extern void sha1_init_ctx (struct sha1_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void sha1_process_block (const void *buffer, size_t len,
+                               struct sha1_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void sha1_process_bytes (const void *buffer, size_t len,
+                               struct sha1_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 20 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.  */
+extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 20 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.  */
+extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf);
+
+
+/* Compute SHA1 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 20 bytes
+   beginning at RESBLOCK.  */
+extern int sha1_stream (FILE *stream, void *resblock);
+
+/* Compute SHA1 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *sha1_buffer (const char *buffer, size_t len, void *resblock);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/lib/gltests/Makefile.am b/lib/gltests/Makefile.am
index 844a1c1..8910664 100644
--- a/lib/gltests/Makefile.am
+++ b/lib/gltests/Makefile.am
@@ -59,6 +59,24 @@ EXTRA_DIST += test-base64.c
 
 ## end   gnulib module base64-tests
 
+## begin gnulib module crypto/gc-hmac-sha1-tests
+
+TESTS += test-gc-hmac-sha1
+check_PROGRAMS += test-gc-hmac-sha1
+
+EXTRA_DIST += test-gc-hmac-sha1.c
+
+## end   gnulib module crypto/gc-hmac-sha1-tests
+
+## begin gnulib module crypto/gc-pbkdf2-sha1-tests
+
+TESTS += test-gc-pbkdf2-sha1
+check_PROGRAMS += test-gc-pbkdf2-sha1
+
+EXTRA_DIST += test-gc-pbkdf2-sha1.c
+
+## end   gnulib module crypto/gc-pbkdf2-sha1-tests
+
 ## begin gnulib module errno-tests
 
 TESTS += test-errno
diff --git a/lib/gltests/test-gc-hmac-md5.c b/lib/gltests/test-gc-hmac-sha1.c
similarity index 77%
copy from lib/gltests/test-gc-hmac-md5.c
copy to lib/gltests/test-gc-hmac-sha1.c
index b594d91..d39f3c5 100644
--- a/lib/gltests/test-gc-hmac-md5.c
+++ b/lib/gltests/test-gc-hmac-sha1.c
@@ -35,8 +35,6 @@ main (int argc, char *argv[])
       return 1;
     }
 
-    /* Test vectors from RFC 2104. */
-
   {
     char *key =
       "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
@@ -44,24 +42,17 @@ main (int argc, char *argv[])
     char *data = "Hi There";
     size_t data_len = 8;
     char *digest =
-      "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d";
-    char out[16];
-
-    /*
-      key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
-      key_len =     16 bytes
-      data =        "Hi There"
-      data_len =    8  bytes
-      digest =      0x9294727a3638bb1c13f48ef8158bfc9d
-    */
+      "\x67\x5b\x0b\x3a\x1b\x4d\xdf\x4e\x12\x48"
+      "\x72\xda\x6c\x2f\x63\x2b\xfe\xd9\x57\xe9";
+    char out[GC_SHA1_DIGEST_SIZE];
 
-    if (gc_hmac_md5 (key, key_len, data, data_len, out) != 0)
+    if (gc_hmac_sha1 (key, key_len, data, data_len, out) != 0)
       {
        printf ("call failure\n");
        return 1;
       }
 
-    if (memcmp (digest, out, 16) != 0)
+    if (memcmp (digest, out, GC_SHA1_DIGEST_SIZE) != 0)
       {
        size_t i;
        printf ("hash 1 mismatch. expected:\n");
diff --git a/lib/gltests/test-gc-pbkdf2-sha1.c 
b/lib/gltests/test-gc-pbkdf2-sha1.c
new file mode 100644
index 0000000..933af95
--- /dev/null
+++ b/lib/gltests/test-gc-pbkdf2-sha1.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2002, 2003, 2004, 2005, 2007  Free Software Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.  */
+
+/* Written by Simon Josefsson.  */
+
+#include <config.h>
+
+#include "gc.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* Test vectors from RFC 3962. */
+
+#define G_CLEF "\xF0\x9D\x84\x9E"
+
+struct pkcs5
+{
+  int iterations;
+  const char *password;
+  const char *salt;
+  int dklen;
+  const char *expected;
+};
+const struct pkcs5 pkcs5[] = {
+  {1, "password", "ATHENA.MIT.EDUraeburn", 16,
+   "\xCD\xED\xB5\x28\x1B\xB2\xF8\x01\x56\x5A\x11\x22\xB2\x56\x35\x15"},
+  {2, "password", "ATHENA.MIT.EDUraeburn", 16,
+   "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d"},
+  {2, "password", "ATHENA.MIT.EDUraeburn", 32,
+   "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
+   "\xa0\x53\x78\xb9\x32\x44\xec\x8f\x48\xa9\x9e\x61\xad\x79\x9d\x86"},
+  {1200, "password", "ATHENA.MIT.EDUraeburn", 16,
+   "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"},
+  {1200, "password", "ATHENA.MIT.EDUraeburn", 32,
+   "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
+   "\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f\x70\x8a\x31\xe2\xe6\x2b\x1e\x13"},
+  {5, "password", "\x12\x34\x56\x78\x78\x56\x34\x12\x00", 16,
+   "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"},
+  {5, "password", "\x12\x34\x56\x78\x78\x56\x34\x12\x00", 32,
+   "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
+   "\x3f\x98\xd2\x03\xe6\xbe\x49\xa6\xad\xf4\xfa\x57\x4b\x6e\x64\xee"},
+  {1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+   "pass phrase equals block size", 16,
+   "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"},
+  {1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+   "pass phrase equals block size", 32,
+   "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
+   "\xc5\xec\x59\xf1\xa4\x52\xf5\xcc\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1"},
+  {1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+   "pass phrase exceeds block size", 16,
+   "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61"},
+  {1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+   "pass phrase exceeds block size", 32,
+   "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
+   "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a"},
+  {50, G_CLEF "\x00", "EXAMPLE.COMpianist", 16,
+   "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"},
+  {50, G_CLEF "\x00", "EXAMPLE.COMpianist", 32,
+   "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
+   "\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2\x81\xff\x30\x69\xe1\xe9\x4f\x52"},
+  {500, "All n-entities must communicate with other n-entities via n-1 "
+   "entiteeheehees", "\x12\x34\x56\x78\x78\x56\x34\x12\x00", 16,
+   "\x6A\x89\x70\xBF\x68\xC9\x2C\xAE\xA8\x4A\x8D\xF2\x85\x10\x85\x86"}
+};
+
+int
+main (int argc, char *argv[])
+{
+  size_t i;
+  int rc;
+  char out[BUFSIZ];
+
+  for (i = 0; i < sizeof (pkcs5) / sizeof (pkcs5[0]); i++)
+    {
+      rc = gc_pbkdf2_sha1 (pkcs5[i].password, strlen (pkcs5[i].password),
+                          pkcs5[i].salt, strlen (pkcs5[i].salt),
+                          pkcs5[i].iterations, out, pkcs5[i].dklen);
+      if (rc != GC_OK)
+       {
+         printf ("PKCS5 entry %ld failed fatally: %d\n",
+                 (unsigned long) i, rc);
+         return 1;
+       }
+
+      if (memcmp (pkcs5[i].expected, out, pkcs5[i].dklen) != 0)
+       {
+         printf ("PKCS5 entry %ld failed\n", (unsigned long) i);
+         return 1;
+       }
+    }
+
+  return 0;
+}
diff --git a/lib/scram/client.c b/lib/scram/client.c
index 29034cc..d440bbc 100644
--- a/lib/scram/client.c
+++ b/lib/scram/client.c
@@ -53,7 +53,6 @@ _gsasl_scram_sha1_client_start (Gsasl_session * sctx, void 
**mech_data)
 {
   struct scram_client_state *state;
   char buf[CNONCE_ENTROPY_BYTES];
-  size_t i;
   int rc;
 
   state = (struct scram_client_state *) calloc (sizeof (*state), 1);
@@ -62,12 +61,18 @@ _gsasl_scram_sha1_client_start (Gsasl_session * sctx, void 
**mech_data)
 
   rc = gsasl_nonce (buf, CNONCE_ENTROPY_BYTES);
   if (rc != GSASL_OK)
-    return rc;
+    {
+      free (state);
+      return rc;
+    }
 
   rc = gsasl_base64_to (buf, CNONCE_ENTROPY_BYTES,
                        &state->cf.client_nonce, NULL);
   if (rc != GSASL_OK)
-    return rc;
+    {
+      free (state);
+      return rc;
+    }
 
   *mech_data = state;
 
@@ -106,12 +111,32 @@ _gsasl_scram_sha1_client_step (Gsasl_session * sctx,
        if (rc != GSASL_OK)
          return rc;
 
+       p = gsasl_property_get (sctx, GSASL_AUTHZID);
+       if (p)
+         state->cf.authzid = strdup (p);
+
        rc = scram_print_client_first (&state->cf, output);
-       if (rc != 0)
+       if (rc == -2)
          return GSASL_MALLOC_ERROR;
+       else if (rc != 0)
+         return GSASL_AUTHENTICATION_ERROR;
 
        *output_len = strlen (*output);
 
+       /* Save "cbind" for next step. */
+       p = strchr (*output, ',');
+       if (!p)
+           return GSASL_AUTHENTICATION_ERROR;
+       p++;
+       p = strchr (p, ',');
+       if (!p)
+           return GSASL_AUTHENTICATION_ERROR;
+       p++;
+       rc = gsasl_base64_to (*output, p - *output, &state->cl.cbind, NULL);
+       if (rc != 0)
+         return rc;
+
+       /* We are done. */
        state->step++;
        return GSASL_NEEDS_MORE;
        break;
@@ -125,10 +150,15 @@ _gsasl_scram_sha1_client_step (Gsasl_session * sctx,
        if (scram_parse_server_first (input, &state->sf) < 0)
          return GSASL_MECHANISM_PARSE_ERROR;
 
+       if (strlen (state->sf.nonce) < strlen (state->cf.client_nonce) ||
+           memcmp (state->cf.client_nonce, state->sf.nonce,
+                   strlen (state->cf.client_nonce)) != 0)
+         return GSASL_AUTHENTICATION_ERROR;
+
        state->cl.nonce = strdup (state->sf.nonce);
+       if (!state->cl.nonce)
+         return GSASL_MALLOC_ERROR;
 
-       /* FIXME */
-       state->cl.cbind = strdup ("cbind");
        state->cl.proof = strdup ("proof");
 
        rc = scram_print_client_final (&state->cl, output);
diff --git a/lib/scram/parser.c b/lib/scram/parser.c
index d83b55f..7ddd173 100644
--- a/lib/scram/parser.c
+++ b/lib/scram/parser.c
@@ -59,8 +59,25 @@ scram_parse_client_first (const char *str,
 
   if (*str == 'a')
     {
-      /* FIXME parse authzid */
-      return -1;
+      char *p;
+      size_t len;
+
+      p = strchr (str, ',');
+      if (!p)
+       return -1;
+
+      len = p - str;
+
+      cf->authzid = malloc (len + 1);
+      if (!cf->authzid)
+       return -1;
+
+      memcpy (cf->authzid, str, len);
+      cf->authzid[len] = '\0';
+
+      /* FIXME decode authzid */
+
+      str = p;
     }
 
   if (*str++ != ',')
@@ -89,6 +106,8 @@ scram_parse_client_first (const char *str,
     memcpy (cf->username, str, len);
     cf->username[len] = '\0';
 
+    /* FIXME decode username */
+
     str = p;
   }
 
@@ -189,7 +208,7 @@ scram_parse_server_first (const char *str,
     memcpy (sf->salt, str, len);
     sf->salt[len] = '\0';
 
-    /* FIXME base64 salt */
+    /* FIXME base64 decode salt */
 
     str = p;
   }
diff --git a/lib/scram/server.c b/lib/scram/server.c
index 7a4f57d..e06c3fc 100644
--- a/lib/scram/server.c
+++ b/lib/scram/server.c
@@ -36,18 +36,21 @@
 /* Get memcpy, strdup, strlen. */
 #include <string.h>
 
+/* Get MAX. */
+#include "minmax.h"
+
 #include "tokens.h"
 #include "parser.h"
 #include "printer.h"
 
-#define DEFAULT_SALT_BYTES 8
+#define DEFAULT_SALT_BYTES 12
 #define SNONCE_ENTROPY_BYTES 18
 
 struct scram_server_state
 {
   int step;
   char *snonce;
-  char salt[DEFAULT_SALT_BYTES + 1];
+  char *salt;
   struct scram_client_first cf;
   struct scram_server_first sf;
   struct scram_client_final cl;
@@ -58,8 +61,7 @@ int
 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
 {
   struct scram_server_state *state;
-  char buf[SNONCE_ENTROPY_BYTES];
-  size_t i;
+  char buf[MAX (SNONCE_ENTROPY_BYTES, DEFAULT_SALT_BYTES)];
   int rc;
 
   state = (struct scram_server_state *) calloc (sizeof (*state), 1);
@@ -68,33 +70,31 @@ _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void 
**mech_data)
 
   rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
   if (rc != GSASL_OK)
-    return rc;
+    goto end;
 
   rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES,
                        &state->snonce, NULL);
   if (rc != GSASL_OK)
-    return rc;
+    goto end;
 
-  rc = gsasl_nonce (state->salt, DEFAULT_SALT_BYTES);
+  rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
   if (rc != GSASL_OK)
-    return rc;
-
-  state->salt[DEFAULT_SALT_BYTES] = '\0';
-
-  for (i = 0; i < DEFAULT_SALT_BYTES; i++)
-    {
-      state->salt[i] &= 0x7f;
-
-      if (state->salt[i] == '\0')
-       state->salt[i]++;
+    goto end;
 
-      if (state->salt[i] == ',')
-       state->salt[i]++;
-    }
+  rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES,
+                       &state->salt, NULL);
+  if (rc != GSASL_OK)
+    goto end;
 
   *mech_data = state;
 
   return GSASL_OK;
+
+ end:
+  free (state->salt);
+  free (state->snonce);
+  free (state);
+  return rc;
 }
 
 int
@@ -169,6 +169,9 @@ _gsasl_scram_sha1_server_step (Gsasl_session * sctx,
        if (scram_parse_client_final (input, &state->cl) < 0)
          return GSASL_MECHANISM_PARSE_ERROR;
 
+       if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
+         return GSASL_AUTHENTICATION_ERROR;
+
        state->sl.verifier = strdup ("verifier");
 
        rc = scram_print_server_final (&state->sl, output);
@@ -197,6 +200,7 @@ _gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void 
*mech_data)
     return;
   
   free (state->snonce);
+  free (state->salt);
   scram_free_client_first (&state->cf);
   scram_free_server_first (&state->sf);
   scram_free_client_final (&state->cl);
diff --git a/tests/scram.c b/tests/scram.c
index c259a36..e2858cf 100644
--- a/tests/scram.c
+++ b/tests/scram.c
@@ -35,6 +35,8 @@
 /* "Al\xC2\xAA""dd\xC2\xAD""in\xC2\xAE" */
 #define AUTHZID "joe"
 
+size_t i;
+
 static int
 callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
 {
@@ -55,8 +57,27 @@ callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property 
prop)
       break;
 
     case GSASL_AUTHZID:
-      gsasl_property_set (sctx, prop, AUTHZID);
-      rc = GSASL_OK;
+      if (i & 0x01)
+       {
+         gsasl_property_set (sctx, prop, AUTHZID);
+         rc = GSASL_OK;
+       }
+      break;
+
+    case GSASL_SCRAM_ITER:
+      if (i & 0x02)
+       {
+         gsasl_property_set (sctx, prop, "1234");
+         rc = GSASL_OK;
+       }
+      break;
+
+    case GSASL_SCRAM_SALT:
+      if (i & 0x04)
+       {
+         gsasl_property_set (sctx, prop, "salt");
+         rc = GSASL_OK;
+       }
       break;
 
     default:
@@ -74,7 +95,6 @@ doit (void)
   Gsasl_session *server = NULL, *client = NULL;
   char *s1, *s2;
   size_t s1len, s2len;
-  size_t i;
   int res;
 
   res = gsasl_init (&ctx);
@@ -94,7 +114,7 @@ doit (void)
 
   gsasl_callback_set (ctx, callback);
 
-  for (i = 0; i < 5; i++)
+  for (i = 0; i <= 7; i++)
     {
       if (debug)
        printf ("Iteration %d ...\n", i);


hooks/post-receive
-- 
GNU gsasl




reply via email to

[Prev in Thread] Current Thread [Next in Thread]