diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index c9341501bc..3ed339ecbb 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -1626,6 +1626,10 @@ typedef struct botan_pk_op_encrypt_struct* botan_pk_op_encrypt_t; BOTAN_FFI_EXPORT(2, 0) int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, botan_pubkey_t key, const char* padding, uint32_t flags); +BOTAN_FFI_EXPORT(3, 7) +int botan_pk_op_encrypt_create_with_rng( + botan_pk_op_encrypt_t* op, botan_rng_t rng, botan_pubkey_t key, const char* padding, uint32_t flags); + /** * @return 0 if success, error if invalid object handle */ @@ -1650,6 +1654,10 @@ typedef struct botan_pk_op_decrypt_struct* botan_pk_op_decrypt_t; BOTAN_FFI_EXPORT(2, 0) int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, botan_privkey_t key, const char* padding, uint32_t flags); +BOTAN_FFI_EXPORT(3, 7) +int botan_pk_op_decrypt_create_with_rng( + botan_pk_op_decrypt_t* op, botan_rng_t rng, botan_privkey_t key, const char* padding, uint32_t flags); + /** * @return 0 if success, error if invalid object handle */ @@ -1673,6 +1681,10 @@ typedef struct botan_pk_op_sign_struct* botan_pk_op_sign_t; BOTAN_FFI_EXPORT(2, 0) int botan_pk_op_sign_create(botan_pk_op_sign_t* op, botan_privkey_t key, const char* hash_and_padding, uint32_t flags); +BOTAN_FFI_EXPORT(3, 7) +int botan_pk_op_sign_create_with_rng( + botan_pk_op_sign_t* op, botan_rng_t rng, botan_privkey_t key, const char* hash_and_padding, uint32_t flags); + /** * @return 0 if success, error if invalid object handle */ @@ -1712,6 +1724,10 @@ typedef struct botan_pk_op_ka_struct* botan_pk_op_ka_t; BOTAN_FFI_EXPORT(2, 0) int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, botan_privkey_t key, const char* kdf, uint32_t flags); +BOTAN_FFI_EXPORT(3, 7) +int botan_pk_op_key_agreement_create_with_rng( + botan_pk_op_ka_t* op, botan_rng_t rng, botan_privkey_t key, const char* kdf, uint32_t flags); + /** * @return 0 if success, error if invalid object handle */ @@ -1771,6 +1787,12 @@ typedef struct botan_pk_op_kem_decrypt_struct* botan_pk_op_kem_decrypt_t; BOTAN_FFI_EXPORT(3, 0) int botan_pk_op_kem_decrypt_create(botan_pk_op_kem_decrypt_t* op, botan_privkey_t key, const char* kdf); +BOTAN_FFI_EXPORT(3, 7) +int botan_pk_op_kem_decrypt_create_with_rng(botan_pk_op_kem_decrypt_t* op, + botan_rng_t rng, + botan_privkey_t key, + const char* kdf); + /** * @return 0 if success, error if invalid object handle */ diff --git a/src/lib/ffi/ffi_pk_op.cpp b/src/lib/ffi/ffi_pk_op.cpp index f08d9ec569..254b4aa954 100644 --- a/src/lib/ffi/ffi_pk_op.cpp +++ b/src/lib/ffi/ffi_pk_op.cpp @@ -43,6 +43,27 @@ int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, botan_pubkey_t key_obj }); } +int botan_pk_op_encrypt_create_with_rng( + botan_pk_op_encrypt_t* op, botan_rng_t rng_obj, botan_pubkey_t key_obj, const char* padding, uint32_t flags) { + if(op == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) { + return BOTAN_FFI_ERROR_BAD_FLAG; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + auto pk = std::make_unique(safe_get(key_obj), rng, padding); + *op = new botan_pk_op_encrypt_struct(std::move(pk)); + return BOTAN_FFI_SUCCESS; + }); +} + int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } @@ -89,6 +110,27 @@ int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, }); } +int botan_pk_op_decrypt_create_with_rng( + botan_pk_op_decrypt_t* op, botan_rng_t rng_obj, botan_privkey_t key_obj, const char* padding, uint32_t flags) { + if(op == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + if(flags != 0) { + return BOTAN_FFI_ERROR_BAD_FLAG; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + auto pk = std::make_unique(safe_get(key_obj), rng, padding); + *op = new botan_pk_op_decrypt_struct(std::move(pk)); + return BOTAN_FFI_SUCCESS; + }); +} + int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } @@ -130,6 +172,30 @@ int botan_pk_op_sign_create(botan_pk_op_sign_t* op, botan_privkey_t key_obj, con }); } +int botan_pk_op_sign_create_with_rng( + botan_pk_op_sign_t* op, botan_rng_t rng_obj, botan_privkey_t key_obj, const char* hash, uint32_t flags) { + if(op == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + if(flags != 0 && flags != BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) { + return BOTAN_FFI_ERROR_BAD_FLAG; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + *op = nullptr; + + auto format = (flags & BOTAN_PUBKEY_DER_FORMAT_SIGNATURE) ? Botan::Signature_Format::DerSequence + : Botan::Signature_Format::Standard; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + auto pk = std::make_unique(safe_get(key_obj), rng, hash, format); + *op = new botan_pk_op_sign_struct(std::move(pk)); + return BOTAN_FFI_SUCCESS; + }); +} + int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } @@ -205,6 +271,25 @@ int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, botan_privkey_t key_o }); } +int botan_pk_op_key_agreement_create_with_rng( + botan_pk_op_ka_t* op, botan_rng_t rng_obj, botan_privkey_t key_obj, const char* kdf, uint32_t flags) { + if(op == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + if(flags != 0) { + return BOTAN_FFI_ERROR_BAD_FLAG; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + *op = nullptr; + auto pk = std::make_unique(safe_get(key_obj), rng, kdf); + *op = new botan_pk_op_ka_struct(std::move(pk)); + return BOTAN_FFI_SUCCESS; + }); +} + int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) { return BOTAN_FFI_CHECKED_DELETE(op); } @@ -318,6 +403,22 @@ int botan_pk_op_kem_decrypt_create(botan_pk_op_kem_decrypt_t* op, botan_privkey_ }); } +int botan_pk_op_kem_decrypt_create_with_rng(botan_pk_op_kem_decrypt_t* op, + botan_rng_t rng_obj, + botan_privkey_t key_obj, + const char* padding) { + if(op == nullptr || padding == nullptr) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + return ffi_guard_thunk(__func__, [=]() -> int { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + auto pk = std::make_unique(safe_get(key_obj), rng, padding); + *op = new botan_pk_op_kem_decrypt_struct(std::move(pk)); + return BOTAN_FFI_SUCCESS; + }); +} + int botan_pk_op_kem_decrypt_shared_key_length(botan_pk_op_kem_decrypt_t op, size_t desired_shared_key_length, size_t* output_shared_key_length) { diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 647e6ad10b..f4e59757aa 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -2484,9 +2484,7 @@ class FFI_RSA_Test final : public FFI_Test { result.test_eq("algo name", std::string(namebuf), "RSA"); } - botan_pk_op_encrypt_t encrypt; - - if(TEST_FFI_INIT(botan_pk_op_encrypt_create, (&encrypt, loaded_pubkey, "OAEP(SHA-256)", 0))) { + auto test_encrypt_opt_fn = [&result, &rng, &priv](botan_pk_op_encrypt_t encrypt) { std::vector plaintext(32); TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size())); @@ -2499,7 +2497,7 @@ class FFI_RSA_Test final : public FFI_Test { ciphertext.resize(ctext_len); botan_pk_op_decrypt_t decrypt; - if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&decrypt, priv, "OAEP(SHA-256)", 0))) { + if(TEST_FFI_OK(botan_pk_op_decrypt_create_with_rng, (&decrypt, rng, priv, "OAEP(SHA-256)", 0))) { size_t decrypted_len; TEST_FFI_OK(botan_pk_op_decrypt_output_length, (decrypt, ciphertext.size(), &decrypted_len)); std::vector decrypted(decrypted_len); @@ -2514,6 +2512,16 @@ class FFI_RSA_Test final : public FFI_Test { } TEST_FFI_OK(botan_pk_op_encrypt_destroy, (encrypt)); + }; + + botan_pk_op_encrypt_t encrypt; + + if(TEST_FFI_INIT(botan_pk_op_encrypt_create, (&encrypt, loaded_pubkey, "OAEP(SHA-256)", 0))) { + test_encrypt_opt_fn(encrypt); + } + + if(TEST_FFI_INIT(botan_pk_op_encrypt_create_with_rng, (&encrypt, rng, loaded_pubkey, "OAEP(SHA-256)", 0))) { + test_encrypt_opt_fn(encrypt); } TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey)); @@ -2975,7 +2983,7 @@ class FFI_ECDH_Test final : public FFI_Test { botan_pk_op_ka_t ka1; REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "KDF2(SHA-256)", 0)); botan_pk_op_ka_t ka2; - REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "KDF2(SHA-256)", 0)); + REQUIRE_FFI_OK(botan_pk_op_key_agreement_create_with_rng, (&ka2, rng, priv2, "KDF2(SHA-256)", 0)); size_t pubkey1_len = 0; TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, @@ -3150,10 +3158,9 @@ class FFI_Ed448_Test final : public FFI_Test { TEST_FFI_OK(botan_pubkey_destroy, (pub)); TEST_FFI_OK(botan_pubkey_load_ed448, (&pub, pk_ref.data())); - botan_pk_op_sign_t signer; std::vector signature; - if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "Pure", 0))) { + auto sign_fn = [&result, &rng, &msg, &signature](botan_pk_op_sign_t signer) { TEST_FFI_OK(botan_pk_op_sign_update, (signer, msg.data(), msg.size())); size_t sig_len; @@ -3165,6 +3172,18 @@ class FFI_Ed448_Test final : public FFI_Test { signature.resize(sig_len); TEST_FFI_OK(botan_pk_op_sign_destroy, (signer)); + }; + + botan_pk_op_sign_t signer; + + if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "Pure", 0))) { + sign_fn(signer); + } + + result.test_eq("Expected signature", signature, sig_ref); + + if(TEST_FFI_OK(botan_pk_op_sign_create_with_rng, (&signer, rng, priv, "Pure", 0))) { + sign_fn(signer); } result.test_eq("Expected signature", signature, sig_ref); @@ -3340,6 +3359,7 @@ class FFI_KEM_Roundtrip_Test : public FFI_Test { public: void ffi_test(Test::Result& result, botan_rng_t rng) override { + bool use_explicit_rng = true; for(auto mode : modes()) { // generate a key pair botan_privkey_t priv; @@ -3423,7 +3443,11 @@ class FFI_KEM_Roundtrip_Test : public FFI_Test { // KEM decryption (using the generated private key) botan_pk_op_kem_decrypt_t kem_dec; - TEST_FFI_OK(botan_pk_op_kem_decrypt_create, (&kem_dec, priv, "Raw")); + if(use_explicit_rng) { + TEST_FFI_OK(botan_pk_op_kem_decrypt_create_with_rng, (&kem_dec, rng, priv, "Raw")); + } else { + TEST_FFI_OK(botan_pk_op_kem_decrypt_create, (&kem_dec, priv, "Raw")); + } size_t shared_key_length2 = 0; TEST_FFI_OK(botan_pk_op_kem_decrypt_shared_key_length, (kem_dec, shared_key_length, &shared_key_length2)); result.test_eq("shared key lengths are consistent", shared_key_length, shared_key_length2); @@ -3465,6 +3489,8 @@ class FFI_KEM_Roundtrip_Test : public FFI_Test { TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded)); TEST_FFI_OK(botan_privkey_destroy, (priv)); TEST_FFI_OK(botan_privkey_destroy, (priv_loaded)); + + use_explicit_rng = !use_explicit_rng; } } }; @@ -3489,6 +3515,7 @@ class FFI_Signature_Roundtrip_Test : public FFI_Test { const std::vector message1 = {'H', 'e', 'l', 'l', 'o', ' '}; const std::vector message2 = {'W', 'o', 'r', 'l', 'd', '!'}; + bool use_explicit_rng = true; for(auto mode : modes()) { // generate a key pair botan_privkey_t priv; @@ -3522,7 +3549,11 @@ class FFI_Signature_Roundtrip_Test : public FFI_Test { // Signature Creation (using the loaded private key) botan_pk_op_sign_t signer; - TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0)); + if(use_explicit_rng) { + TEST_FFI_OK(botan_pk_op_sign_create_with_rng, (&signer, rng, priv_loaded, hash_algo_or_padding(), 0)); + } else { + TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0)); + } // explicitly query the signature output length size_t sig_output_length = 0; @@ -3541,7 +3572,11 @@ class FFI_Signature_Roundtrip_Test : public FFI_Test { // Recreate signer and try again TEST_FFI_OK(botan_pk_op_sign_destroy, (signer)); - TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0)); + if(use_explicit_rng) { + TEST_FFI_OK(botan_pk_op_sign_create_with_rng, (&signer, rng, priv_loaded, hash_algo_or_padding(), 0)); + } else { + TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0)); + } TEST_FFI_OK(botan_pk_op_sign_update, (signer, message1.data(), message1.size())); TEST_FFI_OK(botan_pk_op_sign_update, (signer, message2.data(), message2.size())); @@ -3575,6 +3610,8 @@ class FFI_Signature_Roundtrip_Test : public FFI_Test { TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded)); TEST_FFI_OK(botan_privkey_destroy, (priv)); TEST_FFI_OK(botan_privkey_destroy, (priv_loaded)); + + use_explicit_rng = !use_explicit_rng; } } }; @@ -3885,8 +3922,7 @@ class FFI_ElGamal_Test final : public FFI_Test { } // Test decryption - botan_pk_op_decrypt_t op_dec; - if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, "Raw", 0))) { + auto test_decrypt_fn = [&result, &decryption, &ciphertext](botan_pk_op_decrypt_t op_dec) { size_t ptext_len; TEST_FFI_OK(botan_pk_op_decrypt_output_length, (op_dec, ciphertext.size(), &ptext_len)); decryption.resize(ptext_len); @@ -3894,6 +3930,16 @@ class FFI_ElGamal_Test final : public FFI_Test { (op_dec, decryption.data(), &ptext_len, ciphertext.data(), ciphertext.size())); decryption.resize(ptext_len); TEST_FFI_OK(botan_pk_op_decrypt_destroy, (op_dec)); + }; + + botan_pk_op_decrypt_t op_dec; + + if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, "Raw", 0))) { + test_decrypt_fn(op_dec); + } + + if(TEST_FFI_OK(botan_pk_op_decrypt_create_with_rng, (&op_dec, rng, loaded_privkey, "Raw", 0))) { + test_decrypt_fn(op_dec); } result.test_eq("decryption worked", decryption, plaintext); @@ -3966,7 +4012,7 @@ class FFI_DH_Test final : public FFI_Test { result.confirm("bigint_mp_cmp(y, y)", cmp == 0); botan_pk_op_ka_t ka1; - REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "Raw", 0)); + REQUIRE_FFI_OK(botan_pk_op_key_agreement_create_with_rng, (&ka1, rng, loaded_privkey1, "Raw", 0)); botan_pk_op_ka_t ka2; REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "Raw", 0));