in source/hkdf.c [76:120]
static int aws_cryptosdk_hkdf_expand(
struct aws_byte_buf *okm,
enum aws_cryptosdk_sha_version which_sha,
const uint8_t *prk,
unsigned int prk_len,
const struct aws_byte_buf *info) {
const EVP_MD *evp_md = aws_cryptosdk_get_evp_md(which_sha);
if (!evp_md) return aws_raise_error(AWS_CRYPTOSDK_ERR_UNSUPPORTED_FORMAT);
HMAC_CTX ctx;
uint8_t t[EVP_MAX_MD_SIZE];
size_t n = 0;
unsigned int t_len = 0;
size_t bytes_to_write;
size_t bytes_remaining = okm->len;
size_t hash_len = EVP_MD_size(evp_md);
HMAC_CTX_init(&ctx);
if (!prk || !okm->len || !prk_len) goto err;
n = (okm->len + hash_len - 1) / hash_len;
if (n > 255) goto err;
for (uint32_t idx = 1; idx <= n; idx++) {
uint8_t idx_byte = idx;
if (!HMAC_Init_ex(&ctx, prk, prk_len, evp_md, NULL)) goto err;
if (idx != 1) {
if (!HMAC_Update(&ctx, t, hash_len)) goto err;
}
if (!HMAC_Update(&ctx, info->buffer, info->len)) goto err;
if (!HMAC_Update(&ctx, &idx_byte, 1)) goto err;
if (!HMAC_Final(&ctx, t, &t_len)) goto err;
assert(t_len == hash_len);
bytes_to_write = bytes_remaining < hash_len ? bytes_remaining : hash_len;
memcpy(okm->buffer + (idx - 1) * hash_len, t, bytes_to_write);
bytes_remaining -= bytes_to_write;
}
assert(bytes_remaining == 0);
aws_secure_zero(t, sizeof(t));
HMAC_CTX_cleanup(&ctx);
return AWS_OP_SUCCESS;
err:
HMAC_CTX_cleanup(&ctx);
aws_byte_buf_secure_zero(okm);
aws_secure_zero(t, sizeof(t));
return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
}