int aws_cryptosdk_decrypt_body()

in source/cipher.c [746:806]


int aws_cryptosdk_decrypt_body(
    const struct aws_cryptosdk_alg_properties *props,
    struct aws_byte_buf *outp,
    const struct aws_byte_cursor *inp,
    const struct aws_byte_buf *message_id,
    uint32_t seqno,
    const uint8_t *iv,
    const struct content_key *key,
    const uint8_t *tag,
    int body_frame_type) {
    AWS_PRECONDITION(aws_cryptosdk_alg_properties_is_valid(props));
    AWS_PRECONDITION(aws_byte_buf_is_valid(outp));
    AWS_PRECONDITION(aws_byte_cursor_is_valid(inp));
    AWS_PRECONDITION(aws_byte_buf_is_valid(message_id));
    AWS_PRECONDITION(iv != NULL);
    AWS_PRECONDITION(tag != NULL);
    AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(tag, props->tag_len));
    if (inp->len != outp->capacity - outp->len) {
        return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
    }

    EVP_CIPHER_CTX *ctx           = NULL;
    struct aws_byte_buf outcurs   = *outp;
    struct aws_byte_cursor incurs = *inp;
    int result                    = AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN;

    if (!(ctx = evp_gcm_cipher_init(props, key, iv, false))) goto out;

    if (!update_frame_aad(ctx, message_id, body_frame_type, seqno, inp->len)) goto out;

    while (incurs.len) {
        int in_len = incurs.len > INT_MAX ? INT_MAX : incurs.len;
        int pt_len;

        if (!EVP_DecryptUpdate(ctx, outcurs.buffer + outcurs.len, &pt_len, incurs.ptr, in_len)) goto out;
        /*
         * The next two advances should never fail ... but check the return values
         * just in case.
         */
        if (!aws_byte_cursor_advance_nospec(&incurs, in_len).ptr) goto out;

        if (aws_add_size_checked(outcurs.len, pt_len, &outcurs.len)) goto out;

        if (outcurs.len > outcurs.capacity) {
            /* Somehow we ran over the output buffer. abort() to limit the damage. */
            abort();
        }
    }

    result = evp_gcm_decrypt_final(props, ctx, tag);
out:
    if (ctx) EVP_CIPHER_CTX_free(ctx);

    if (result == AWS_ERROR_SUCCESS) {
        *outp = outcurs;
        return AWS_OP_SUCCESS;
    } else {
        aws_byte_buf_secure_zero(outp);
        return aws_raise_error(result);
    }
}