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