From 064ca2e3d1b2a3e07f905221c177fb5572bcda02 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 17 Mar 2004 01:29:13 +0000 Subject: [PATCH] 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. --- sbin/cgdconfig/cgdconfig.8 | 27 +++++++++++++++++--------- sbin/cgdconfig/cgdconfig.c | 36 ++++++++++++++++++++++++----------- sbin/cgdconfig/params.c | 33 ++++++++++++++++++++++++++------ sbin/cgdconfig/params.h | 11 ++++++----- sbin/cgdconfig/pkcs5_pbkdf2.c | 12 +++++++----- sbin/cgdconfig/pkcs5_pbkdf2.h | 4 ++-- 6 files changed, 85 insertions(+), 38 deletions(-) diff --git a/sbin/cgdconfig/cgdconfig.8 b/sbin/cgdconfig/cgdconfig.8 index 459f0fd6acbe..52414e055bbb 100644 --- a/sbin/cgdconfig/cgdconfig.8 +++ b/sbin/cgdconfig/cgdconfig.8 @@ -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=; diff --git a/sbin/cgdconfig/cgdconfig.c b/sbin/cgdconfig/cgdconfig.c index 06fb5cc705da..397c3c6affb8 100644 --- a/sbin/cgdconfig/cgdconfig.c +++ b/sbin/cgdconfig/cgdconfig.c @@ -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 @@ -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; } diff --git a/sbin/cgdconfig/params.c b/sbin/cgdconfig/params.c index 10550941249c..e0537862c0b0 100644 --- a/sbin/cgdconfig/params.c +++ b/sbin/cgdconfig/params.c @@ -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 #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 @@ -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); diff --git a/sbin/cgdconfig/params.h b/sbin/cgdconfig/params.h index d8e837741b1f..9b158f4b909e 100644 --- a/sbin/cgdconfig/params.h +++ b/sbin/cgdconfig/params.h @@ -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 */ diff --git a/sbin/cgdconfig/pkcs5_pbkdf2.c b/sbin/cgdconfig/pkcs5_pbkdf2.c index 6f15df6f88d8..0dcb90b35f69 100644 --- a/sbin/cgdconfig/pkcs5_pbkdf2.c +++ b/sbin/cgdconfig/pkcs5_pbkdf2.c @@ -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 #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 @@ -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); diff --git a/sbin/cgdconfig/pkcs5_pbkdf2.h b/sbin/cgdconfig/pkcs5_pbkdf2.h index f169617604fc..443e3e4298cd 100644 --- a/sbin/cgdconfig/pkcs5_pbkdf2.h +++ b/sbin/cgdconfig/pkcs5_pbkdf2.h @@ -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