diff options
author | Greg Hudson <ghudson@mit.edu> | 2015-12-07 11:16:06 -0500 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2016-10-03 15:38:10 -0400 |
commit | dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0 (patch) | |
tree | e859856130c7093474bcf7e1099ac647abe39f49 | |
parent | c438227afd763997c131339c1476f61d1628a20d (diff) | |
download | krb5-dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0.zip krb5-dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0.tar.gz krb5-dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0.tar.bz2 |
Enable PBKDF2 with SHA-256 and SHA-384
Rename krb5int_pbkdf2_hmac_sha1() to krb5int_pbkdf2_hmac() and add a
hash parameter. In the OpenSSL implementation, look up the
corresponding PBKDF2 parameter based on the hash pointer. In
pbkdf2_string_to_key(), pass the hash function for the key type if one
is present, and use SHA-1 if it does not (as for the Camellia
enctypes).
In the builtin implementation, use the hash provider instead of
assuming SHA-1. Remove the functional parameterization of the PRF and
turn it into an hmac() helper function. Use krb5int_hmac_keyblock()
to remove the need for a krb5_key object containing the password.
Rename the internal function from krb5int_pbkdf2() to pbkdf2().
ticket: 8490
-rw-r--r-- | src/lib/crypto/builtin/pbkdf2.c | 93 | ||||
-rw-r--r-- | src/lib/crypto/krb/crypto_int.h | 12 | ||||
-rw-r--r-- | src/lib/crypto/krb/s2k_pbkdf2.c | 4 | ||||
-rw-r--r-- | src/lib/crypto/openssl/pbkdf2.c | 27 |
4 files changed, 68 insertions, 68 deletions
diff --git a/src/lib/crypto/builtin/pbkdf2.c b/src/lib/crypto/builtin/pbkdf2.c index e6d13f6..6a97270 100644 --- a/src/lib/crypto/builtin/pbkdf2.c +++ b/src/lib/crypto/builtin/pbkdf2.c @@ -46,12 +46,6 @@ typedef krb5_error_code (*prf_fn)(krb5_key pass, krb5_data *salt, krb5_data *out); -/* Not exported, for now. */ -static krb5_error_code -krb5int_pbkdf2 (prf_fn prf, size_t hlen, krb5_key pass, - const krb5_data *salt, unsigned long count, - const krb5_data *output); - static int debug_hmac = 0; static void printd (const char *descr, krb5_data *d) { @@ -75,9 +69,32 @@ static void printd (const char *descr, krb5_data *d) { printf("\n"); } +/* + * Implements the hmac-sha1 PRF. pass has been pre-hashed (if + * necessary) and converted to a key already; salt has had the block + * index appended to the original salt. + */ +static krb5_error_code +hmac(const struct krb5_hash_provider *hash, krb5_keyblock *pass, + krb5_data *salt, krb5_data *out) +{ + krb5_error_code err; + krb5_crypto_iov iov; + + if (debug_hmac) + printd(" hmac input", salt); + iov.flags = KRB5_CRYPTO_TYPE_DATA; + iov.data = *salt; + err = krb5int_hmac_keyblock(hash, pass, &iov, 1, out); + if (err == 0 && debug_hmac) + printd(" hmac output", out); + return err; +} + static krb5_error_code -F(char *output, char *u_tmp1, char *u_tmp2, prf_fn prf, size_t hlen, - krb5_key pass, const krb5_data *salt, unsigned long count, int i) +F(char *output, char *u_tmp1, char *u_tmp2, + const struct krb5_hash_provider *hash, size_t hlen, krb5_keyblock *pass, + const krb5_data *salt, unsigned long count, int i) { unsigned char ibytes[4]; size_t tlen; @@ -111,7 +128,7 @@ F(char *output, char *u_tmp1, char *u_tmp2, prf_fn prf, size_t hlen, #if 0 printf("F: computing hmac #1 (U_1) with %s\n", pdata.contents); #endif - err = (*prf)(pass, &sdata, &out); + err = hmac(hash, pass, &sdata, &out); if (err) return err; #if 0 @@ -126,7 +143,7 @@ F(char *output, char *u_tmp1, char *u_tmp2, prf_fn prf, size_t hlen, printf("F: computing hmac #%d (U_%d)\n", j, j); #endif memcpy(u_tmp2, u_tmp1, hlen); - err = (*prf)(pass, &sdata, &out); + err = hmac(hash, pass, &sdata, &out); if (err) return err; #if 0 @@ -146,13 +163,13 @@ F(char *output, char *u_tmp1, char *u_tmp2, prf_fn prf, size_t hlen, } static krb5_error_code -krb5int_pbkdf2 (prf_fn prf, size_t hlen, krb5_key pass, - const krb5_data *salt, unsigned long count, - const krb5_data *output) +pbkdf2(const struct krb5_hash_provider *hash, krb5_keyblock *pass, + const krb5_data *salt, unsigned long count, const krb5_data *output) { + size_t hlen = hash->hashsize; int l, i; char *utmp1, *utmp2; - char utmp3[20]; /* XXX length shouldn't be hardcoded! */ + char utmp3[128]; /* XXX length shouldn't be hardcoded! */ if (output->length == 0 || hlen == 0) abort(); @@ -183,7 +200,7 @@ krb5int_pbkdf2 (prf_fn prf, size_t hlen, krb5_key pass, out = utmp3; else out = output->data + (i-1) * hlen; - err = F(out, utmp1, utmp2, prf, hlen, pass, salt, count, i); + err = F(out, utmp1, utmp2, hash, hlen, pass, salt, count, i); if (err) { free(utmp1); free(utmp2); @@ -205,46 +222,23 @@ krb5int_pbkdf2 (prf_fn prf, size_t hlen, krb5_key pass, return 0; } -/* - * Implements the hmac-sha1 PRF. pass has been pre-hashed (if - * necessary) and converted to a key already; salt has had the block - * index appended to the original salt. - */ -static krb5_error_code -hmac_sha1(krb5_key pass, krb5_data *salt, krb5_data *out) -{ - const struct krb5_hash_provider *h = &krb5int_hash_sha1; - krb5_error_code err; - krb5_crypto_iov iov; - - if (debug_hmac) - printd(" hmac input", salt); - iov.flags = KRB5_CRYPTO_TYPE_DATA; - iov.data = *salt; - err = krb5int_hmac(h, pass, &iov, 1, out); - if (err == 0 && debug_hmac) - printd(" hmac output", out); - return err; -} - krb5_error_code -krb5int_pbkdf2_hmac_sha1(const krb5_data *out, unsigned long count, - const krb5_data *pass, const krb5_data *salt) +krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, + const krb5_data *out, unsigned long count, + const krb5_data *pass, const krb5_data *salt) { - const struct krb5_hash_provider *h = &krb5int_hash_sha1; krb5_keyblock keyblock; - krb5_key key; - char tmp[40]; + char tmp[128]; krb5_data d; krb5_crypto_iov iov; krb5_error_code err; - assert(h->hashsize <= sizeof(tmp)); - if (pass->length > h->blocksize) { - d = make_data(tmp, h->hashsize); + assert(hash->hashsize <= sizeof(tmp)); + if (pass->length > hash->blocksize) { + d = make_data(tmp, hash->hashsize); iov.flags = KRB5_CRYPTO_TYPE_DATA; iov.data = *pass; - err = h->hash(&iov, 1, &d); + err = hash->hash(&iov, 1, &d); if (err) return err; keyblock.length = d.length; @@ -255,11 +249,6 @@ krb5int_pbkdf2_hmac_sha1(const krb5_data *out, unsigned long count, } keyblock.enctype = ENCTYPE_NULL; - err = krb5_k_create_key(NULL, &keyblock, &key); - if (err) - return err; - - err = krb5int_pbkdf2(hmac_sha1, 20, key, salt, count, out); - krb5_k_free_key(NULL, key); + err = pbkdf2(hash, &keyblock, salt, count, out); return err; } diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h index 311d2a8..fec0eab 100644 --- a/src/lib/crypto/krb/crypto_int.h +++ b/src/lib/crypto/krb/crypto_int.h @@ -457,13 +457,13 @@ krb5_error_code krb5int_hmac_keyblock(const struct krb5_hash_provider *hash, /* * Compute the PBKDF2 (see RFC 2898) of password and salt, with the specified - * count, using HMAC-SHA-1 as the pseudorandom function, storing the result - * into out (caller-allocated). + * count, using HMAC with the specified hash as the pseudo-random function, + * storing the result into out (caller-allocated). */ -krb5_error_code krb5int_pbkdf2_hmac_sha1(const krb5_data *out, - unsigned long count, - const krb5_data *password, - const krb5_data *salt); +krb5_error_code krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, + const krb5_data *out, unsigned long count, + const krb5_data *password, + const krb5_data *salt); /* The following are used by test programs and are just handler functions from * the AES and Camellia enc providers. */ diff --git a/src/lib/crypto/krb/s2k_pbkdf2.c b/src/lib/crypto/krb/s2k_pbkdf2.c index 1808882..316f59a 100644 --- a/src/lib/crypto/krb/s2k_pbkdf2.c +++ b/src/lib/crypto/krb/s2k_pbkdf2.c @@ -111,6 +111,7 @@ pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, const krb5_data *params, krb5_keyblock *key, enum deriv_alg deriv_alg, unsigned long def_iter_count) { + const struct krb5_hash_provider *hash; unsigned long iter_count; krb5_data out; static const krb5_data usage = { KV5M_DATA, 8, "kerberos" }; @@ -158,7 +159,8 @@ pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, salt = &sandp; } - err = krb5int_pbkdf2_hmac_sha1 (&out, iter_count, string, salt); + hash = (ktp->hash != NULL) ? ktp->hash : &krb5int_hash_sha1; + err = krb5int_pbkdf2_hmac(hash, &out, iter_count, string, salt); if (err) goto cleanup; diff --git a/src/lib/crypto/openssl/pbkdf2.c b/src/lib/crypto/openssl/pbkdf2.c index 2a7da3f..00c2116 100644 --- a/src/lib/crypto/openssl/pbkdf2.c +++ b/src/lib/crypto/openssl/pbkdf2.c @@ -30,15 +30,24 @@ #include <openssl/hmac.h> krb5_error_code -krb5int_pbkdf2_hmac_sha1 (const krb5_data *out, unsigned long count, - const krb5_data *pass, const krb5_data *salt) +krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash, + const krb5_data *out, unsigned long count, + const krb5_data *pass, const krb5_data *salt) { -/* - * This is an implementation of PKCS#5 v2.0 - * Does not return an error - */ - PKCS5_PBKDF2_HMAC_SHA1(pass->data, pass->length, - (unsigned char *)salt->data, salt->length, count, - out->length, (unsigned char *)out->data); + const EVP_MD *md = NULL; + + /* Get the message digest handle corresponding to the hash. */ + if (hash == &krb5int_hash_sha1) + md = EVP_sha1(); + else if (hash == &krb5int_hash_sha256) + md = EVP_sha256(); + else if (hash == &krb5int_hash_sha384) + md = EVP_sha384(); + if (md == NULL) + return KRB5_CRYPTO_INTERNAL; + + PKCS5_PBKDF2_HMAC(pass->data, pass->length, (unsigned char *)salt->data, + salt->length, count, md, out->length, + (unsigned char *)out->data); return 0; } |