int aws_cryptosdk_rsa_decrypt()

in source/cipher.c [1010:1061]


int aws_cryptosdk_rsa_decrypt(
    struct aws_byte_buf *plain,
    struct aws_allocator *alloc,
    const struct aws_byte_cursor cipher,
    const struct aws_string *rsa_private_key_pem,
    enum aws_cryptosdk_rsa_padding_mode rsa_padding_mode) {
    AWS_PRECONDITION(aws_byte_buf_is_valid(plain));
    AWS_PRECONDITION(aws_byte_cursor_is_valid(&cipher));
    AWS_PRECONDITION(aws_string_is_valid(rsa_private_key_pem));
    if (plain->buffer) return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE);
    int padding = get_openssl_rsa_padding_mode(rsa_padding_mode);
    if (padding < 0) return aws_raise_error(AWS_CRYPTOSDK_ERR_UNSUPPORTED_FORMAT);
    BIO *bio          = NULL;
    EVP_PKEY_CTX *ctx = NULL;
    EVP_PKEY *pkey    = NULL;
    bool error        = true;
    int err_code      = AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN;
    pkey              = EVP_PKEY_new();
    if (!pkey) goto cleanup;
    bio = BIO_new_mem_buf(aws_string_bytes(rsa_private_key_pem), rsa_private_key_pem->len);
    if (!bio) goto cleanup;
    if (!PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)) goto cleanup;
    ctx = EVP_PKEY_CTX_new(pkey, NULL);
    if (!ctx) goto cleanup;
    if (EVP_PKEY_decrypt_init(ctx) <= 0) goto cleanup;
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) goto cleanup;
    if (rsa_padding_mode == AWS_CRYPTOSDK_RSA_OAEP_SHA256_MGF1) {
        if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha256()) <= 0) goto cleanup;
        if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) goto cleanup;
    }
    size_t outlen;
    if (EVP_PKEY_decrypt(ctx, NULL, &outlen, cipher.ptr, cipher.len) <= 0) goto cleanup;
    if (aws_byte_buf_init(plain, alloc, outlen)) goto cleanup;
    if (EVP_PKEY_decrypt(ctx, plain->buffer, &outlen, cipher.ptr, cipher.len) <= 0) {
        err_code = AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT;
    } else {
        plain->len = outlen;
        error      = false;
    }

cleanup:
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pkey);
    BIO_free(bio);
    flush_openssl_errors();
    if (error) {
        aws_byte_buf_clean_up_secure(plain);
        return aws_raise_error(err_code);
    } else {
        return AWS_OP_SUCCESS;
    }
}