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 + + * protect.c (hash_passphrase): Use the new gcry_kdf_derive. + 2011-03-08 Werner Koch * 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 ], + [ 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 + + * passphrase.c (hash_passphrase): Remove. + (passphrase_to_dek_ext): Use gcry_kdf_derive. + 2011-03-03 Werner Koch * 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);