int aws_cryptosdk_aes_gcm_encrypt()

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