int hash_dec_request()

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