aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2015-12-07 11:16:06 -0500
committerGreg Hudson <ghudson@mit.edu>2016-10-03 15:38:10 -0400
commitdc967ce5c4a03201b2a6ff477f6c4e33b07e90f0 (patch)
treee859856130c7093474bcf7e1099ac647abe39f49
parentc438227afd763997c131339c1476f61d1628a20d (diff)
downloadkrb5-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.c93
-rw-r--r--src/lib/crypto/krb/crypto_int.h12
-rw-r--r--src/lib/crypto/krb/s2k_pbkdf2.c4
-rw-r--r--src/lib/crypto/openssl/pbkdf2.c27
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;
}