aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2011-03-10 17:39:34 +0000
committerWerner Koch <[email protected]>2011-03-10 17:39:34 +0000
commitb9bcc77d6ca13463c2e4bede91fc1782795f1eae (patch)
tree9b4de77f9fef5d3684ff2d52a06aab14f12a83a0
parentSupport pkcs#12 import of PBES2 encoded data. (diff)
downloadgnupg-b9bcc77d6ca13463c2e4bede91fc1782795f1eae.tar.gz
gnupg-b9bcc77d6ca13463c2e4bede91fc1782795f1eae.zip
Make use of gcry_kdf_derive.
Factoring common code out is always a Good Thing. Also added a configure test to print an error if gcry_kdf_derive is missing in Libgcrypt.
-rw-r--r--agent/ChangeLog4
-rw-r--r--agent/protect.c69
-rw-r--r--configure.ac25
-rw-r--r--g10/ChangeLog5
-rw-r--r--g10/passphrase.c96
5 files changed, 59 insertions, 140 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index b636c50e3..5f143069c 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,7 @@
+2011-03-10 Werner Koch <[email protected]>
+
+ * protect.c (hash_passphrase): Use the new gcry_kdf_derive.
+
2011-03-08 Werner Koch <[email protected]>
* cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: Remove.
diff --git a/agent/protect.c b/agent/protect.c
index 94de89311..0b8c9b408 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -1023,70 +1023,13 @@ hash_passphrase (const char *passphrase, int hashalgo,
unsigned long s2kcount,
unsigned char *key, size_t keylen)
{
- int rc;
- gcry_md_hd_t md;
- int pass, i;
- int used = 0;
- int pwlen = strlen (passphrase);
-
- if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
- || !hashalgo || !keylen || !key || !passphrase)
- return gpg_error (GPG_ERR_INV_VALUE);
- if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
- if (rc)
- return rc;
-
- for (pass=0; used < keylen; pass++)
- {
- if (pass)
- {
- gcry_md_reset (md);
- for (i=0; i < pass; i++) /* preset the hash context */
- gcry_md_putc (md, 0);
- }
-
- if (s2kmode == 1 || s2kmode == 3)
- {
- int len2 = pwlen + 8;
- unsigned long count = len2;
-
- if (s2kmode == 3)
- {
- count = s2kcount;
- if (count < len2)
- count = len2;
- }
- while (count > len2)
- {
- gcry_md_write (md, s2ksalt, 8);
- gcry_md_write (md, passphrase, pwlen);
- count -= len2;
- }
- if (count < 8)
- gcry_md_write (md, s2ksalt, count);
- else
- {
- gcry_md_write (md, s2ksalt, 8);
- count -= 8;
- gcry_md_write (md, passphrase, count);
- }
- }
- else
- gcry_md_write (md, passphrase, pwlen);
-
- gcry_md_final (md);
- i = gcry_md_get_algo_dlen (hashalgo);
- if (i > keylen - used)
- i = keylen - used;
- memcpy (key+used, gcry_md_read (md, hashalgo), i);
- used += i;
- }
- gcry_md_close(md);
- return 0;
+ return gcry_kdf_derive (passphrase, strlen (passphrase),
+ s2kmode == 3? GCRY_KDF_ITERSALTED_S2K :
+ s2kmode == 1? GCRY_KDF_SALTED_S2K :
+ s2kmode == 0? GCRY_KDF_SIMPLE_S2K : GCRY_KDF_NONE,
+ hashalgo, s2ksalt, 8, s2kcount,
+ keylen, key);
}
diff --git a/configure.ac b/configure.ac
index f265dc393..ab40c6fd0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -742,6 +742,22 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION",
have_libgcrypt=yes,have_libgcrypt=no)
+# FIxme: Remove this test after libgcrypt 1.5.0 has been released.
+AC_CACHE_CHECK([whether Libgcrypt has gcry_kdf_derive],
+ gnupg_cv_gcry_kdf_derive,
+ [ _gnupg_gcry_save_cflags=$CFLAGS
+ _gnupg_gcry_save_libs=$LIBS
+ CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
+ LIBS="$LIBS $LIBGCRYPT_LIBS"
+ AC_TRY_LINK(
+ [#include <gcrypt.h>],
+ [ return gcry_kdf_derive (NULL,0,0,0,NULL,0,0,0,NULL); ],
+ gnupg_cv_gcry_kdf_derive=yes,
+ gnupg_cv_gcry_kdf_derive=no)
+ LIBS=$_gnupg_gcry_save_libs
+ CFLAGS=$_gnupg_gcry_save_cflags])
+
+
#
# libassuan is used for IPC
#
@@ -1605,6 +1621,15 @@ if test "$have_libgcrypt" = "no"; then
*** ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/
*** (at least version $NEED_LIBGCRYPT_VERSION using API $NEED_LIBGCRYPT_API is required.)
***]])
+elif test "$gnupg_cv_gcry_kdf_derive" = no; then
+ die=yes
+ AC_MSG_NOTICE([[
+***
+*** Libgcrypt 1.5.0 has not yet been released and thus the API
+*** is a bit in a flux. Your version misses the function
+*** gcry_kdf_derive
+*** You need to install a newer Libgcrypt version.
+***]])
fi
if test "$have_libassuan" = "no"; then
die=yes
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 902607715..f9edf5781 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,8 @@
+2011-03-10 Werner Koch <[email protected]>
+
+ * passphrase.c (hash_passphrase): Remove.
+ (passphrase_to_dek_ext): Use gcry_kdf_derive.
+
2011-03-03 Werner Koch <[email protected]>
* keylist.c (print_card_key_info): Re-implement using the agent.
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 8065810c9..481d29ed9 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -1,6 +1,6 @@
/* passphrase.c - Get a passphrase
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- * 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+ * 2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -101,81 +101,6 @@ encode_s2k_iterations (int iterations)
}
-
-/* Hash a passphrase using the supplied s2k.
- Always needs: dek->algo, s2k->mode, s2k->hash_algo. */
-static void
-hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k)
-{
- gcry_md_hd_t md;
- int pass, i;
- int used = 0;
- int pwlen = strlen(pw);
-
- assert ( s2k->hash_algo );
- dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo);
- if ( !(dek->keylen > 0 && dek->keylen <= DIM(dek->key)) )
- BUG();
-
- if (gcry_md_open (&md, s2k->hash_algo, 1))
- BUG ();
- for (pass=0; used < dek->keylen ; pass++ )
- {
- if ( pass )
- {
- gcry_md_reset (md);
- for (i=0; i < pass; i++ ) /* Preset the hash context. */
- gcry_md_putc (md, 0 );
- }
-
- if ( s2k->mode == 1 || s2k->mode == 3 )
- {
- int len2 = pwlen + 8;
- ulong count = len2;
-
- if ( s2k->mode == 3 )
- {
- count = S2K_DECODE_COUNT(s2k->count);
- if ( count < len2 )
- count = len2;
- }
-
- /* Fixme: To avoid DoS attacks by sending an sym-encrypted
- packet with a very high S2K count, we should either cap
- the iteration count or CPU seconds based timeout. */
-
- /* A little bit complicated because we need a ulong for count. */
- while ( count > len2 ) /* maybe iterated+salted */
- {
- gcry_md_write ( md, s2k->salt, 8 );
- gcry_md_write ( md, pw, pwlen );
- count -= len2;
- }
- if ( count < 8 )
- gcry_md_write ( md, s2k->salt, count );
- else
- {
- gcry_md_write ( md, s2k->salt, 8 );
- count -= 8;
- gcry_md_write ( md, pw, count );
- }
- }
- else
- gcry_md_write ( md, pw, pwlen );
- gcry_md_final( md );
-
- i = gcry_md_get_algo_dlen ( s2k->hash_algo );
- if ( i > dek->keylen - used )
- i = dek->keylen - used;
-
- memcpy (dek->key+used, gcry_md_read (md, s2k->hash_algo), i);
- used += i;
- }
- gcry_md_close(md);
-}
-
-
-
int
have_static_passphrase()
{
@@ -655,7 +580,24 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
if ( (!pw || !*pw) && (mode == 2 || mode == 4))
dek->keylen = 0;
else
- hash_passphrase (dek, pw, s2k);
+ {
+ dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo);
+ if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key)))
+ BUG ();
+ if (gcry_kdf_derive (pw, strlen (pw),
+ s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K :
+ s2k->mode == 1? GCRY_KDF_SALTED_S2K :
+ /* */ GCRY_KDF_SIMPLE_S2K,
+ s2k->hash_algo, s2k->salt, 8,
+ S2K_DECODE_COUNT(s2k->count),
+ dek->keylen, dek->key))
+ {
+ xfree (pw);
+ xfree (dek);
+ write_status( STATUS_MISSING_PASSPHRASE );
+ return NULL;
+ }
+ }
if (s2k_cacheid)
memcpy (dek->s2k_cacheid, s2k_cacheid, sizeof dek->s2k_cacheid);
xfree(last_pw);