static int aws_cryptosdk_hkdf_expand()

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);
}