mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
Implement dynamic S2K count computation.
This commit is contained in:
parent
ed7bf14034
commit
4d693033ab
3
NEWS
3
NEWS
@ -18,6 +18,9 @@ Noteworthy changes in version 2.1.x (under development)
|
|||||||
|
|
||||||
* New GPGSM option --ignore-cert-extension.
|
* 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)
|
Noteworthy changes in version 2.0.13 (2009-09-04)
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
2009-12-14 Werner Koch <wk@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@g10code.com>
|
2009-12-08 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* protect.c (agent_unprotect): Avoid compiler warning.
|
* protect.c (agent_unprotect): Avoid compiler warning.
|
||||||
|
@ -285,6 +285,7 @@ int agent_genkey (ctrl_t ctrl,
|
|||||||
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
||||||
|
|
||||||
/*-- protect.c --*/
|
/*-- protect.c --*/
|
||||||
|
unsigned long get_standard_s2k_count (void);
|
||||||
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
||||||
|
@ -61,6 +61,7 @@ enum cmd_and_opt_values
|
|||||||
oShadow,
|
oShadow,
|
||||||
oShowShadowInfo,
|
oShowShadowInfo,
|
||||||
oShowKeygrip,
|
oShowKeygrip,
|
||||||
|
oS2Kcalibration,
|
||||||
oCanonical,
|
oCanonical,
|
||||||
|
|
||||||
oP12Import,
|
oP12Import,
|
||||||
@ -121,6 +122,8 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
ARGPARSE_c (oP12Export, "p12-export",
|
ARGPARSE_c (oP12Export, "p12-export",
|
||||||
"export a private key pkcs#12 encoded"),
|
"export a private key pkcs#12 encoded"),
|
||||||
|
|
||||||
|
ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
|
||||||
|
|
||||||
ARGPARSE_group (301, N_("@\nOptions:\n ")),
|
ARGPARSE_group (301, N_("@\nOptions:\n ")),
|
||||||
|
|
||||||
ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
|
ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
|
||||||
@ -1061,6 +1064,8 @@ main (int argc, char **argv )
|
|||||||
case oP12Export: cmd = oP12Export; break;
|
case oP12Export: cmd = oP12Export; break;
|
||||||
case oP12Charset: opt_p12_charset = pargs.r.ret_str; 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 oPassphrase: opt_passphrase = pargs.r.ret_str; break;
|
||||||
case oStore: opt_store = 1; break;
|
case oStore: opt_store = 1; break;
|
||||||
case oForce: opt_force = 1; break;
|
case oForce: opt_force = 1; break;
|
||||||
@ -1105,6 +1110,12 @@ main (int argc, char **argv )
|
|||||||
import_p12_file (fname);
|
import_p12_file (fname);
|
||||||
else if (cmd == oP12Export)
|
else if (cmd == oP12Export)
|
||||||
export_p12_file (fname);
|
export_p12_file (fname);
|
||||||
|
else if (cmd == oS2Kcalibration)
|
||||||
|
{
|
||||||
|
if (!opt.verbose)
|
||||||
|
opt.verbose++; /* We need to see something. */
|
||||||
|
get_standard_s2k_count ();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
show_file (fname);
|
show_file (fname);
|
||||||
|
|
||||||
|
148
agent/protect.c
148
agent/protect.c
@ -27,6 +27,11 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
# include <windows.h>
|
||||||
|
#else
|
||||||
|
# include <sys/times.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
|
|
||||||
@ -51,12 +56,133 @@ static struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* 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
|
static int
|
||||||
hash_passphrase (const char *passphrase, int hashalgo,
|
hash_passphrase (const char *passphrase, int hashalgo,
|
||||||
int s2kmode,
|
int s2kmode,
|
||||||
const unsigned char *s2ksalt, unsigned long s2kcount,
|
const unsigned char *s2ksalt, unsigned long s2kcount,
|
||||||
unsigned char *key, size_t keylen);
|
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
|
/* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
|
||||||
@ -193,7 +319,8 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
|
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)
|
if (!rc)
|
||||||
rc = gcry_cipher_setkey (hd, key, keylen);
|
rc = gcry_cipher_setkey (hd, key, keylen);
|
||||||
xfree (key);
|
xfree (key);
|
||||||
@ -757,9 +884,23 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
|||||||
is nothing we should worry about */
|
is nothing we should worry about */
|
||||||
if (s[n] != ')' )
|
if (s[n] != ')' )
|
||||||
return gpg_error (GPG_ERR_INV_SEXP);
|
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);
|
s2kcount = strtoul ((const char*)s, NULL, 10);
|
||||||
if (!s2kcount)
|
if (!s2kcount)
|
||||||
return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
|
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 += n;
|
||||||
s++; /* skip list end */
|
s++; /* skip list end */
|
||||||
|
|
||||||
@ -848,8 +989,7 @@ agent_private_key_type (const unsigned char *privatekey)
|
|||||||
/* Transform a passphrase into a suitable key of length KEYLEN and
|
/* Transform a passphrase into a suitable key of length KEYLEN and
|
||||||
store this key in the caller provided buffer KEY. The caller must
|
store this key in the caller provided buffer KEY. The caller must
|
||||||
provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
|
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
|
that mode an S2KSALT of 8 random bytes and an S2KCOUNT.
|
||||||
value is 96).
|
|
||||||
|
|
||||||
Returns an error code on failure. */
|
Returns an error code on failure. */
|
||||||
static int
|
static int
|
||||||
@ -891,7 +1031,7 @@ hash_passphrase (const char *passphrase, int hashalgo,
|
|||||||
|
|
||||||
if (s2kmode == 3)
|
if (s2kmode == 3)
|
||||||
{
|
{
|
||||||
count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
|
count = s2kcount;
|
||||||
if (count < len2)
|
if (count < len2)
|
||||||
count = len2;
|
count = len2;
|
||||||
}
|
}
|
||||||
|
23
g10/server.c
23
g10/server.c
@ -601,6 +601,24 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||||||
return rc;
|
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. */
|
/* Helper to register our commands with libassuan. */
|
||||||
@ -611,6 +629,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
assuan_handler_t handler;
|
assuan_handler_t handler;
|
||||||
|
assuan_handler_t help;
|
||||||
} table[] = {
|
} table[] = {
|
||||||
{ "RECIPIENT", cmd_recipient },
|
{ "RECIPIENT", cmd_recipient },
|
||||||
{ "SIGNER", cmd_signer },
|
{ "SIGNER", cmd_signer },
|
||||||
@ -628,13 +647,15 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "GENKEY", cmd_genkey },
|
{ "GENKEY", cmd_genkey },
|
||||||
{ "DELKEYS", cmd_delkeys },
|
{ "DELKEYS", cmd_delkeys },
|
||||||
{ "GETINFO", cmd_getinfo },
|
{ "GETINFO", cmd_getinfo },
|
||||||
|
{ "PASSWD", cmd_passwd, hlp_passwd},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
|
||||||
for (i=0; table[i].name; i++)
|
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)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user