diff options
Diffstat (limited to 'src/lib/crypto/krb/dk/derive.c')
-rw-r--r-- | src/lib/crypto/krb/dk/derive.c | 86 |
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 |