#include "crypto_int.h"
#ifdef K5_BUILTIN_KDF
krb5_error_code
k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
krb5_key key, const krb5_data *label,
const krb5_data *context, krb5_data *rnd_out)
{
krb5_crypto_iov iov[5];
krb5_error_code ret;
krb5_data prf;
unsigned char ibuf[4], lbuf[4];
if (hash == NULL || rnd_out->length > hash->hashsize)
return KRB5_CRYPTO_INTERNAL;
ret = alloc_data(&prf, hash->hashsize);
if (ret)
return ret;
iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
iov[0].data = make_data(ibuf, sizeof(ibuf));
store_32_be(1, ibuf);
iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
iov[1].data = *label;
iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
iov[2].data = make_data("", 1);
iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
iov[3].data = *context;
iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
iov[4].data = make_data(lbuf, sizeof(lbuf));
store_32_be(rnd_out->length * 8, lbuf);
ret = krb5int_hmac(hash, key, iov, 5, &prf);
if (!ret)
memcpy(rnd_out->data, prf.data, rnd_out->length);
zapfree(prf.data, prf.length);
return ret;
}
krb5_error_code
k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc, krb5_key key,
const krb5_data *label, krb5_data *rnd_out)
{
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 (key->keyblock.length != enc->keylength || rnd_out->length != keybytes)
return KRB5_CRYPTO_INTERNAL;
ret = alloc_data(&prf, blocksize);
if (ret)
return ret;
iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
iov[0].data = prf;
iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
iov[1].data = make_data(ibuf, sizeof(ibuf));
iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
iov[2].data = *label;
iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
iov[3].data = make_data("", 1);
iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
iov[4].data = empty_data();
iov[5].flags = KRB5_CRYPTO_TYPE_DATA;
iov[5].data = make_data(Lbuf, sizeof(Lbuf));
store_32_be(rnd_out->length * 8, Lbuf);
for (i = 1, n = 0; n < keybytes; i++) {
store_32_be(i, ibuf);
ret = krb5int_cmac_checksum(enc, key, iov, 6, &prf);
if (ret)
goto cleanup;
if (keybytes - n <= blocksize) {
memcpy(rnd_out->data + n, prf.data, keybytes - n);
break;
}
memcpy(rnd_out->data + n, prf.data, blocksize);
n += blocksize;
}
cleanup:
zapfree(prf.data, blocksize);
return ret;
}
krb5_error_code
k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key key,
const krb5_data *constant, krb5_data *rnd_out)
{
size_t blocksize, keybytes, n;
krb5_error_code ret;
krb5_data block = empty_data();
blocksize = enc->block_size;
keybytes = enc->keybytes;
if (blocksize == 1)
return KRB5_BAD_ENCTYPE;
if (key->keyblock.length != enc->keylength || rnd_out->length != keybytes)
return KRB5_CRYPTO_INTERNAL;
ret = alloc_data(&block, blocksize);
if (ret)
return ret;
if (constant->length == blocksize) {
memcpy(block.data, constant->data, blocksize);
} else {
krb5int_nfold(constant->length * 8, (uint8_t *)constant->data,
blocksize * 8, (uint8_t *)block.data);
}
n = 0;
while (n < keybytes) {
ret = encrypt_block(enc, key, &block);
if (ret)
goto cleanup;
if ((keybytes - n) <= blocksize) {
memcpy(rnd_out->data + n, block.data, (keybytes - n));
break;
}
memcpy(rnd_out->data + n, block.data, blocksize);
n += blocksize;
}
cleanup:
zapfree(block.data, blocksize);
return ret;
}
#endif