in source/cipher.c [844:889]
int aws_cryptosdk_aes_gcm_encrypt(
struct aws_byte_buf *cipher,
struct aws_byte_buf *tag,
const struct aws_byte_cursor plain,
const struct aws_byte_cursor iv,
const struct aws_byte_cursor aad,
const struct aws_string *key) {
AWS_PRECONDITION(aws_byte_buf_is_valid(cipher));
AWS_PRECONDITION(cipher->buffer != NULL);
AWS_PRECONDITION(aws_byte_buf_is_valid(tag));
AWS_PRECONDITION(aws_byte_cursor_is_valid(&plain));
AWS_PRECONDITION(aws_byte_cursor_is_valid(&iv));
AWS_PRECONDITION(aws_byte_cursor_is_valid(&aad));
AWS_PRECONDITION(aws_string_is_valid(key));
const EVP_CIPHER *alg = get_alg_from_key_size(key->len);
if (!alg || iv.len != aes_gcm_iv_len || tag->capacity < aes_gcm_tag_len || cipher->capacity < plain.len)
return aws_raise_error(AWS_ERROR_INVALID_BUFFER_SIZE);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) goto openssl_err;
if (!EVP_EncryptInit_ex(ctx, alg, NULL, aws_string_bytes(key), iv.ptr)) goto openssl_err;
int out_len;
if (aad.len) {
if (!EVP_EncryptUpdate(ctx, NULL, &out_len, aad.ptr, aad.len)) goto openssl_err;
}
if (!EVP_EncryptUpdate(ctx, cipher->buffer, &out_len, plain.ptr, plain.len)) goto openssl_err;
int prev_len = out_len;
if (!EVP_EncryptFinal_ex(ctx, cipher->buffer + out_len, &out_len)) goto openssl_err;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, aes_gcm_tag_len, tag->buffer)) goto openssl_err;
tag->len = aes_gcm_tag_len;
cipher->len = prev_len + out_len;
assert(cipher->len == plain.len);
EVP_CIPHER_CTX_free(ctx);
return AWS_OP_SUCCESS;
openssl_err:
EVP_CIPHER_CTX_free(ctx);
aws_byte_buf_secure_zero(cipher);
aws_byte_buf_secure_zero(tag);
flush_openssl_errors();
return aws_raise_error(AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN);
}