diff --git a/NEWS b/NEWS index beadfc3ac..f37deb29e 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Noteworthy changes in version 2.1.0beta3 ----------------------------------------------------- + * Fixed regression in GPG'S secret key export function. + Noteworthy changes in version 2.1.0beta2 (2011-03-08) ----------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index 9a6134d7f..78ddf8d22 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,10 @@ +2011-04-26 Werner Koch + + * cvt-openpgp.c (convert_to_openpgp): Use rfc4880 encoded S2K count. + * protect.c (get_standard_s2k_count_rfc4880): New. + (S2K_DECODE_COUNT): New. + (s2k_hash_passphrase): Use the new macro. + 2011-04-21 Werner Koch * agent.h (server_control_s): Add field cache_ttl_opt_preset. diff --git a/agent/agent.h b/agent/agent.h index 16c9aba56..9aaf26441 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -330,6 +330,7 @@ gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey, /*-- protect.c --*/ unsigned long get_standard_s2k_count (void); +unsigned char get_standard_s2k_count_rfc4880 (void); int agent_protect (const unsigned char *plainkey, const char *passphrase, unsigned char **result, size_t *resultlen); int agent_unprotect (const unsigned char *protectedkey, const char *passphrase, diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 1595a324b..0f3172894 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -1046,7 +1046,10 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, gcry_create_nonce (protect_iv, sizeof protect_iv); gcry_create_nonce (salt, sizeof salt); - s2k_count = get_standard_s2k_count (); + /* We need to use the encoded S2k count. It is not possible to + encode it after it has been used because the encoding procedure + may round the value up. */ + s2k_count = get_standard_s2k_count_rfc4880 (); err = apply_protection (array, npkey, nskey, passphrase, GCRY_CIPHER_AES, protect_iv, sizeof protect_iv, 3, GCRY_MD_SHA1, salt, s2k_count); diff --git a/agent/protect.c b/agent/protect.c index 0b8c9b408..7df82de03 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -41,6 +41,9 @@ #define PROT_CIPHER_STRING "aes" #define PROT_CIPHER_KEYLEN (128/8) +/* Decode an rfc4880 encoded S2K count. */ +#define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) + /* A table containing the information needed to create a protected private key. */ @@ -192,6 +195,33 @@ get_standard_s2k_count (void) } +/* Same as get_standard_s2k_count but return the count in the encoding + as described by rfc4880. */ +unsigned char +get_standard_s2k_count_rfc4880 (void) +{ + unsigned long iterations; + unsigned int count; + unsigned char result; + unsigned char c=0; + + iterations = get_standard_s2k_count (); + if (iterations >= 65011712) + return 255; + + /* Need count to be in the range 16-31 */ + for (count=iterations>>6; count>=32; count>>=1) + c++; + + result = (c<<4)|(count-16); + + if (S2K_DECODE_COUNT(result) < iterations) + result++; + + return result; + +} + /* Calculate the MIC for a private key or shared secret S-expression. @@ -1041,7 +1071,7 @@ s2k_hash_passphrase (const char *passphrase, int hashalgo, unsigned char *key, size_t keylen) { return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt, - (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6), + S2K_DECODE_COUNT (s2kcount), key, keylen); } diff --git a/g10/ChangeLog b/g10/ChangeLog index 8b22df854..86c9b9817 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,8 @@ +2011-04-26 Werner Koch + + * export.c (transfer_format_to_openpgp): Do not apply + encode_s2k_iterations to S2K_COUNT. + 2011-04-25 Werner Koch * delkey.c (do_delete_key): Mark classify_user_id for use with diff --git a/g10/export.c b/g10/export.c index 9f4959e61..2e35eea9f 100644 --- a/g10/export.c +++ b/g10/export.c @@ -626,10 +626,9 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) } /* Do some sanity checks. */ - if (s2k_count <= 1024) + if (s2k_count > 255) { - /* The count must be larger so that encode_s2k_iterations does - not fall into a backward compatibility mode. */ + /* We expect an already encoded S2K count. */ err = gpg_error (GPG_ERR_INV_DATA); goto leave; } @@ -682,7 +681,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) ski->s2k.hash_algo = s2k_algo; assert (sizeof ski->s2k.salt == sizeof s2k_salt); memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt); - ski->s2k.count = encode_s2k_iterations (s2k_count); + ski->s2k.count = s2k_count; assert (ivlen <= sizeof ski->iv); memcpy (ski->iv, iv, ivlen); ski->ivlen = ivlen;