aboutsummaryrefslogtreecommitdiff
path: root/src/lib/crypto/krb/dk/derive.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypto/krb/dk/derive.c')
-rw-r--r--src/lib/crypto/krb/dk/derive.c86
1 files changed, 84 insertions, 2 deletions
diff --git a/src/lib/crypto/krb/dk/derive.c b/src/lib/crypto/krb/dk/derive.c
index 5fd8876..24dcb53 100644
--- a/src/lib/crypto/krb/dk/derive.c
+++ b/src/lib/crypto/krb/dk/derive.c
@@ -79,8 +79,8 @@ cleanup:
return ENOMEM;
}
-krb5_error_code
-krb5int_derive_random(const struct krb5_enc_provider *enc,
+static krb5_error_code
+derive_random_rfc3961(const struct krb5_enc_provider *enc,
krb5_key inkey, krb5_data *outrnd,
const krb5_data *in_constant)
{
@@ -131,6 +131,88 @@ cleanup:
}
/*
+ * NIST SP800-108 KDF in feedback mode with CMAC as PRF
+ */
+static krb5_error_code
+derive_random_sp800_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ size_t blocksize, keybytes, n;
+ krb5_crypto_iov iov[6];
+ krb5_error_code ret;
+ krb5_data prf;
+ unsigned int i;
+ unsigned char ibuf[4], Lbuf[4];
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+
+ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
+ return KRB5_CRYPTO_INTERNAL;
+
+ /* Allocate encryption data buffer. */
+ ret = alloc_data(&prf, blocksize);
+ if (ret)
+ return ret;
+
+ /* K(i-1) */
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[0].data = prf;
+ /* [i]2 */
+ iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[1].data = make_data(ibuf, sizeof(ibuf));
+ /* Label */
+ iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[2].data = *in_constant;
+ /* 0x00 */
+ iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[3].data = make_data("", 1);
+ /* Context */
+ iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[4].data = empty_data();
+ /* [L]2 */
+ iov[5].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[5].data = make_data(Lbuf, sizeof(Lbuf));
+ store_32_be(outrnd->length, Lbuf);
+
+ for (i = 1, n = 0; n < keybytes; i++) {
+ store_32_be(i, ibuf);
+
+ ret = krb5int_cmac_checksum(enc, inkey, iov, 6, &prf);
+ if (ret)
+ goto cleanup;
+
+ if (keybytes - n <= blocksize) {
+ memcpy(outrnd->data + n, prf.data, keybytes - n);
+ break;
+ }
+
+ memcpy(outrnd->data + n, prf.data, blocksize);
+ n += blocksize;
+ }
+
+cleanup:
+ zapfree(prf.data, blocksize);
+ return ret;
+}
+
+krb5_error_code
+krb5int_derive_random(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ krb5_error_code ret;
+
+ if (enc->cbc_mac)
+ ret = derive_random_sp800_cmac(enc, inkey, outrnd, in_constant);
+ else
+ ret = derive_random_rfc3961(enc, inkey, outrnd, in_constant);
+
+ return ret;
+}
+
+/*
* Compute a derived key into the keyblock outkey. This variation on
* krb5int_derive_key does not cache the result, as it is only used
* directly in situations which are not expected to be repeated with