From 52335d25ee955bc231a41d112f56d6ac79feda8f Mon Sep 17 00:00:00 2001 From: Xie Zhihao Date: Mon, 1 Apr 2024 10:48:46 +0800 Subject: [PATCH] cryptomb: reduce memory copy in ECDSA (#33201) * cryptomb: reduce memory copy in ECDSA The original implementation serializes signatures into a temporary output buffer during processing phase and then copy to the BoringSSL buffer in the completion phase. This patch change the way and directly serializes signatures to the BoringSSL buffer. In addition, the patch adds a speed test to track the performance change by mathematical implementation of private key provider. Risk Level: Low Testing: N/A Docs Changes: N/A Release Notes: N/A Platform Specific Features: Requires AVX512 or equivalent CPU instruction set Signed-off-by: Xie Zhihao --- .../source/cryptomb_private_key_provider.cc | 130 +++-- .../source/cryptomb_private_key_provider.h | 15 +- .../cryptomb/private_key_providers/test/BUILD | 15 + .../private_key_providers/test/ops_test.cc | 48 +- .../private_key_providers/test/speed_test.cc | 523 ++++++++++++++++++ 5 files changed, 657 insertions(+), 74 deletions(-) create mode 100644 contrib/cryptomb/private_key_providers/test/speed_test.cc diff --git a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc index 7ed6246805ee..58c670e7c4df 100644 --- a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc +++ b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.cc @@ -183,6 +183,65 @@ ssl_private_key_result_t ecdsaPrivateKeyDecrypt(SSL*, uint8_t*, size_t*, size_t, return ssl_private_key_failure; } +ssl_private_key_result_t ecdsaPrivateKeyCompleteInternal(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out) { + if (ops == nullptr) { + return ssl_private_key_failure; + } + + // Check if the MB operation is ready yet. This can happen if someone calls + // the top-level SSL function too early. The op status is only set from this + // thread. + if (ops->mb_ctx_->getStatus() == RequestStatus::Retry) { + return ssl_private_key_retry; + } + + // If this point is reached, the MB processing must be complete. + + // See if the operation failed. + if (ops->mb_ctx_->getStatus() != RequestStatus::Success) { + ops->logWarnMsg("private key operation failed."); + return ssl_private_key_failure; + } + + CryptoMbEcdsaContextSharedPtr mb_ctx = + std::static_pointer_cast(ops->mb_ctx_); + if (mb_ctx->sig_len_ > max_out) { + return ssl_private_key_failure; + } + + ECDSA_SIG* sig = ECDSA_SIG_new(); + if (sig == nullptr) { + return ssl_private_key_failure; + } + BIGNUM* sig_r = BN_bin2bn(mb_ctx->sig_r_, 32, nullptr); + BIGNUM* sig_s = BN_bin2bn(mb_ctx->sig_s_, 32, nullptr); + ECDSA_SIG_set0(sig, sig_r, sig_s); + + // Marshal signature into out. + CBB cbb; + if (!CBB_init_fixed(&cbb, out, mb_ctx->sig_len_) || !ECDSA_SIG_marshal(&cbb, sig) || + !CBB_finish(&cbb, nullptr, out_len)) { + CBB_cleanup(&cbb); + ECDSA_SIG_free(sig); + return ssl_private_key_failure; + } + + ECDSA_SIG_free(sig); + + return ssl_private_key_success; +} + +ssl_private_key_result_t ecdsaPrivateKeyComplete(SSL* ssl, uint8_t* out, size_t* out_len, + size_t max_out) { + return ssl == nullptr ? ssl_private_key_failure + : ecdsaPrivateKeyCompleteInternal( + static_cast(SSL_get_ex_data( + ssl, CryptoMbPrivateKeyMethodProvider::connectionIndex())), + out, out_len, max_out); +} + ssl_private_key_result_t rsaPrivateKeySignInternal(CryptoMbPrivateKeyConnection* ops, uint8_t*, size_t*, size_t, uint16_t signature_algorithm, const uint8_t* in, size_t in_len) { @@ -337,8 +396,9 @@ ssl_private_key_result_t rsaPrivateKeyDecrypt(SSL* ssl, uint8_t* out, size_t* ou out, out_len, max_out, in, in_len); } -ssl_private_key_result_t privateKeyCompleteInternal(CryptoMbPrivateKeyConnection* ops, uint8_t* out, - size_t* out_len, size_t max_out) { +ssl_private_key_result_t rsaPrivateKeyCompleteInternal(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out) { if (ops == nullptr) { return ssl_private_key_failure; } @@ -358,21 +418,22 @@ ssl_private_key_result_t privateKeyCompleteInternal(CryptoMbPrivateKeyConnection return ssl_private_key_failure; } - *out_len = ops->mb_ctx_->out_len_; + CryptoMbRsaContextSharedPtr mb_ctx = std::static_pointer_cast(ops->mb_ctx_); + *out_len = mb_ctx->out_len_; if (*out_len > max_out) { return ssl_private_key_failure; } - memcpy(out, ops->mb_ctx_->out_buf_, *out_len); // NOLINT(safe-memcpy) + memcpy(out, mb_ctx->out_buf_, *out_len); // NOLINT(safe-memcpy) return ssl_private_key_success; } -ssl_private_key_result_t privateKeyComplete(SSL* ssl, uint8_t* out, size_t* out_len, - size_t max_out) { +ssl_private_key_result_t rsaPrivateKeyComplete(SSL* ssl, uint8_t* out, size_t* out_len, + size_t max_out) { return ssl == nullptr ? ssl_private_key_failure - : privateKeyCompleteInternal( + : rsaPrivateKeyCompleteInternal( static_cast(SSL_get_ex_data( ssl, CryptoMbPrivateKeyMethodProvider::connectionIndex())), out, out_len, max_out); @@ -381,9 +442,15 @@ ssl_private_key_result_t privateKeyComplete(SSL* ssl, uint8_t* out, size_t* out_ } // namespace // External linking, meant for testing without SSL context. -ssl_private_key_result_t privateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, uint8_t* out, - size_t* out_len, size_t max_out) { - return privateKeyCompleteInternal(ops, out, out_len, max_out); +ssl_private_key_result_t ecdsaPrivateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out) { + return ecdsaPrivateKeyCompleteInternal(ops, out, out_len, max_out); +} +ssl_private_key_result_t rsaPrivateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out) { + return rsaPrivateKeyCompleteInternal(ops, out, out_len, max_out); } ssl_private_key_result_t ecdsaPrivateKeySignForTest(CryptoMbPrivateKeyConnection* ops, uint8_t* out, size_t* out_len, size_t max_out, @@ -519,12 +586,8 @@ void CryptoMbQueue::processRsaRequests() { } void CryptoMbQueue::processEcdsaRequests() { - uint8_t sig_r[MULTIBUFF_BATCH][32]; - uint8_t sig_s[MULTIBUFF_BATCH][32]; - uint8_t* pa_sig_r[MULTIBUFF_BATCH] = {sig_r[0], sig_r[1], sig_r[2], sig_r[3], - sig_r[4], sig_r[5], sig_r[6], sig_r[7]}; - uint8_t* pa_sig_s[MULTIBUFF_BATCH] = {sig_s[0], sig_s[1], sig_s[2], sig_s[3], - sig_s[4], sig_s[5], sig_s[6], sig_s[7]}; + uint8_t* pa_sig_r[MULTIBUFF_BATCH] = {}; + uint8_t* pa_sig_s[MULTIBUFF_BATCH] = {}; const unsigned char* digest[MULTIBUFF_BATCH] = {nullptr}; const BIGNUM* eph_key[MULTIBUFF_BATCH] = {nullptr}; const BIGNUM* priv_key[MULTIBUFF_BATCH] = {nullptr}; @@ -533,6 +596,8 @@ void CryptoMbQueue::processEcdsaRequests() { for (unsigned req_num = 0; req_num < request_queue_.size(); req_num++) { CryptoMbEcdsaContextSharedPtr mb_ctx = std::static_pointer_cast(request_queue_[req_num]); + pa_sig_r[req_num] = mb_ctx->sig_r_; + pa_sig_s[req_num] = mb_ctx->sig_s_; digest[req_num] = mb_ctx->in_buf_.get(); eph_key[req_num] = mb_ctx->k_; priv_key[req_num] = mb_ctx->priv_key_; @@ -551,11 +616,7 @@ void CryptoMbQueue::processEcdsaRequests() { enum RequestStatus ctx_status; if (ipp_->mbxGetSts(ecdsa_sts, req_num)) { ENVOY_LOG(debug, "Multibuffer ECDSA request {} success", req_num); - if (postprocessEcdsaRequest(mb_ctx, pa_sig_r[req_num], pa_sig_s[req_num])) { - status[req_num] = RequestStatus::Success; - } else { - status[req_num] = RequestStatus::Error; - } + status[req_num] = RequestStatus::Success; } else { ENVOY_LOG(debug, "Multibuffer ECDSA request {} failure", req_num); status[req_num] = RequestStatus::Error; @@ -569,29 +630,6 @@ void CryptoMbQueue::processEcdsaRequests() { } } -bool CryptoMbQueue::postprocessEcdsaRequest(CryptoMbEcdsaContextSharedPtr mb_ctx, - const uint8_t* pa_sig_r, const uint8_t* pa_sig_s) { - ECDSA_SIG* sig = ECDSA_SIG_new(); - if (sig == nullptr) { - return false; - } - BIGNUM* sig_r = BN_bin2bn(pa_sig_r, 32, nullptr); - BIGNUM* sig_s = BN_bin2bn(pa_sig_s, 32, nullptr); - ECDSA_SIG_set0(sig, sig_r, sig_s); - - // Marshal signature into out_buf_. - CBB cbb; - if (!CBB_init_fixed(&cbb, mb_ctx->out_buf_, mb_ctx->sig_len_) || !ECDSA_SIG_marshal(&cbb, sig) || - !CBB_finish(&cbb, nullptr, &mb_ctx->out_len_)) { - CBB_cleanup(&cbb); - ECDSA_SIG_free(sig); - return false; - } - - ECDSA_SIG_free(sig); - return true; -} - CryptoMbPrivateKeyConnection::CryptoMbPrivateKeyConnection(Ssl::PrivateKeyConnectionCallbacks& cb, Event::Dispatcher& dispatcher, bssl::UniquePtr pkey, @@ -678,7 +716,7 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( method_->sign = rsaPrivateKeySign; method_->decrypt = rsaPrivateKeyDecrypt; - method_->complete = privateKeyComplete; + method_->complete = rsaPrivateKeyComplete; RSA* rsa = EVP_PKEY_get0_RSA(pkey.get()); switch (RSA_bits(rsa)) { @@ -722,7 +760,7 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider( method_->sign = ecdsaPrivateKeySign; method_->decrypt = ecdsaPrivateKeyDecrypt; - method_->complete = privateKeyComplete; + method_->complete = ecdsaPrivateKeyComplete; const EC_GROUP* ecdsa_group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey.get())); if (ecdsa_group == nullptr) { diff --git a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h index b3da76dab5a8..9806f64bac0d 100644 --- a/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h +++ b/contrib/cryptomb/private_key_providers/source/cryptomb_private_key_provider.h @@ -40,10 +40,6 @@ class CryptoMbContext { enum RequestStatus getStatus() { return status_; } void scheduleCallback(enum RequestStatus status); - // Buffer length is the same as the max signature length (4096 bits = 512 bytes) - unsigned char out_buf_[MAX_SIGNATURE_SIZE]; - // The real length of the signature. - size_t out_len_{}; // Incoming data buffer. std::unique_ptr in_buf_; @@ -75,6 +71,10 @@ class CryptoMbEcdsaContext : public CryptoMbContext { // BoringSSL ECDSA key structure, so not wrapped in smart pointers. const BIGNUM* priv_key_{}; size_t sig_len_{}; + + // ECDSA signature. + uint8_t sig_r_[32]{}; + uint8_t sig_s_[32]{}; }; // CryptoMbRsaContext is a CryptoMbContext which holds the extra RSA parameters and has @@ -103,6 +103,11 @@ class CryptoMbRsaContext : public CryptoMbContext { // Buffer for `Lenstra` check. unsigned char lenstra_to_[MAX_SIGNATURE_SIZE]; + + // Buffer length is the same as the max signature length (4096 bits = 512 bytes) + unsigned char out_buf_[MAX_SIGNATURE_SIZE]; + // The real length of the signature. + size_t out_len_{}; }; using CryptoMbContextSharedPtr = std::shared_ptr; @@ -123,8 +128,6 @@ class CryptoMbQueue : public Logger::Loggable { void processRequests(); void processRsaRequests(); void processEcdsaRequests(); - bool postprocessEcdsaRequest(CryptoMbEcdsaContextSharedPtr mb_ctx, const uint8_t* sign_r, - const uint8_t* sign_s); void startTimer(); void stopTimer(); diff --git a/contrib/cryptomb/private_key_providers/test/BUILD b/contrib/cryptomb/private_key_providers/test/BUILD index 6b4c01fa3ec4..2940695756b1 100644 --- a/contrib/cryptomb/private_key_providers/test/BUILD +++ b/contrib/cryptomb/private_key_providers/test/BUILD @@ -1,5 +1,6 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_cc_benchmark_binary", "envoy_cc_test", "envoy_cc_test_library", "envoy_contrib_package", @@ -82,3 +83,17 @@ envoy_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_cc_benchmark_binary( + name = "speed_test", + srcs = ["speed_test.cc"], + external_deps = [ + "benchmark", + "ssl", + ], + deps = [ + "//contrib/cryptomb/private_key_providers/source:ipp_crypto_wrapper_lib", + "//source/common/common:assert_lib", + "//source/common/common:utility_lib", + ], +) diff --git a/contrib/cryptomb/private_key_providers/test/ops_test.cc b/contrib/cryptomb/private_key_providers/test/ops_test.cc index d5f35db774b3..14761d8fea62 100644 --- a/contrib/cryptomb/private_key_providers/test/ops_test.cc +++ b/contrib/cryptomb/private_key_providers/test/ops_test.cc @@ -22,8 +22,12 @@ namespace PrivateKeyMethodProvider { namespace CryptoMb { // Testing interface -ssl_private_key_result_t privateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, uint8_t* out, - size_t* out_len, size_t max_out); +ssl_private_key_result_t ecdsaPrivateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out); +ssl_private_key_result_t rsaPrivateKeyCompleteForTest(CryptoMbPrivateKeyConnection* ops, + uint8_t* out, size_t* out_len, + size_t max_out); ssl_private_key_result_t ecdsaPrivateKeySignForTest(CryptoMbPrivateKeyConnection* ops, uint8_t* out, size_t* out_len, size_t max_out, uint16_t signature_algorithm, const uint8_t* in, @@ -148,14 +152,14 @@ TEST_F(CryptoMbProviderEcdsaTest, TestEcdsaSigning) { // No processing done after first requests. // After the last request, the status is set only from the event loop which is not run. This // should still be "retry", the cryptographic result is present anyway. - res_ = privateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); EXPECT_EQ(res_, ssl_private_key_retry); } // Timeout does not have to be triggered when queue is at maximum size. dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); } @@ -179,14 +183,14 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaPkcs1Signing) { // No processing done after first requests. // After the last request, the status is set only from the event loop which is not run. This // should still be "retry", the cryptographic result is present anyway. - res_ = privateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); EXPECT_EQ(res_, ssl_private_key_retry); } // Timeout does not have to be triggered when queue is at maximum size. dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -217,14 +221,14 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaPssSigning) { // No processing done after first requests. // After the last request, the status is set only from the event loop which is not run. This // should still be "retry", the cryptographic result is present anyway. - res_ = privateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); EXPECT_EQ(res_, ssl_private_key_retry); } // Timeout does not have to be triggered when queue is at maximum size. dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -263,14 +267,14 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaDecrypt) { // No processing done after first requests. // After the last request, the status is set only from the event loop which is not run. This // should still be "retry", the cryptographic result is present anyway. - res_ = privateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[i].get(), nullptr, nullptr, max_out_len_); EXPECT_EQ(res_, ssl_private_key_retry); } // Timeout does not have to be triggered when queue is at maximum size. dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); } @@ -333,14 +337,14 @@ TEST_F(CryptoMbProviderEcdsaTest, TestEcdsaTimer) { SSL_SIGN_ECDSA_SECP256R1_SHA256, in_, in_len_); EXPECT_EQ(res_, ssl_private_key_retry); - res_ = privateKeyCompleteForTest(&op0, nullptr, nullptr, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(&op0, nullptr, nullptr, max_out_len_); // No processing done yet after first request EXPECT_EQ(res_, ssl_private_key_retry); time_system_.advanceTimeAndRun(std::chrono::seconds(1), *dispatcher_, Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(&op0, out_, &out_len_, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(&op0, out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -354,14 +358,14 @@ TEST_F(CryptoMbProviderEcdsaTest, TestEcdsaTimer) { SSL_SIGN_ECDSA_SECP256R1_SHA256, in_, in_len_); EXPECT_EQ(res_, ssl_private_key_retry); - res_ = privateKeyCompleteForTest(&op1, nullptr, nullptr, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(&op1, nullptr, nullptr, max_out_len_); // No processing done yet after first request EXPECT_EQ(res_, ssl_private_key_retry); time_system_.advanceTimeAndRun(std::chrono::seconds(1), *dispatcher_, Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(&op1, out_, &out_len_, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(&op1, out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_failure); } @@ -374,14 +378,14 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaTimer) { in_, in_len_); EXPECT_EQ(res_, ssl_private_key_retry); - res_ = privateKeyCompleteForTest(&op0, nullptr, nullptr, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(&op0, nullptr, nullptr, max_out_len_); // No processing done yet after first request EXPECT_EQ(res_, ssl_private_key_retry); time_system_.advanceTimeAndRun(std::chrono::seconds(1), *dispatcher_, Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(&op0, out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(&op0, out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -395,14 +399,14 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaTimer) { in_, in_len_); EXPECT_EQ(res_, ssl_private_key_retry); - res_ = privateKeyCompleteForTest(&op1, nullptr, nullptr, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(&op1, nullptr, nullptr, max_out_len_); // No processing done yet after first request EXPECT_EQ(res_, ssl_private_key_retry); time_system_.advanceTimeAndRun(std::chrono::seconds(1), *dispatcher_, Event::Dispatcher::RunType::NonBlock); - res_ = privateKeyCompleteForTest(&op1, out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(&op1, out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_failure); } @@ -428,7 +432,7 @@ TEST_F(CryptoMbProviderEcdsaTest, TestEcdsaQueueSizeStatistics) { Event::Dispatcher::RunType::NonBlock); out_len_ = 0; - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -451,7 +455,7 @@ TEST_F(CryptoMbProviderEcdsaTest, TestEcdsaQueueSizeStatistics) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); out_len_ = 0; - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = ecdsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -483,7 +487,7 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaQueueSizeStatistics) { Event::Dispatcher::RunType::NonBlock); out_len_ = 0; - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); @@ -506,7 +510,7 @@ TEST_F(CryptoMbProviderRsaTest, TestRsaQueueSizeStatistics) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); out_len_ = 0; - res_ = privateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); + res_ = rsaPrivateKeyCompleteForTest(connections[0].get(), out_, &out_len_, max_out_len_); EXPECT_EQ(res_, ssl_private_key_success); EXPECT_NE(out_len_, 0); diff --git a/contrib/cryptomb/private_key_providers/test/speed_test.cc b/contrib/cryptomb/private_key_providers/test/speed_test.cc new file mode 100644 index 000000000000..f5e8b87b9f47 --- /dev/null +++ b/contrib/cryptomb/private_key_providers/test/speed_test.cc @@ -0,0 +1,523 @@ +#include "source/common/common/assert.h" + +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" +#include "openssl/curve25519.h" +#include "openssl/evp.h" +#include "openssl/pem.h" +#include "openssl/rand.h" +#include "openssl/ssl.h" + +#ifndef IPP_CRYPTO_DISABLED +#include "crypto_mb/ec_nistp256.h" +#include "crypto_mb/rsa.h" +#include "crypto_mb/x25519.h" +#endif + +namespace Envoy { + +constexpr absl::string_view RsaKey = R"EOF( +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAtBPRFC+8WpCauAyIr1uCTSK6qtAeevEW1vRkn/KkFQX27UWS +NgU/IukTbA091BDae7HEiWSp7IA1IDbu2q4IwY9UksjF8yFVNZYifr/IzS6lbHOI +ZRxuBzQOWgn0+7WNqzylXQ4y88yVVqSsdfiB8kJHi9o5r+M/3TBOrWCu75iYJeBV +w0nhMYIYOxB0RkPqB1+5z4cgLjyZYuC6iZe+9m718J4LRHTd60lg9wtg4H7RUE3u +VgjLSNpNyvVpOW2qHq+o21gdS7xBQ3pbD619vBWeNDkvCaBp6YZw4ENhUxeg4xaZ +nOrNEKZw4HQnzklDJe1a69InQI6F2b/26VEGgQIDAQABAoIBABKTzMkBV7QcIOoF +2QAGN74PbCR9Dffu8UVBtzPNC2Jj2CKIP9o01luaofdOsmczSebi4vytlt4gJ9rn +7+I9fAfD6pyt+8XmVW0OzQY4cNXCDyzOCm8r7Knvk990EYL6KuBUhFbCRT1jiLCE +koolFfrRHaJu4+6iSg9ekW9PfxyWfAxtEp4XrrqgN4jN3Lrx1rYCZnuYp3Lb+7WI +fJC/rK6MTphUMLbPMvmUwHjFzoe7g9MZxRRY3kY3h1n3Ju1ZbaCbP0Vi/+tdgKAl +290J2MStWWJfOoTNnnOSYhWIPQUiFtuUiab7tJ90GGb1DyLbOrr6wG2awJoqF9ZM +Qwvkf/UCgYEA5dsHhxuX+cTHF6m+aGuyB0pF/cnFccTtwWz2WwiH6tldnOAIPfSi +WJU33C988KwJFmAurcW43VVVs7fxYbC6ptQluEI+/L/3Mj/3WgwZaqX00cEPkzKA +M1XbvanQAU0nGfq+ja7sZVpdbBoBUb6Bh7HFyLM3LgliT0kMQeolKXMCgYEAyI9W +tEHnkHoPjAVSSobBOqCVpTp1WGb7XoxhahjjZcTOgxucna26mUyJeHQrOPp88PJo +xxdDJU410p/tZARtFBoAa++IK9qC6QLjN23CuwhD7y6RNZsRZg0kOCg9SLj+zVj5 +mrvZFf6663EpL82UZ2zUGl4L1sMhYkia0TMjYzsCgYAFHuAIDoFQOyYETO/E+8E3 +kFwGz1vqsOxrBrZmSMZeYQFI4WTNnImRV6Gq8hPieLKrIPFpRaJcq+4A1vQ1rO47 +kTZV6IPmtZAYOnyUMPjP+2p80cQ7D0Dz49HFY+cSYFmipodgOKljiKPUKLAm1guk +rj0tv3BXQjZCdeoj/cdeKQKBgF8u3+hWqs5/j2dVkzN5drUbR0oOT2iwHzZFC2pt ++2XuHFBOx2px6/AbSdbX0zeMccVsVlu+Z4iJ8LNQYTqpexciK/cNzCN75csuKqXA +ur1G8+7Mu++j84LqU7kvJ76exZaxVmygICv3I8DfiLt+JqNbG+KTpay8GNjrOkZ0 +raPHAoGAQ1p/Qvp7DHP2qOnUB/rItEVgWECD3uPx4NOCq7Zcx7mb9p7CI6nePT5y +heHpaJIqVyaS5/LHJDwvdB1nvtlgc9xKa5d1fWhLL3dwFCa98x5PDlN/JztH8DIt +tTlD+8NECIvI+ytbzLS0PZWBYctAR2rP2qlMCGdYerdjwl8S98E= +-----END RSA PRIVATE KEY----- +)EOF"; + +constexpr absl::string_view EcdsaKey = R"EOF( +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMpJw5U66K+DcA963b+/jZYrMrZDjaB0khHSwZte3vYCoAoGCCqGSM49 +AwEHoUQDQgAELp3XvBfkVWQBOKo3ttAaJ6SUaUb8uKqCS504WXHWMO4h89F+nYtC +Ecgl8EiLXXyc86tawKjGdizcCjrKMiFo3A== +-----END EC PRIVATE KEY----- +)EOF"; + +bssl::UniquePtr makeEcdsaKey() { + bssl::UniquePtr bio(BIO_new_mem_buf(EcdsaKey.data(), EcdsaKey.size())); + bssl::UniquePtr key(EVP_PKEY_new()); + EC_KEY* ec = PEM_read_bio_ECPrivateKey(bio.get(), nullptr, nullptr, nullptr); + RELEASE_ASSERT(ec != nullptr, "PEM_read_bio_ECPrivateKey failed."); + RELEASE_ASSERT(1 == EVP_PKEY_assign_EC_KEY(key.get(), ec), "EVP_PKEY_assign_EC_KEY failed."); + return key; +} + +bssl::UniquePtr makeRsaKey() { + bssl::UniquePtr bio(BIO_new_mem_buf(RsaKey.data(), RsaKey.size())); + bssl::UniquePtr key(EVP_PKEY_new()); + RSA* rsa = PEM_read_bio_RSAPrivateKey(bio.get(), nullptr, nullptr, nullptr); + RELEASE_ASSERT(rsa != nullptr, "PEM_read_bio_RSAPrivateKey failed."); + RELEASE_ASSERT(1 == EVP_PKEY_assign_RSA(key.get(), rsa), "EVP_PKEY_assign_RSA failed."); + return key; +} + +const std::vector& message() { CONSTRUCT_ON_FIRST_USE(std::vector, 32, 127); } + +int calculateDigest(const EVP_MD* md, const uint8_t* in, size_t in_len, unsigned char* hash, + unsigned int* hash_len) { + bssl::ScopedEVP_MD_CTX ctx; + + // Calculate the message digest for signing. + if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) || !EVP_DigestUpdate(ctx.get(), in, in_len) || + !EVP_DigestFinal_ex(ctx.get(), hash, hash_len)) { + return 0; + } + return 1; +} + +void verifyEcdsa(EC_KEY* ec_key, uint8_t* out, uint32_t out_len) { + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_ECDSA_SECP256R1_SHA256); + uint8_t hash[EVP_MAX_MD_SIZE]; + uint32_t hash_len; + calculateDigest(md, message().data(), message().size(), hash, &hash_len); + + EXPECT_EQ(ECDSA_verify(0, hash, hash_len, out, out_len, ec_key), 1); +} + +void verifyRsa(RSA* rsa, uint8_t* out, uint32_t out_len) { + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_RSA_PSS_SHA256); + uint8_t buf[32]; + uint32_t buf_len; + calculateDigest(md, message().data(), message().size(), buf, &buf_len); + + EXPECT_EQ(RSA_verify_pss_mgf1(rsa, buf, buf_len, md, nullptr, -1, out, out_len), 1); +} + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_ECDSA_Signing(benchmark::State& state) { + bssl::UniquePtr pkey = makeEcdsaKey(); + uint8_t out[512]; + uint32_t out_len; + for (auto _ : state) { // NOLINT + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_ECDSA_SECP256R1_SHA256); + + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len; + calculateDigest(md, message().data(), message().size(), hash, &hash_len); + + ECDSA_sign(0, hash, hash_len, out, &out_len, ec_key); + } + + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + verifyEcdsa(ec_key, out, out_len); + + state.counters["Requests"] = benchmark::Counter(state.iterations(), benchmark::Counter::kIsRate); +} +BENCHMARK(BM_ECDSA_Signing); + +#ifndef IPP_CRYPTO_DISABLED +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_ECDSA_Signing_CryptoMB(benchmark::State& state) { + bssl::UniquePtr pkey = makeEcdsaKey(); + uint8_t out[8][512]; + size_t out_len[8]; + for (auto _ : state) { // NOLINT + std::unique_ptr in_buf[8]; + size_t sig_len[8]; + const BIGNUM* priv_key[8]; + bssl::UniquePtr ctx[8]; + BIGNUM* k[8]; + for (int i = 0; i < 8; i++) { + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_ECDSA_SECP256R1_SHA256); + + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len; + calculateDigest(md, message().data(), message().size(), hash, &hash_len); + + priv_key[i] = EC_KEY_get0_private_key(ec_key); + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + const BIGNUM* order = EC_GROUP_get0_order(group); + ctx[i] = bssl::UniquePtr(BN_CTX_new()); + BN_CTX_start(ctx[i].get()); + k[i] = BN_CTX_get(ctx[i].get()); + while (BN_is_zero(k[i])) { + BN_rand_range(k[i], order); + } + + int len = BN_num_bits(order); + size_t buf_len = (len + 7) / 8; + if (8 * hash_len < static_cast(len)) { + in_buf[i] = std::make_unique(buf_len); + memcpy(in_buf[i].get() + buf_len - hash_len, hash, hash_len); + } else { + in_buf[i] = std::make_unique(hash_len); + memcpy(in_buf[i].get(), hash, hash_len); + } + sig_len[i] = ECDSA_size(ec_key); + } + + uint8_t sig_r[8][32]; + uint8_t sig_s[8][32]; + uint8_t* pa_sig_r[8]; + uint8_t* pa_sig_s[8]; + const uint8_t* digest[8]; + for (int i = 0; i < 8; i++) { + pa_sig_r[i] = sig_r[i]; + pa_sig_s[i] = sig_s[i]; + digest[i] = in_buf[i].get(); + } + mbx_nistp256_ecdsa_sign_ssl_mb8(pa_sig_r, pa_sig_s, digest, k, priv_key, nullptr); + + for (int i = 0; i < 8; i++) { + ECDSA_SIG* sig = ECDSA_SIG_new(); + BIGNUM* cur_sig_r = BN_bin2bn(sig_r[i], 32, nullptr); + BIGNUM* cur_sig_s = BN_bin2bn(sig_s[i], 32, nullptr); + ECDSA_SIG_set0(sig, cur_sig_r, cur_sig_s); + + CBB cbb; + CBB_init_fixed(&cbb, out[i], sig_len[i]); + ECDSA_SIG_marshal(&cbb, sig); + CBB_finish(&cbb, nullptr, &out_len[i]); + ECDSA_SIG_free(sig); + } + } + + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get()); + for (int i = 0; i < 8; i++) { + verifyEcdsa(ec_key, out[i], out_len[i]); + } + + state.counters["Requests"] = + benchmark::Counter(state.iterations() * 8, benchmark::Counter::kIsRate); +} +BENCHMARK(BM_ECDSA_Signing_CryptoMB); +#endif + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_RSA_Signing(benchmark::State& state) { + bssl::UniquePtr pkey = makeRsaKey(); + uint8_t out[512]; + size_t out_len; + for (auto _ : state) { // NOLINT + RSA* rsa = EVP_PKEY_get0_RSA(pkey.get()); + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_RSA_PSS_SHA256); + + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len; + calculateDigest(md, message().data(), message().size(), hash, &hash_len); + + RSA_sign_pss_mgf1(rsa, &out_len, out, 256, hash, hash_len, md, nullptr, -1); + } + + RSA* rsa = EVP_PKEY_get0_RSA(pkey.get()); + verifyRsa(rsa, out, out_len); + + state.counters["Requests"] = benchmark::Counter(state.iterations(), benchmark::Counter::kIsRate); +} +BENCHMARK(BM_RSA_Signing); + +#ifndef IPP_CRYPTO_DISABLED +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_RSA_Signing_CryptoMB(benchmark::State& state) { + bssl::UniquePtr pkey = makeRsaKey(); + uint8_t out[8][512]; + uint32_t out_len[8]; + for (auto _ : state) { // NOLINT + std::unique_ptr in_buf[8]; + uint32_t out_buf_len[8]; + const BIGNUM* p[8]; + const BIGNUM* q[8]; + const BIGNUM* dmp1[8]; + const BIGNUM* dmq1[8]; + const BIGNUM* iqmp[8]; + for (int i = 0; i < 8; i++) { + RSA* rsa = EVP_PKEY_get0_RSA(pkey.get()); + const EVP_MD* md = SSL_get_signature_algorithm_digest(SSL_SIGN_RSA_PSS_SHA256); + + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len; + calculateDigest(md, message().data(), message().size(), hash, &hash_len); + + size_t msg_len = RSA_size(rsa); + uint8_t* msg = static_cast(OPENSSL_malloc(msg_len)); + RSA_padding_add_PKCS1_PSS_mgf1(rsa, msg, hash, md, nullptr, -1); + + RSA_get0_factors(rsa, &p[i], &q[i]); + RSA_get0_crt_params(rsa, &dmp1[i], &dmq1[i], &iqmp[i]); + + out_buf_len[i] = msg_len; + in_buf[i] = std::make_unique(msg_len); + memcpy(in_buf[i].get(), msg, msg_len); + OPENSSL_free(msg); + } + + uint8_t out_buf[8][512]; + const uint8_t* from[8]; + uint8_t* to[8]; + for (int i = 0; i < 8; i++) { + from[i] = in_buf[i].get(); + to[i] = out_buf[i]; + } + mbx_rsa_private_crt_ssl_mb8(from, to, p, q, dmp1, dmq1, iqmp, out_buf_len[0] * 8); + + for (int i = 0; i < 8; i++) { + out_len[i] = out_buf_len[i]; + memcpy(out[i], out_buf[i], out_buf_len[i]); + } + } + + RSA* rsa = EVP_PKEY_get0_RSA(pkey.get()); + for (int i = 0; i < 8; i++) { + verifyRsa(rsa, out[i], out_len[i]); + } + + state.counters["Requests"] = + benchmark::Counter(state.iterations() * 8, benchmark::Counter::kIsRate); +} +BENCHMARK(BM_RSA_Signing_CryptoMB); +#endif + +const std::vector& x25519Key() { + CONSTRUCT_ON_FIRST_USE(std::vector, + {143, 108, 246, 59, 152, 5, 67, 152, 220, 11, 144, + 198, 61, 43, 240, 209, 94, 190, 231, 111, 57, 42, + 141, 225, 230, 220, 231, 252, 50, 205, 236, 181}); +} + +const std::vector& x25519PeerKey() { + CONSTRUCT_ON_FIRST_USE(std::vector, + {64, 109, 230, 49, 46, 217, 20, 68, 22, 16, 129, + 224, 53, 100, 61, 184, 204, 65, 60, 10, 60, 73, + 62, 45, 192, 238, 74, 116, 237, 230, 155, 63}); +} + +const std::vector& p256Key() { + CONSTRUCT_ON_FIRST_USE(std::vector, + {154, 198, 171, 184, 138, 154, 154, 228, 142, 151, 103, + 249, 233, 0, 68, 110, 166, 26, 232, 232, 71, 127, + 53, 107, 249, 233, 71, 125, 136, 239, 141, 143}); +} + +const std::vector& p256PeerKey() { + CONSTRUCT_ON_FIRST_USE(std::vector, + {4, 0, 125, 68, 149, 141, 169, 88, 123, 178, 63, 48, 93, + 53, 234, 36, 240, 255, 93, 0, 165, 216, 140, 3, 12, 220, + 201, 27, 126, 171, 36, 172, 205, 175, 174, 17, 128, 214, 28, + 189, 58, 138, 133, 149, 148, 84, 2, 46, 144, 172, 236, 7, + 226, 234, 110, 168, 52, 119, 85, 146, 77, 157, 59, 39, 122}); +} + +void verifyX25519(uint8_t* ciphertext, uint8_t* secret) { + uint8_t peer_secret[32]; + X25519(peer_secret, x25519Key().data(), ciphertext); + + EXPECT_EQ(CRYPTO_memcmp(secret, peer_secret, 32), 0); +} + +void verifyP256(uint8_t* ciphertext, uint8_t* secret) { + bssl::UniquePtr key(BN_new()); + BN_bin2bn(p256Key().data(), p256Key().size(), key.get()); + + const EC_GROUP* group = EC_group_p256(); + bssl::UniquePtr point(EC_POINT_new(group)); + EC_POINT_oct2point(group, point.get(), ciphertext, 65, nullptr); + bssl::UniquePtr result(EC_POINT_new(group)); + bssl::UniquePtr x(BN_new()); + EC_POINT_mul(group, result.get(), nullptr, point.get(), key.get(), nullptr); + EC_POINT_get_affine_coordinates_GFp(group, result.get(), x.get(), nullptr, nullptr); + + uint8_t peer_secret[32]; + BN_bn2bin_padded(peer_secret, 32, x.get()); + + EXPECT_EQ(CRYPTO_memcmp(secret, peer_secret, 32), 0); +} + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_X25519_Computing(benchmark::State& state) { + uint8_t ciphertext[32]; + uint8_t secret[32]; + for (auto _ : state) { // NOLINT + uint8_t priv_key[32]; + uint8_t public_key[32]; + X25519_keypair(public_key, priv_key); + memcpy(ciphertext, public_key, 32); + + X25519(secret, priv_key, x25519PeerKey().data()); + } + + verifyX25519(ciphertext, secret); + + state.counters["Requests"] = benchmark::Counter(state.iterations(), benchmark::Counter::kIsRate); +} +BENCHMARK(BM_X25519_Computing); + +#ifndef IPP_CRYPTO_DISABLED +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_X25519_Computing_CryptoMB(benchmark::State& state) { + uint8_t ciphertext[8][32]; + uint8_t secret[8][32]; + for (auto _ : state) { // NOLINT + uint8_t priv_key[8][32]; + // NOLINTNEXTLINE(modernize-loop-convert) + for (int i = 0; i < 8; i++) { + RAND_bytes(priv_key[i], 32); + priv_key[i][0] |= ~248; + priv_key[i][31] &= ~64; + priv_key[i][31] |= ~127; + } + + uint8_t pub_key[8][32]; + const uint8_t* pa_priv_key[8]; + uint8_t* pa_pub_key[8]; + for (int i = 0; i < 8; i++) { + pa_priv_key[i] = priv_key[i]; + pa_pub_key[i] = pub_key[i]; + } + mbx_x25519_public_key_mb8(pa_pub_key, pa_priv_key); + + uint8_t shared_key[8][32]; + uint8_t* pa_shared_key[8]; + const uint8_t* pa_peer_key[8]; + for (int i = 0; i < 8; i++) { + pa_shared_key[i] = shared_key[i]; + pa_peer_key[i] = x25519PeerKey().data(); + } + mbx_x25519_mb8(pa_shared_key, pa_priv_key, pa_peer_key); + + for (int i = 0; i < 8; i++) { + memcpy(ciphertext[i], pub_key[i], 32); + memcpy(secret[i], pa_shared_key[i], 32); + } + } + + for (int i = 0; i < 8; i++) { + verifyX25519(ciphertext[i], secret[i]); + } + + state.counters["Requests"] = + benchmark::Counter(state.iterations() * 8, benchmark::Counter::kIsRate); +} +BENCHMARK(BM_X25519_Computing_CryptoMB); +#endif + +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_P256_Computing(benchmark::State& state) { + uint8_t ciphertext[65]; + uint8_t secret[32]; + for (auto _ : state) { // NOLINT + const EC_GROUP* group = EC_group_p256(); + bssl::UniquePtr priv_key(BN_new()); + BN_rand_range_ex(priv_key.get(), 1, EC_GROUP_get0_order(group)); + bssl::UniquePtr public_key(EC_POINT_new(group)); + EC_POINT_mul(group, public_key.get(), priv_key.get(), nullptr, nullptr, nullptr); + EC_POINT_point2oct(group, public_key.get(), POINT_CONVERSION_UNCOMPRESSED, ciphertext, 65, + nullptr); + + bssl::UniquePtr peer_point(EC_POINT_new(group)); + EC_POINT_oct2point(group, peer_point.get(), p256PeerKey().data(), p256PeerKey().size(), + nullptr); + bssl::UniquePtr result(EC_POINT_new(group)); + bssl::UniquePtr x(BN_new()); + EC_POINT_mul(group, result.get(), nullptr, peer_point.get(), priv_key.get(), nullptr); + EC_POINT_get_affine_coordinates_GFp(group, result.get(), x.get(), nullptr, nullptr); + + BN_bn2bin_padded(secret, 32, x.get()); + } + + verifyP256(ciphertext, secret); + + state.counters["Requests"] = benchmark::Counter(state.iterations(), benchmark::Counter::kIsRate); +} +BENCHMARK(BM_P256_Computing); + +#ifndef IPP_CRYPTO_DISABLED +// NOLINTNEXTLINE(readability-identifier-naming) +static void BM_P256_Computing_CryptoMB(benchmark::State& state) { + const EC_GROUP* group = EC_group_p256(); + uint8_t ciphertext[8][65]; + uint8_t secret[8][32]; + for (auto _ : state) { // NOLINT + bssl::UniquePtr priv_key[8]; + // NOLINTNEXTLINE(modernize-loop-convert) + for (int i = 0; i < 8; i++) { + priv_key[i].reset(BN_new()); + BN_rand_range_ex(priv_key[i].get(), 1, EC_GROUP_get0_order(group)); + } + + bssl::UniquePtr pub_x[8]; + bssl::UniquePtr pub_y[8]; + BIGNUM* pa_pub_x[8]; + BIGNUM* pa_pub_y[8]; + const BIGNUM* pa_priv_key[8]; + for (int i = 0; i < 8; i++) { + pub_x[i].reset(BN_new()); + pub_y[i].reset(BN_new()); + pa_pub_x[i] = pub_x[i].get(); + pa_pub_y[i] = pub_y[i].get(); + pa_priv_key[i] = priv_key[i].get(); + } + mbx_nistp256_ecpublic_key_ssl_mb8(pa_pub_x, pa_pub_y, nullptr, pa_priv_key, nullptr); + + uint8_t out_ciphertext[8][65]; + bssl::UniquePtr public_key[8]; + for (int i = 0; i < 8; i++) { + public_key[i].reset(EC_POINT_new(group)); + EC_POINT_set_affine_coordinates_GFp(group, public_key[i].get(), pub_x[i].get(), + pub_y[i].get(), nullptr); + EC_POINT_point2oct(group, public_key[i].get(), POINT_CONVERSION_UNCOMPRESSED, + out_ciphertext[i], 65, nullptr); + } + + bssl::UniquePtr peer_x[8]; + bssl::UniquePtr peer_y[8]; + for (int i = 0; i < 8; i++) { + peer_x[i].reset(BN_new()); + peer_y[i].reset(BN_new()); + bssl::UniquePtr peer_key(EC_POINT_new(group)); + EC_POINT_oct2point(group, peer_key.get(), p256PeerKey().data(), p256PeerKey().size(), + nullptr); + EC_POINT_get_affine_coordinates_GFp(group, peer_key.get(), peer_x[i].get(), peer_y[i].get(), + nullptr); + } + + uint8_t shared_key[8][32] = {}; + uint8_t* pa_shared_key[8]; + BIGNUM* pa_peer_x[8]; + BIGNUM* pa_peer_y[8]; + for (int i = 0; i < 8; i++) { + pa_shared_key[i] = shared_key[i]; + pa_peer_x[i] = peer_x[i].get(); + pa_peer_y[i] = peer_y[i].get(); + } + mbx_nistp256_ecdh_ssl_mb8(pa_shared_key, pa_priv_key, pa_peer_x, pa_peer_y, nullptr, nullptr); + + for (int i = 0; i < 8; i++) { + memcpy(ciphertext[i], out_ciphertext[i], 65); + memcpy(secret[i], pa_shared_key[i], 32); + } + } + + for (int i = 0; i < 8; i++) { + verifyP256(ciphertext[i], secret[i]); + } + + state.counters["Requests"] = + benchmark::Counter(state.iterations() * 8, benchmark::Counter::kIsRate); +} +BENCHMARK(BM_P256_Computing_CryptoMB); +#endif + +} // namespace Envoy