[svn] GnuPG - r5226 - in trunk: . agent g10
svn author wk
cvs at cvs.gnupg.org
Mon Dec 14 21:12:57 CET 2009
Author: wk
Date: 2009-12-14 21:12:56 +0100 (Mon, 14 Dec 2009)
New Revision: 5226
Modified:
trunk/NEWS
trunk/agent/ChangeLog
trunk/agent/agent.h
trunk/agent/protect-tool.c
trunk/agent/protect.c
trunk/g10/server.c
Log:
Implement dynamic S2K count computation.
Modified: trunk/agent/ChangeLog
===================================================================
--- trunk/agent/ChangeLog 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/agent/ChangeLog 2009-12-14 20:12:56 UTC (rev 5226)
@@ -1,3 +1,12 @@
+2009-12-14 Werner Koch <wk at g10code.com>
+
+ * protect.c (agent_unprotect): Decode the S2K count here and take
+ care of the new unencoded values. Add a lower limit sanity check.
+ (hash_passphrase): Do not decode here.
+ (get_standard_s2k_count, calibrate_s2k_count): New.
+ (calibrate_get_time, calibrate_elapsed_time): New.
+ (do_encryption): Use get_standard_s2k_count.
+
2009-12-08 Werner Koch <wk at g10code.com>
* protect.c (agent_unprotect): Avoid compiler warning.
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/NEWS 2009-12-14 20:12:56 UTC (rev 5226)
@@ -18,7 +18,10 @@
* New GPGSM option --ignore-cert-extension.
+ * New and changed passphrases are now created with an iteration count
+ requiring about 100ms of CPU work.
+
Noteworthy changes in version 2.0.13 (2009-09-04)
-------------------------------------------------
Modified: trunk/agent/agent.h
===================================================================
--- trunk/agent/agent.h 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/agent/agent.h 2009-12-14 20:12:56 UTC (rev 5226)
@@ -285,6 +285,7 @@
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
/*-- protect.c --*/
+unsigned long get_standard_s2k_count (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,
Modified: trunk/agent/protect-tool.c
===================================================================
--- trunk/agent/protect-tool.c 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/agent/protect-tool.c 2009-12-14 20:12:56 UTC (rev 5226)
@@ -61,6 +61,7 @@
oShadow,
oShowShadowInfo,
oShowKeygrip,
+ oS2Kcalibration,
oCanonical,
oP12Import,
@@ -120,6 +121,8 @@
"import a pkcs#12 encoded private key"),
ARGPARSE_c (oP12Export, "p12-export",
"export a private key pkcs#12 encoded"),
+
+ ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
@@ -1061,6 +1064,8 @@
case oP12Export: cmd = oP12Export; break;
case oP12Charset: opt_p12_charset = pargs.r.ret_str; break;
+ case oS2Kcalibration: cmd = oS2Kcalibration; break;
+
case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
case oStore: opt_store = 1; break;
case oForce: opt_force = 1; break;
@@ -1105,6 +1110,12 @@
import_p12_file (fname);
else if (cmd == oP12Export)
export_p12_file (fname);
+ else if (cmd == oS2Kcalibration)
+ {
+ if (!opt.verbose)
+ opt.verbose++; /* We need to see something. */
+ get_standard_s2k_count ();
+ }
else
show_file (fname);
Modified: trunk/agent/protect.c
===================================================================
--- trunk/agent/protect.c 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/agent/protect.c 2009-12-14 20:12:56 UTC (rev 5226)
@@ -27,6 +27,11 @@
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#else
+# include <sys/times.h>
+#endif
#include "agent.h"
@@ -51,13 +56,134 @@
};
+/* A helper object for time measurement. */
+struct calibrate_time_s
+{
+#ifdef HAVE_W32_SYSTEM
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+#else
+ clock_t ticks;
+#endif
+};
+
+
static int
hash_passphrase (const char *passphrase, int hashalgo,
int s2kmode,
const unsigned char *s2ksalt, unsigned long s2kcount,
unsigned char *key, size_t keylen);
+/* Get the process time and store it in DATA. */
+static void
+calibrate_get_time (struct calibrate_time_s *data)
+{
+#ifdef HAVE_W32_SYSTEM
+ GetProcessTimes (GetCurrentProcess (),
+ &data->creation_time, &data->exit_time,
+ &data->kernel_time, &data->user_time);
+#else
+ struct tms tmp;
+
+ times (&tmp);
+ data->ticks = tmp.tms_utime;
+#endif
+}
+
+static unsigned long
+calibrate_elapsed_time (struct calibrate_time_s *starttime)
+{
+ struct calibrate_time_s stoptime;
+
+ calibrate_get_time (&stoptime);
+#ifdef HAVE_W32_SYSTEM
+ {
+ unsigned long long t1, t2;
+
+ t1 = (((unsigned long long)starttime->kernel_time.dwHighDateTime << 32)
+ + starttime->kernel_time.dwLowDateTime);
+ t1 += (((unsigned long long)starttime->user_time.dwHighDateTime << 32)
+ + starttime->user_time.dwLowDateTime);
+ t2 = (((unsigned long long)stoptime.kernel_time.dwHighDateTime << 32)
+ + stoptime.kernel_time.dwLowDateTime);
+ t2 += (((unsigned long long)stoptime.user_time.dwHighDateTime << 32)
+ + stoptime.user_time.dwLowDateTime);
+ return (unsigned long)((t2 - t1)/10000);
+ }
+#else
+ return (unsigned long)((((double) (stoptime.ticks - starttime->ticks))
+ /CLOCKS_PER_SEC)*10000000);
+#endif
+}
+
+
+/* Run a test hashing for COUNT and return the time required in
+ milliseconds. */
+static unsigned long
+calibrate_s2k_count_one (unsigned long count)
+{
+ int rc;
+ char keybuf[PROT_CIPHER_KEYLEN];
+ struct calibrate_time_s starttime;
+
+ calibrate_get_time (&starttime);
+ rc = hash_passphrase ("123456789abcdef0", GCRY_MD_SHA1,
+ 3, "saltsalt", count, keybuf, sizeof keybuf);
+ if (rc)
+ BUG ();
+ return calibrate_elapsed_time (&starttime);
+}
+
+
+/* Measure the time we need to do the hash operations and deduce an
+ S2K count which requires about 100ms of time. */
+static unsigned long
+calibrate_s2k_count (void)
+{
+ unsigned long count;
+ unsigned long ms;
+
+ for (count = 65536; count; count *= 2)
+ {
+ ms = calibrate_s2k_count_one (count);
+ if (opt.verbose > 1)
+ log_info ("S2K calibration: %lu -> %lums\n", count, ms);
+ if (ms > 100)
+ break;
+ }
+
+ count = (unsigned long)(((double)count / ms) * 100);
+ count /= 1024;
+ count *= 1024;
+ if (count < 65536)
+ count = 65536;
+
+ if (opt.verbose)
+ {
+ ms = calibrate_s2k_count_one (count);
+ log_info ("S2K calibration: %lu iterations for %lums\n", count, ms);
+ }
+
+ return count;
+}
+
+
+
+/* Return the standard S2K count. */
+unsigned long
+get_standard_s2k_count (void)
+{
+ static unsigned long count;
+
+ if (!count)
+ count = calibrate_s2k_count ();
+
+ /* Enforce a lower limit. */
+ return count < 65536 ? 65536 : count;
+}
+
+
+
/* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
a 20 byte buffer. This function is suitable for any algorithms. */
@@ -193,7 +319,8 @@
else
{
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
- 3, iv+2*blklen, 96, key, keylen);
+ 3, iv+2*blklen,
+ get_standard_s2k_count (), key, keylen);
if (!rc)
rc = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
@@ -757,9 +884,23 @@
is nothing we should worry about */
if (s[n] != ')' )
return gpg_error (GPG_ERR_INV_SEXP);
+
+ /* Old versions of gpg-agent used the funny floating point number in
+ a byte encoding as specified by OpenPGP. However this is not
+ needed and thus we now store it as a plain unsigned integer. We
+ can easily distinguish the old format by looking at its value:
+ Less than 256 is an old-style encoded number; other values are
+ plain integers. In any case we check that they are at least
+ 65536 because we never used a lower value in the past and we
+ should have a lower limit. */
s2kcount = strtoul ((const char*)s, NULL, 10);
if (!s2kcount)
return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+ if (s2kcount < 256)
+ s2kcount = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
+ if (s2kcount < 65536)
+ return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+
s += n;
s++; /* skip list end */
@@ -848,8 +989,7 @@
/* Transform a passphrase into a suitable key of length KEYLEN and
store this key in the caller provided buffer KEY. The caller must
provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
- that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
- value is 96).
+ that mode an S2KSALT of 8 random bytes and an S2KCOUNT.
Returns an error code on failure. */
static int
@@ -891,7 +1031,7 @@
if (s2kmode == 3)
{
- count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
+ count = s2kcount;
if (count < len2)
count = len2;
}
Modified: trunk/g10/server.c
===================================================================
--- trunk/g10/server.c 2009-12-14 12:33:23 UTC (rev 5225)
+++ trunk/g10/server.c 2009-12-14 20:12:56 UTC (rev 5226)
@@ -601,7 +601,25 @@
return rc;
}
+static const char hlp_passwd[] =
+ "PASSWD <userID>\n"
+ "\n"
+ "Change the passphrase of the secret key for USERID.";
+static gpg_error_t
+cmd_passwd (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ line = skip_options (line);
+
+ err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ return err;
+}
+
+
+
/* Helper to register our commands with libassuan. */
static int
@@ -611,6 +629,7 @@
{
const char *name;
assuan_handler_t handler;
+ assuan_handler_t help;
} table[] = {
{ "RECIPIENT", cmd_recipient },
{ "SIGNER", cmd_signer },
@@ -628,13 +647,15 @@
{ "GENKEY", cmd_genkey },
{ "DELKEYS", cmd_delkeys },
{ "GETINFO", cmd_getinfo },
+ { "PASSWD", cmd_passwd, hlp_passwd},
{ NULL }
};
int i, rc;
for (i=0; table[i].name; i++)
{
- rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
+ rc = assuan_register_command (ctx, table[i].name,
+ table[i].handler, table[i].help);
if (rc)
return rc;
}
More information about the Gnupg-commits
mailing list