in source/caching_cmm.c [372:475]
int hash_dec_request(
const struct aws_string *partition_id, struct aws_byte_buf *out, const struct aws_cryptosdk_dec_request *req) {
static const struct edk_hash_entry zero_entry = { { 0 } };
int rv = AWS_OP_ERR;
size_t md_length = aws_cryptosdk_md_size(AWS_CRYPTOSDK_MD_SHA512);
uint16_t alg_id_be = aws_hton16(req->alg);
struct aws_byte_buf context_buf = { 0 };
uint8_t context_digest_arr[AWS_CRYPTOSDK_MD_MAX_SIZE] = { 0 };
struct aws_byte_buf context_digest_buf = aws_byte_buf_from_array(context_digest_arr, sizeof(context_digest_arr));
struct aws_cryptosdk_md_context *md_context = NULL;
struct aws_array_list edk_hash_list;
if (out->capacity < AWS_CRYPTOSDK_MD_MAX_SIZE) {
return aws_raise_error(AWS_ERROR_INVALID_BUFFER_SIZE);
}
if (aws_array_list_init_dynamic(
&edk_hash_list,
req->alloc,
aws_array_list_length(&req->encrypted_data_keys),
sizeof(struct edk_hash_entry))) {
return AWS_OP_ERR;
}
size_t context_size;
if (aws_cryptosdk_md_init(req->alloc, &md_context, AWS_CRYPTOSDK_MD_SHA512) ||
aws_cryptosdk_enc_ctx_size(&context_size, req->enc_ctx) ||
aws_byte_buf_init(&context_buf, req->alloc, context_size) ||
aws_cryptosdk_enc_ctx_serialize(req->alloc, &context_buf, req->enc_ctx) ||
aws_cryptosdk_md_update(md_context, context_buf.buffer, context_buf.len)) {
goto err;
}
if (aws_cryptosdk_md_finish(md_context, context_digest_buf.buffer, &context_digest_buf.len)) {
md_context = NULL;
goto err;
}
// The decryption request cache IDs are constructed out of a hash of:
// [partition ID]
// [algorithm ID]
// [EDK hashes, in sorted order]
// [digestLength zero bytes]
// [encryption context hash]
// Before we start hashing the top level stuff, let's hash the EDKs and sort them
// Note that the EDK entries have no length field - if we introduce a larger hash
// in the future, we just treat the smaller (?) SHA-512 as the top-order bits of
// a larger field.
size_t n_edks = aws_array_list_length(&req->encrypted_data_keys);
for (size_t i = 0; i < n_edks; i++) {
struct edk_hash_entry entry;
const struct aws_cryptosdk_edk *edk = NULL;
void *vp_edk = NULL;
if (aws_array_list_get_at_ptr(&req->encrypted_data_keys, &vp_edk, i)) {
goto err;
}
edk = vp_edk;
if (hash_edk_for_decrypt(req->alloc, &entry, edk)) {
goto err;
}
if (aws_array_list_push_back(&edk_hash_list, &entry)) {
goto err;
}
}
aws_array_list_sort(&edk_hash_list, edk_hash_entry_cmp);
if (aws_cryptosdk_md_init(req->alloc, &md_context, AWS_CRYPTOSDK_MD_SHA512) ||
aws_cryptosdk_md_update(md_context, aws_string_bytes(partition_id), partition_id->len) ||
aws_cryptosdk_md_update(md_context, &alg_id_be, sizeof(alg_id_be))) {
goto err;
}
for (size_t i = 0; i < n_edks; i++) {
void *vp_entry = NULL;
if (aws_array_list_get_at_ptr(&edk_hash_list, &vp_entry, i) ||
aws_cryptosdk_md_update(md_context, ((struct edk_hash_entry *)vp_entry)->hash_data, md_length)) {
goto err;
}
}
if (aws_cryptosdk_md_update(md_context, &zero_entry, sizeof(zero_entry)) ||
aws_cryptosdk_md_update(md_context, context_digest_buf.buffer, context_digest_buf.len)) {
goto err;
}
rv = aws_cryptosdk_md_finish(md_context, out->buffer, &out->len);
md_context = NULL;
err:
aws_cryptosdk_md_abort(md_context);
aws_byte_buf_clean_up(&context_buf);
aws_array_list_clean_up(&edk_hash_list);
return rv;
}