Fix a longstanding algorithmic flaw in PKCS#5 key generation.

The existing pkcs5_pbdkf2 keygen method is retained functionally
as-is, for compatibility with existing params files.  The corrected
algorithm, which is now the default for new params file generation, is
called pkcs5_pbkdf2/sha1.

NB. The backwards compatibility for the miscreant keygen method will
be removed at the same time as support for the previous parameters
file syntax. Sometime between now and then, users should update their
params files using -G, which will create a new params file including
an xor value so that the resulting generated key is the same; they
should also

Problem discovery and 2-char algorithm fix by Charles Blundell, messy
compat goop by me, long complicated names by Roland Dowdeswell.

Update manpage accordingly and bump date.
This commit is contained in:
dan 2004-03-17 01:29:13 +00:00
parent d25d657094
commit 064ca2e3d1
6 changed files with 85 additions and 38 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: cgdconfig.8,v 1.16 2003/09/23 21:25:20 wiz Exp $
.\" $NetBSD: cgdconfig.8,v 1.17 2004/03/17 01:29:13 dan Exp $
.\"
.\" Copyright (c) 2002, The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -34,7 +34,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 23, 2003
.Dd March 17, 2004
.Dt CGDCONFIG 8
.Os
.Sh NAME
@ -104,7 +104,7 @@ Generate a paramsfile (to stdout).
.It Fl i Ar ivmeth
Specify the IV method (default: encblkno).
.It Fl k Ar kgmeth
Specify the key generation method (default: pkcs5_pbkdf2).
Specify the key generation method (default: pkcs5_pbkdf2/sha1).
.It Fl o Ar outfile
When generating a
.Ar paramsfile ,
@ -132,14 +132,22 @@ To generate the key which it will use,
evaluates all of the key generation methods in the parameters file
and uses the exclusive-or of the outputs of all the methods.
The methods and descriptions are as follows:
.Bl -tag -width indentxxxxxx
.It pkcs5_pbkdf2
.Bl -tag -width indentxxxxxxxxxxx
.It pkcs5_pbkdf2/sha1
This method requires a passphrase which is entered at configuration
time.
It is a salted hmac-based scheme detailed in
.Dq PKCS#5 v2.0: Password-Based Cryptography Standard ,
RSA Laboratories, March 25, 1999, pages 8-10.
PKCS #5 was also republished as RFC 2898.
.It pkcs5_pbkdf2
This is an earlier, slightly incorrect and deprecated implementation
of the above algorithm.
It is retained for backwards compatibility with existing parameters
files, and will be removed. Existing parameters files should be
converted to use the correct method using the
.Fl G
option, and a new passphrase.
.It randomkey
The method simply reads
.Pa /dev/random
@ -173,7 +181,8 @@ scan for a valid FFS file system.
.It re-enter
prompt for passphrase twice, and ensure entered passphrases are
identical.
This method only works with the pkcs5_pbkdf2 key generator.
This method only works with the pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2 key
generators.
.El
.Ss /etc/cgd/cgd.conf
The file
@ -267,9 +276,9 @@ The keygen statement's statement block may contain the following statements:
.It key Ar string
The key. Only used for the storedkey key generation method.
.It iterations Ar integer
The number of iterations. Only used for pkcs5_pbkdf2.
The number of iterations. Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2.
.It salt Ar base64
The salt. Only used for pkcs5_pbkdf2.
The salt. Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2.
.El
.Sh FILES
.Bl -tag -width indentxxxxxxxxxxxxxxxxxx -compact
@ -325,7 +334,7 @@ An example parameters file which uses PKCS#5 PBKDF2:
iv-method encblkno;
keylength 128;
verify_method none;
keygen pkcs5_pbkdf2 {
keygen pkcs5_pbkdf2/sha1 {
iterations 39361;
salt AAAAgMoHiYonye6Kog \\
dYJAobCHE=;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cgdconfig.c,v 1.9 2003/09/23 17:24:46 cb Exp $ */
/* $NetBSD: cgdconfig.c,v 1.10 2004/03/17 01:29:13 dan Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
__COPYRIGHT(
"@(#) Copyright (c) 2002, 2003\
The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: cgdconfig.c,v 1.9 2003/09/23 17:24:46 cb Exp $");
__RCSID("$NetBSD: cgdconfig.c,v 1.10 2004/03/17 01:29:13 dan Exp $");
#endif
#include <err.h>
@ -97,7 +97,7 @@ static int configure_params(int, const char *, const char *,
static bits_t *getkey(const char *, struct keygen *, int);
static bits_t *getkey_storedkey(const char *, struct keygen *, int);
static bits_t *getkey_randomkey(const char *, struct keygen *, int);
static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, int);
static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, int, int);
static int opendisk_werror(const char *, char *, int);
static int unconfigure_fd(int);
static int verify(struct params *, int);
@ -257,8 +257,12 @@ getkey(const char *dev, struct keygen *kg, int len)
case KEYGEN_RANDOMKEY:
tmp = getkey_randomkey(dev, kg, len);
break;
case KEYGEN_PKCS5_PBKDF2:
tmp = getkey_pkcs5_pbkdf2(dev, kg, len);
case KEYGEN_PKCS5_PBKDF2_SHA1:
tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
break;
/* provide backwards compatibility for old config files */
case KEYGEN_PKCS5_PBKDF2_OLD:
tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
break;
default:
warnx("unrecognised keygen method %d in getkey()",
@ -294,8 +298,16 @@ getkey_randomkey(const char *target, struct keygen *kg, int keylen)
}
/*ARGSUSED*/
/*
* XXX take, and pass through, a compat flag that indicates whether we
* provide backwards compatibility with a previous bug. The previous
* behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
* non-zero compat flag. The new default, and correct keygen method is
* called pcks5_pbkdf2/sha1. When the old method is removed, so will
* be the compat argument.
*/
static bits_t *
getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, int keylen)
getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, int keylen, int compat)
{
bits_t *ret;
char *passp;
@ -306,7 +318,7 @@ getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, int keylen)
passp = getpass(buf);
if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), passp, strlen(passp),
bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
kg->kg_iterations)) {
kg->kg_iterations, compat)) {
warnx("failed to generate PKCS#5 PBKDF2 key");
return NULL;
}
@ -641,14 +653,16 @@ verify_reenter(struct params *p)
ret = 0;
for (kg = p->keygen; kg && !ret; kg = kg->next) {
if (kg->kg_method != KEYGEN_PKCS5_PBKDF2)
if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) &&
(kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD ))
continue;
orig_key = kg->kg_key;
kg->kg_key = NULL;
/* add a compat flag till the _OLD method goes away */
key = getkey_pkcs5_pbkdf2("re-enter device", kg,
bits_len(orig_key));
bits_len(orig_key), kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD);
ret = !bits_match(key, orig_key);
bits_free(key);
@ -676,7 +690,7 @@ generate(struct params *p, int argc, char **argv, const char *outfile)
return ret;
if (!p->keygen) {
p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2);
p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
if (!p->keygen)
return -1;
}
@ -737,7 +751,7 @@ generate_convert(struct params *p, int argc, char **argv, const char *outfile)
params_free(oldp);
if (!p->keygen) {
p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2);
p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
if (!p->keygen)
return -1;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.c,v 1.8 2003/09/23 17:24:46 cb Exp $ */
/* $NetBSD: params.c,v 1.9 2004/03/17 01:29:13 dan Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: params.c,v 1.8 2003/09/23 17:24:46 cb Exp $");
__RCSID("$NetBSD: params.c,v 1.9 2004/03/17 01:29:13 dan Exp $");
#endif
#include <sys/types.h>
@ -333,7 +333,7 @@ keygen_verify(const struct keygen *kg)
if (!kg)
return 1;
switch (kg->kg_method) {
case KEYGEN_PKCS5_PBKDF2:
case KEYGEN_PKCS5_PBKDF2_OLD:
if (kg->kg_iterations == -1) {
warnx("keygen pkcs5_pbkdf2 must provide `iterations'");
return 0;
@ -345,6 +345,18 @@ keygen_verify(const struct keygen *kg)
return 0;
}
break;
case KEYGEN_PKCS5_PBKDF2_SHA1:
if (kg->kg_iterations == -1) {
warnx("keygen pkcs5_pbkdf2/sha1 must provide `iterations'");
return 0;
}
if (kg->kg_key)
warnx("keygen pkcs5_pbkdf2/sha1 does not need a `key'");
if (!kg->kg_salt) {
warnx("keygen pkcs5_pbkdf2/sha1 must provide a salt");
return 0;
}
break;
case KEYGEN_STOREDKEY:
if (kg->kg_iterations != -1)
warnx("keygen storedkey does not need `iterations'");
@ -397,7 +409,8 @@ keygen_filldefaults(struct keygen *kg, int keylen)
switch (kg->kg_method) {
case KEYGEN_RANDOMKEY:
break;
case KEYGEN_PKCS5_PBKDF2:
case KEYGEN_PKCS5_PBKDF2_OLD:
case KEYGEN_PKCS5_PBKDF2_SHA1:
kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN);
kg->kg_iterations =
pkcs5_pbkdf2_calibrate(keylen, DEFAULT_ITERATION_TIME);
@ -456,7 +469,9 @@ keygen_method(string_t *in)
const char *kgm = string_tocharstar(in);
if (!strcmp("pkcs5_pbkdf2", kgm))
kg->kg_method = KEYGEN_PKCS5_PBKDF2;
kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD;
if (!strcmp("pkcs5_pbkdf2/sha1", kgm))
kg->kg_method = KEYGEN_PKCS5_PBKDF2_SHA1;
if (!strcmp("randomkey", kgm))
kg->kg_method = KEYGEN_RANDOMKEY;
if (!strcmp("storedkey", kgm))
@ -670,12 +685,18 @@ keygen_fput(struct keygen *kg, int ts, FILE *f)
case KEYGEN_RANDOMKEY:
fprintf(f, "randomkey;\n");
break;
case KEYGEN_PKCS5_PBKDF2:
case KEYGEN_PKCS5_PBKDF2_OLD:
fprintf(f, "pkcs5_pbkdf2 {\n");
print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
fprintf(f, "};\n");
break;
case KEYGEN_PKCS5_PBKDF2_SHA1:
fprintf(f, "pkcs5_pbkdf2/sha1 {\n");
print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
fprintf(f, "};\n");
break;
default:
fprintf(stderr, "keygen_fput: %d not a valid method\n",
kg->kg_method);

View File

@ -1,4 +1,4 @@
/* $NetBSD: params.h,v 1.5 2003/09/23 17:24:46 cb Exp $ */
/* $NetBSD: params.h,v 1.6 2004/03/17 01:29:13 dan Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -62,10 +62,11 @@ struct params {
/* key generation methods */
#define KEYGEN_UNKNOWN 0x0
#define KEYGEN_RANDOMKEY 0x1
#define KEYGEN_PKCS5_PBKDF2 0x2
#define KEYGEN_STOREDKEY 0x3
#define KEYGEN_UNKNOWN 0x0
#define KEYGEN_RANDOMKEY 0x1
#define KEYGEN_PKCS5_PBKDF2_OLD 0x2
#define KEYGEN_STOREDKEY 0x3
#define KEYGEN_PKCS5_PBKDF2_SHA1 0x5
/* verification methods */

View File

@ -1,4 +1,4 @@
/* $NetBSD: pkcs5_pbkdf2.c,v 1.4 2003/09/25 01:43:12 cb Exp $ */
/* $NetBSD: pkcs5_pbkdf2.c,v 1.5 2004/03/17 01:29:13 dan Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -53,7 +53,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: pkcs5_pbkdf2.c,v 1.4 2003/09/25 01:43:12 cb Exp $");
__RCSID("$NetBSD: pkcs5_pbkdf2.c,v 1.5 2004/03/17 01:29:13 dan Exp $");
#endif
#include <sys/resource.h>
@ -127,7 +127,7 @@ prf_iterate(u_int8_t *r, const u_int8_t *P, int Plen,
int
pkcs5_pbkdf2(u_int8_t **r, int dkLen, const u_int8_t *P, int Plen,
const u_int8_t *S, int Slen, int c)
const u_int8_t *S, int Slen, int c, int compat)
{
int i;
int l;
@ -150,7 +150,8 @@ pkcs5_pbkdf2(u_int8_t **r, int dkLen, const u_int8_t *P, int Plen,
/* Step 3 */
for (i=0; i < l; i++)
prf_iterate(*r + (PRF_BLOCKLEN * i), P, Plen, S, Slen, c, i);
prf_iterate(*r + (PRF_BLOCKLEN * i), P, Plen, S, Slen, c,
(compat?i:i+1));
/* Step 4 and 5
* by the structure of the code, we do not need to concatenate
@ -194,7 +195,8 @@ pkcs5_pbkdf2_time(int dkLen, int c)
u_int8_t S[CAL_SALTLEN];
getrusage(RUSAGE_SELF, &start);
ret = pkcs5_pbkdf2(&r, dkLen, P, sizeof(P), S, sizeof(S), c);
/* XXX compat flag at end to be removed when _OLD keygen method is */
ret = pkcs5_pbkdf2(&r, dkLen, P, sizeof(P), S, sizeof(S), c, 0);
if (ret)
return ret;
getrusage(RUSAGE_SELF, &end);

View File

@ -1,4 +1,4 @@
/* $NetBSD: pkcs5_pbkdf2.h,v 1.2 2003/03/24 02:02:51 elric Exp $ */
/* $NetBSD: pkcs5_pbkdf2.h,v 1.3 2004/03/17 01:29:13 dan Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
__BEGIN_DECLS
int pkcs5_pbkdf2(u_int8_t **, int, const u_int8_t *, int,
const u_int8_t *, int, int);
const u_int8_t *, int, int, int);
int pkcs5_pbkdf2_calibrate(int, int);
__END_DECLS
#endif