krb5 commit: Enable PBKDF2 with SHA-256 and SHA-384

Greg Hudson ghudson at mit.edu
Mon Oct 3 16:02:41 EDT 2016


https://github.com/krb5/krb5/commit/dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0
commit dc967ce5c4a03201b2a6ff477f6c4e33b07e90f0
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Dec 7 11:16:06 2015 -0500

    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

 src/lib/crypto/builtin/pbkdf2.c |   93 +++++++++++++++++----------------------
 src/lib/crypto/krb/crypto_int.h |   12 +++---
 src/lib/crypto/krb/s2k_pbkdf2.c |    4 +-
 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;
 }


More information about the cvs-krb5 mailing list