Move functions from public_metdata_crypto_utils into crypto_utils. PiperOrigin-RevId: 518104334
diff --git a/build/source_list.bzl b/build/source_list.bzl index d592628..749ab21 100644 --- a/build/source_list.bzl +++ b/build/source_list.bzl
@@ -1551,7 +1551,6 @@ "blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h", "blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h", "blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.h", - "blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h", "blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h", "blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h", "blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.h", @@ -1567,7 +1566,6 @@ "blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.cc", - "blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc", "blind_sign_auth/blind_sign_auth.cc", @@ -1580,7 +1578,6 @@ "blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils_test.cc", - "blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc", "blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder_test.cc", "blind_sign_auth/blind_sign_auth_test.cc", "blind_sign_auth/cached_blind_sign_auth_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni index cd27eea..69ef202 100644 --- a/build/source_list.gni +++ b/build/source_list.gni
@@ -1551,7 +1551,6 @@ "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.h", - "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.h", @@ -1567,7 +1566,6 @@ "src/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.cc", - "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc", "src/quiche/blind_sign_auth/blind_sign_auth.cc", @@ -1580,7 +1578,6 @@ "src/quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils_test.cc", - "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc", "src/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder_test.cc", "src/quiche/blind_sign_auth/blind_sign_auth_test.cc", "src/quiche/blind_sign_auth/cached_blind_sign_auth_test.cc",
diff --git a/build/source_list.json b/build/source_list.json index 7f8511c..aec8a99 100644 --- a/build/source_list.json +++ b/build/source_list.json
@@ -1550,7 +1550,6 @@ "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.h", - "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.h", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.h", @@ -1566,7 +1565,6 @@ "quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils.cc", - "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc", "quiche/blind_sign_auth/blind_sign_auth.cc", @@ -1579,7 +1577,6 @@ "quiche/blind_sign_auth/anonymous_tokens/cpp/client/anonymous_tokens_rsa_bssa_client_test.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/proto_utils_test.cc", - "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc", "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder_test.cc", "quiche/blind_sign_auth/blind_sign_auth_test.cc", "quiche/blind_sign_auth/cached_blind_sign_auth_test.cc"
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc index 2e0005f..342ee56 100644 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc +++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/at_crypto_utils_test.cc
@@ -14,14 +14,18 @@ #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h" +#include <memory> #include <string> +#include <utility> #include <vector> #include "quiche/common/platform/api/quiche_test.h" #include "quiche/common/test_tools/quiche_test_utils.h" #include "absl/strings/escaping.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.h" +#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" #include "openssl/base.h" +#include "openssl/rsa.h" namespace private_membership { namespace anonymous_tokens { @@ -144,6 +148,234 @@ INSTANTIATE_TEST_SUITE_P(ComputeHashTests, ComputeHashTest, testing::ValuesIn(GetComputeHashTestParams())); +std::pair<RSAPublicKey, std::string> GetFixedTestPublicKeyAndPublicMetadata() { + RSAPublicKey public_key; + public_key.set_n(absl::HexStringToBytes( + "b2ae391467872a7506468a9ac4e980fa76164666955ef8999917295dbbd89dd7aa9c0e41" + "2dcda3dd1aa867e0c414d80afb9544a7c71c32d83e1b8417f293f325d2ffe2f9e296d28f" + "b89a443de5cc06ab3c516913fc18694539c370315d3e7f4ac5f87faaf3fee751c9f439ae" + "8d53eee249d8c49b33bd3bb7aa060eb462522da98a02f92eff110cc9408ca0ccc54abf2c" + "fcb68b77fb0ec7048d8b76416f61f2b182ea73169ed18f0d1d238dcaf6fc9de067d4831f" + "68f485483dd5c9ec17d9384825ba7284bc38bb1ea5e40d9207d9007e609a19e3fab695a1" + "8c30f1a7c4b03c77ef72211415a0bfeacd3298dccafa7e06e41dc2131f9076b92bb352c8" + "f7bccfe9")); + public_key.set_e(absl::HexStringToBytes("03")); + std::string public_metadata = absl::HexStringToBytes("6d65746164617461"); + return std::make_pair(std::move(public_key), std::move(public_metadata)); +} + +std::string GetFixedTestNewPublicKeyExponentUnderPublicMetadata() { + std::string new_e = absl::HexStringToBytes( + "0b2d80537b4c899c7107eef3b74ddc0dcd931aff9c583ce3cf3527d42483052b27d55dd4" + "d2f831a38430f13d81574c51aa97af6f5c3a6c03b269bc156d029273bd60e7af578fff15" + "c52cbb5c19288fd1ce59f6f756b2d93b6f2586210fb969efb5065700da5598bb8914d395" + "4d97a49c5ca05b2386bc3cf098281958cf372481"); + return new_e; +} + +using CreateTestKeyPairFunction = + absl::StatusOr<std::pair<RSAPublicKey, RSAPrivateKey>>(); + +class CryptoUtilsTest + : public testing::TestWithParam<CreateTestKeyPairFunction*> { + protected: + void SetUp() override { + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto keys_pair, (*GetParam())()); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + private_key_, AnonymousTokensRSAPrivateKeyToRSA(keys_pair.second)); + public_key_ = std::move(keys_pair.first); + } + + bssl::UniquePtr<RSA> private_key_; + RSAPublicKey public_key_; +}; + +TEST_P(CryptoUtilsTest, PublicExponentCoprime) { + std::string metadata = "md"; + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> exp, + PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata)); + int rsa_mod_size_bits = BN_num_bits(RSA_get0_n(private_key_.get())); + // Check that exponent is odd. + EXPECT_EQ(BN_is_odd(exp.get()), 1); + // Check that exponent is small enough. + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> sqrt2, + GetRsaSqrtTwo(rsa_mod_size_bits / 2)); + EXPECT_LT(BN_cmp(exp.get(), sqrt2.get()), 0); + EXPECT_LT(BN_cmp(exp.get(), RSA_get0_p(private_key_.get())), 0); + EXPECT_LT(BN_cmp(exp.get(), RSA_get0_q(private_key_.get())), 0); +} + +TEST_P(CryptoUtilsTest, PublicExponentHash) { + std::string metadata1 = "md1"; + std::string metadata2 = "md2"; + // Check that hash is deterministic. + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> exp1, + PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata1)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> another_exp1, + PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata1)); + EXPECT_EQ(BN_cmp(exp1.get(), another_exp1.get()), 0); + // Check that hashes are distinct for different metadata. + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> exp2, + PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata2)); + EXPECT_NE(BN_cmp(exp1.get(), exp2.get()), 0); +} + +TEST_P(CryptoUtilsTest, FinalExponentCoprime) { + std::string metadata = "md"; + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> final_exponent, + ComputeFinalExponentUnderPublicMetadata(*RSA_get0_n(private_key_.get()), + *RSA_get0_e(private_key_.get()), + metadata)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(BnCtxPtr ctx, GetAndStartBigNumCtx()); + + // Check that exponent is odd. + EXPECT_EQ(BN_is_odd(final_exponent.get()), 1); + // Check that exponent is co-prime to factors of the rsa modulus. + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> gcd_p_fe, + NewBigNum()); + ASSERT_EQ(BN_gcd(gcd_p_fe.get(), RSA_get0_p(private_key_.get()), + final_exponent.get(), ctx.get()), + 1); + EXPECT_EQ(BN_cmp(gcd_p_fe.get(), BN_value_one()), 0); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> gcd_q_fe, + NewBigNum()); + ASSERT_EQ(BN_gcd(gcd_q_fe.get(), RSA_get0_q(private_key_.get()), + final_exponent.get(), ctx.get()), + 1); + EXPECT_EQ(BN_cmp(gcd_q_fe.get(), BN_value_one()), 0); +} + +TEST_P(CryptoUtilsTest, DeterministicRSAPublicKeyToRSAUnderPublicMetadata) { + std::string metadata = "md"; + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> rsa_public_key_1, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> rsa_public_key_2, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata)); + EXPECT_EQ(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), + RSA_get0_e(rsa_public_key_2.get())), + 0); +} + +TEST_P(CryptoUtilsTest, + DifferentPublicMetadataRSAPublicKeyToRSAUnderPublicMetadata) { + std::string metadata_1 = "md1"; + std::string metadata_2 = "md2"; + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> rsa_public_key_1, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata_1)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> rsa_public_key_2, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata_2)); + // Check that exponent is different in all keys + EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), + RSA_get0_e(rsa_public_key_2.get())), + 0); + EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), + RSA_get0_e(private_key_.get())), + 0); + EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), + RSA_get0_e(private_key_.get())), + 0); +} + +TEST_P(CryptoUtilsTest, NoPublicMetadataRSAPublicKeyToRSAUnderPublicMetadata) { + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> rsa_public_key, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_, "")); + + // Check that exponent is same in output and input. + EXPECT_EQ( + BN_cmp(RSA_get0_e(rsa_public_key.get()), RSA_get0_e(private_key_.get())), + 0); + // Check that rsa_modulus is correct + EXPECT_EQ( + BN_cmp(RSA_get0_n(rsa_public_key.get()), RSA_get0_n(private_key_.get())), + 0); +} + +INSTANTIATE_TEST_SUITE_P(CryptoUtilsTest, CryptoUtilsTest, + testing::Values(&GetStrongRsaKeys2048, + &GetAnotherStrongRsaKeys2048, + &GetStrongRsaKeys3072, + &GetStrongRsaKeys4096)); + +TEST(CryptoUtilsInternalTest, PublicMetadataHashWithHKDF) { + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(BnCtxPtr ctx, GetAndStartBigNumCtx()); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> max_value, + NewBigNum()); + ASSERT_TRUE(BN_set_word(max_value.get(), 4294967296)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair, GetStrongRsaKeys2048()); + std::string input1 = "ro1"; + std::string input2 = "ro2"; + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> output1, + internal::PublicMetadataHashWithHKDF(input1, key_pair.first.n(), + 1 + input1.size())); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> another_output1, + internal::PublicMetadataHashWithHKDF(input1, key_pair.first.n(), + 1 + input1.size())); + EXPECT_EQ(BN_cmp(output1.get(), another_output1.get()), 0); + + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> output2, + internal::PublicMetadataHashWithHKDF(input2, key_pair.first.n(), + 1 + input2.size())); + EXPECT_NE(BN_cmp(output1.get(), output2.get()), 0); + + EXPECT_LT(BN_cmp(output1.get(), max_value.get()), 0); + EXPECT_LT(BN_cmp(output2.get(), max_value.get()), 0); +} + +TEST(CryptoUtilsTest, PublicExponentHashDifferentModulus) { + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair_1, GetStrongRsaKeys2048()); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair_2, + GetAnotherStrongRsaKeys2048()); + std::string metadata = "md"; + // Check that same metadata and different modulus result in different + // hashes. + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + auto rsa_private_key_1, + AnonymousTokensRSAPrivateKeyToRSA(key_pair_1.second)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> exp1, + PublicMetadataExponent(*RSA_get0_n(rsa_private_key_1.get()), metadata)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + auto rsa_private_key_2, + AnonymousTokensRSAPrivateKeyToRSA(key_pair_2.second)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> exp2, + PublicMetadataExponent(*RSA_get0_n(rsa_private_key_2.get()), metadata)); + EXPECT_NE(BN_cmp(exp1.get(), exp2.get()), 0); +} + +TEST(CryptoUtilsTest, FixedTestRSAPublicKeyToRSAUnderPublicMetadata) { + const auto public_key_and_metadata = GetFixedTestPublicKeyAndPublicMetadata(); + const std::string expected_new_e_str = + GetFixedTestNewPublicKeyExponentUnderPublicMetadata(); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<BIGNUM> rsa_modulus, + StringToBignum(public_key_and_metadata.first.n())); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> expected_new_e, + StringToBignum(expected_new_e_str)); + ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( + bssl::UniquePtr<RSA> modified_rsa_public_key, + RSAPublicKeyToRSAUnderPublicMetadata(public_key_and_metadata.first, + public_key_and_metadata.second)); + EXPECT_EQ( + BN_cmp(RSA_get0_n(modified_rsa_public_key.get()), rsa_modulus.get()), 0); + EXPECT_EQ( + BN_cmp(RSA_get0_e(modified_rsa_public_key.get()), expected_new_e.get()), + 0); +} + } // namespace } // namespace anonymous_tokens } // namespace private_membership
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc index fc0bd4e..e870b4d 100644 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc +++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.cc
@@ -17,6 +17,7 @@ #include <stddef.h> #include <stdint.h> +#include <cstdint> #include <iterator> #include <string> #include <utility> @@ -28,7 +29,9 @@ #include "absl/strings/string_view.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h" +#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" #include "openssl/err.h" +#include "openssl/hkdf.h" #include "openssl/rsa.h" namespace private_membership { @@ -62,6 +65,39 @@ }; const int kBoringSSLRSASqrtTwoLen = 32; +absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataHashWithHKDF( + absl::string_view public_metadata, absl::string_view rsa_modulus_str, + size_t out_len_bytes) { + const EVP_MD* evp_md_sha_384 = EVP_sha384(); + // Append 0x00 to input. + std::vector<uint8_t> input_buffer(public_metadata.begin(), + public_metadata.end()); + input_buffer.push_back(0x00); + std::string out_e; + // We set the out_e size beyond out_len_bytes so that out_e bytes are + // indifferentiable from truly random bytes even after truncations. + // + // Expanding to 16 more bytes is sufficient. + // https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.html#name-hashing-to-a-finite-field + const size_t hkdf_output_size = out_len_bytes + 16; + out_e.resize(hkdf_output_size); + // The modulus is used as salt to ensure different outputs for same metadata + // and different modulus. + if (HKDF(reinterpret_cast<uint8_t*>(out_e.data()), hkdf_output_size, + evp_md_sha_384, input_buffer.data(), input_buffer.size(), + reinterpret_cast<const uint8_t*>(rsa_modulus_str.data()), + rsa_modulus_str.size(), + reinterpret_cast<const uint8_t*>(kHkdfPublicMetadataInfo.data()), + kHkdfPublicMetadataInfoSizeInBytes) != kBsslSuccess) { + return absl::InternalError("HKDF failed in public_metadata_crypto_utils"); + } + // Truncate out_e to out_len_bytes + out_e.resize(out_len_bytes); + ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> out, + StringToBignum(out_e)); + return out; +} + } // namespace internal absl::StatusOr<BnCtxPtr> GetAndStartBigNumCtx() { @@ -268,5 +304,99 @@ return lcm; } +absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataExponent( + const BIGNUM& n, absl::string_view public_metadata) { + // Check modulus length. + if (BN_num_bits(&n) % 2 == 1) { + return absl::InvalidArgumentError( + "Strong RSA modulus should be even length."); + } + int modulus_bytes = BN_num_bytes(&n); + // The integer modulus_bytes is expected to be a power of 2. + int prime_bytes = modulus_bytes / 2; + + ANON_TOKENS_ASSIGN_OR_RETURN(std::string rsa_modulus_str, + BignumToString(n, modulus_bytes)); + + // Get HKDF output of length prime_bytes. + ANON_TOKENS_ASSIGN_OR_RETURN( + bssl::UniquePtr<BIGNUM> exponent, + internal::PublicMetadataHashWithHKDF(public_metadata, rsa_modulus_str, + prime_bytes)); + + // We need to generate random odd exponents < 2^(primes_bits - 2) where + // prime_bits = prime_bytes * 8. This will guarantee that the resulting + // exponent is coprime to phi(N) = 4p'q' as 2^(prime_bits - 2) < p', q' < + // 2^(prime_bits - 1). + // + // To do this, we can truncate the HKDF output (exponent) which is prime_bits + // long, to prime_bits - 2, by clearing its top two bits. We then set the + // least significant bit to 1. This way the final exponent will be less than + // 2^(primes_bits - 2) and will always be odd. + if (BN_clear_bit(exponent.get(), (prime_bytes * 8) - 1) != kBsslSuccess || + BN_clear_bit(exponent.get(), (prime_bytes * 8) - 2) != kBsslSuccess || + BN_set_bit(exponent.get(), 0) != kBsslSuccess) { + return absl::InvalidArgumentError(absl::StrCat( + "Could not clear the two most significant bits and set the least " + "significant bit to zero: ", + GetSslErrors())); + } + // Check that exponent is small enough to ensure it is coprime to phi(n). + if (BN_num_bits(exponent.get()) >= (8 * prime_bytes - 1)) { + return absl::InternalError("Generated exponent is too large."); + } + + return exponent; +} + +absl::StatusOr<bssl::UniquePtr<BIGNUM>> ComputeFinalExponentUnderPublicMetadata( + const BIGNUM& n, const BIGNUM& e, absl::string_view public_metadata) { + ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> md_exp, + PublicMetadataExponent(n, public_metadata)); + ANON_TOKENS_ASSIGN_OR_RETURN(BnCtxPtr bn_ctx, GetAndStartBigNumCtx()); + // new_e=e*md_exp + ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> new_e, NewBigNum()); + if (BN_mul(new_e.get(), md_exp.get(), &e, bn_ctx.get()) != 1) { + return absl::InternalError( + absl::StrCat("Unable to multiply e with md_exp: ", GetSslErrors())); + } + return new_e; +} + +// TODO(b/259581423) Remove RSAPublicKeyToRSAUnderPublicMetadata as we should +// not put public exponent values in borignssl RSA struct other than the +// standard public exponent values. +absl::StatusOr<bssl::UniquePtr<RSA>> RSAPublicKeyToRSAUnderPublicMetadata( + const RSAPublicKey& public_key, absl::string_view public_metadata) { + ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rsa_modulus, + StringToBignum(public_key.n())); + ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> old_e, + StringToBignum(public_key.e())); + bssl::UniquePtr<BIGNUM> new_e; + if (!public_metadata.empty()) { + // Final exponent under Public metadata + ANON_TOKENS_ASSIGN_OR_RETURN( + new_e, ComputeFinalExponentUnderPublicMetadata( + *rsa_modulus.get(), *old_e.get(), public_metadata)); + } else { + new_e = std::move(old_e); + } + // Convert to OpenSSL RSA. + bssl::UniquePtr<RSA> rsa_public_key(RSA_new()); + if (!rsa_public_key.get()) { + return absl::InternalError( + absl::StrCat("RSA_new failed: ", GetSslErrors())); + } else if (RSA_set0_key(rsa_public_key.get(), rsa_modulus.get(), new_e.get(), + nullptr) != kBsslSuccess) { + return absl::InternalError( + absl::StrCat("RSA_set0_key failed: ", GetSslErrors())); + } + // RSA_set0_key takes ownership of the pointers under rsa_modulus, new_e on + // success. + rsa_modulus.release(); + new_e.release(); + return rsa_public_key; +} + } // namespace anonymous_tokens } // namespace private_membership
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h index c0d8625..6d840bc 100644 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h +++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h
@@ -31,6 +31,24 @@ namespace private_membership { namespace anonymous_tokens { +// Internal functions only exposed for testing. +namespace internal { + +// Outputs a public metadata `hash` using HKDF with the public metadata as +// input and the rsa modulus as salt. The expected output hash size is passed as +// out_len_bytes. +// +// This method internally calls HKDF with output size of more than +// out_len_bytes and later truncates the output to out_len_bytes. This is done +// so that the output is indifferentiable from truly random bytes. +// https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.html#name-hashing-to-a-finite-field +absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT +PublicMetadataHashWithHKDF(absl::string_view public_metadata, + absl::string_view rsa_modulus_str, + size_t out_len_bytes); + +} // namespace internal + // Deletes a BN_CTX. class BnCtxDeleter { public: @@ -97,6 +115,30 @@ absl::StatusOr<bssl::UniquePtr<RSA>> QUICHE_EXPORT AnonymousTokensRSAPrivateKeyToRSA(const RSAPrivateKey& private_key); +// Compute exponent based only on the public metadata. Assumes that n is a safe +// modulus i.e. it produces a strong RSA key pair. If not, the exponent may be +// invalid. +absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT +PublicMetadataExponent(const BIGNUM& n, absl::string_view public_metadata); + +// Computes final exponent by multiplying the public exponent e with the +// exponent derived from public metadata. Assumes that n is a safe modulus i.e. +// it produces a strong RSA key pair. If not, the exponent may be invalid. +absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT +ComputeFinalExponentUnderPublicMetadata(const BIGNUM& n, const BIGNUM& e, + absl::string_view public_metadata); + +// Converts AnonymousTokens RSAPublicKey to RSA under a fixed public_metadata. +// +// If the public_metadata is empty, this method doesn't modify the public +// exponent but instead simply outputs the RSA for the unmodified RSAPublicKey. +// +// TODO(b/271441409): Stop using RSA object from boringssl in +// AnonymousTokensService. Replace with a new internal struct. +absl::StatusOr<bssl::UniquePtr<RSA>> QUICHE_EXPORT +RSAPublicKeyToRSAUnderPublicMetadata(const RSAPublicKey& public_key, + absl::string_view public_metadata); + } // namespace anonymous_tokens } // namespace private_membership
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc deleted file mode 100644 index 8a11dbd..0000000 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.cc +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h" - -#include <cstdint> -#include <string> -#include <utility> -#include <vector> - -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" -#include "openssl/hkdf.h" -#include "openssl/rsa.h" - -namespace private_membership { -namespace anonymous_tokens { - -namespace public_metadata_crypto_utils_internal { - -absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataHashWithHKDF( - absl::string_view public_metadata, absl::string_view rsa_modulus_str, - size_t out_len_bytes) { - const EVP_MD* evp_md_sha_384 = EVP_sha384(); - // append 0x00 to input - std::vector<uint8_t> input_buffer(public_metadata.begin(), - public_metadata.end()); - input_buffer.push_back(0x00); - std::string out_e; - // We set the out_e size beyond out_len_bytes so that out_e bytes are - // indifferentiable from truly random bytes even after truncations. - // - // Expanding to 16 more bytes is sufficient. - // https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.html#name-hashing-to-a-finite-field - const size_t hkdf_output_size = out_len_bytes + 16; - out_e.resize(hkdf_output_size); - // The modulus is used as salt to ensure different outputs for same metadata - // and different modulus. - if (HKDF(reinterpret_cast<uint8_t*>(out_e.data()), hkdf_output_size, - evp_md_sha_384, input_buffer.data(), input_buffer.size(), - reinterpret_cast<const uint8_t*>(rsa_modulus_str.data()), - rsa_modulus_str.size(), - reinterpret_cast<const uint8_t*>(kHkdfPublicMetadataInfo.data()), - kHkdfPublicMetadataInfoSizeInBytes) != kBsslSuccess) { - return absl::InternalError("HKDF failed in public_metadata_crypto_utils"); - } - // Truncate out_e to out_len_bytes - out_e.resize(out_len_bytes); - ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> out, - StringToBignum(out_e)); - return std::move(out); -} - -} // namespace public_metadata_crypto_utils_internal - -absl::StatusOr<bssl::UniquePtr<BIGNUM>> PublicMetadataExponent( - const BIGNUM& n, absl::string_view public_metadata) { - // Check modulus length. - if (BN_num_bits(&n) % 2 == 1) { - return absl::InvalidArgumentError( - "Strong RSA modulus should be even length."); - } - int modulus_bytes = BN_num_bytes(&n); - // The integer modulus_bytes is expected to be a power of 2. - int prime_bytes = modulus_bytes / 2; - - ANON_TOKENS_ASSIGN_OR_RETURN(std::string rsa_modulus_str, - BignumToString(n, modulus_bytes)); - - // Get HKDF output of length prime_bytes. - ANON_TOKENS_ASSIGN_OR_RETURN( - bssl::UniquePtr<BIGNUM> exponent, - public_metadata_crypto_utils_internal::PublicMetadataHashWithHKDF( - public_metadata, rsa_modulus_str, prime_bytes)); - - // We need to generate random odd exponents < 2^(primes_bits - 2) where - // prime_bits = prime_bytes * 8. This will guarantee that the resulting - // exponent is coprime to phi(N) = 4p'q' as 2^(prime_bits - 2) < p', q' < - // 2^(prime_bits - 1). - // - // To do this, we can truncate the HKDF output (exponent) which is prime_bits - // long, to prime_bits - 2, by clearing its top two bits. We then set the - // least significant bit to 1. This way the final exponent will be less than - // 2^(primes_bits - 2) and will always be odd. - if (BN_clear_bit(exponent.get(), (prime_bytes * 8) - 1) != kBsslSuccess || - BN_clear_bit(exponent.get(), (prime_bytes * 8) - 2) != kBsslSuccess || - BN_set_bit(exponent.get(), 0) != kBsslSuccess) { - return absl::InvalidArgumentError(absl::StrCat( - "Could not clear the two most significant bits and set the least " - "significant bit to zero: ", - GetSslErrors())); - } - // Check that exponent is small enough to ensure it is coprime to phi(n). - if (BN_num_bits(exponent.get()) >= (8 * prime_bytes - 1)) { - return absl::InternalError("Generated exponent is too large."); - } - - return std::move(exponent); -} - -// TODO(b/259581423) Move ComputeFinalExponentUnderPublicMetadata to anonymous -// namespace once it is only used by RSAPublicKeyToRSAUnderPublicMetadata -absl::StatusOr<bssl::UniquePtr<BIGNUM>> ComputeFinalExponentUnderPublicMetadata( - const BIGNUM& n, const BIGNUM& e, absl::string_view public_metadata) { - ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> md_exp, - PublicMetadataExponent(n, public_metadata)); - ANON_TOKENS_ASSIGN_OR_RETURN(BnCtxPtr bn_ctx, GetAndStartBigNumCtx()); - // new_e=e*md_exp - ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> new_e, NewBigNum()); - if (BN_mul(new_e.get(), md_exp.get(), &e, bn_ctx.get()) != 1) { - return absl::InternalError( - absl::StrCat("Unable to multiply e with md_exp: ", GetSslErrors())); - } - return std::move(new_e); -} - -absl::StatusOr<bssl::UniquePtr<RSA>> RSAPublicKeyToRSAUnderPublicMetadata( - const RSAPublicKey& public_key, absl::string_view public_metadata) { - ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rsa_modulus, - StringToBignum(public_key.n())); - ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> old_e, - StringToBignum(public_key.e())); - bssl::UniquePtr<BIGNUM> new_e; - if (!public_metadata.empty()) { - // Final exponent under Public metadata - ANON_TOKENS_ASSIGN_OR_RETURN( - new_e, ComputeFinalExponentUnderPublicMetadata( - *rsa_modulus.get(), *old_e.get(), public_metadata)); - } else { - new_e = std::move(old_e); - } - // Convert to OpenSSL RSA. - bssl::UniquePtr<RSA> rsa_public_key(RSA_new()); - if (!rsa_public_key.get()) { - return absl::InternalError( - absl::StrCat("RSA_new failed: ", GetSslErrors())); - } else if (RSA_set0_key(rsa_public_key.get(), rsa_modulus.get(), new_e.get(), - nullptr) != kBsslSuccess) { - return absl::InternalError( - absl::StrCat("RSA_set0_key failed: ", GetSslErrors())); - } - rsa_modulus.release(); - new_e.release(); - return std::move(rsa_public_key); -} - -} // namespace anonymous_tokens -} // namespace private_membership
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h deleted file mode 100644 index 0d00646..0000000 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef THIRD_PARTY_ANONYMOUS_TOKENS_CPP_CRYPTO_PUBLIC_METADATA_CRYPTO_UTILS_H_ -#define THIRD_PARTY_ANONYMOUS_TOKENS_CPP_CRYPTO_PUBLIC_METADATA_CRYPTO_UTILS_H_ - -#include <stddef.h> - -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" -#include "openssl/base.h" -// #include "quiche/common/platform/api/quiche_export.h" - -namespace private_membership { -namespace anonymous_tokens { - -// Internal functions only exposed for testing. -namespace public_metadata_crypto_utils_internal { - -// Outputs a public metadata `hash` using HKDF with the public metadata as -// input and the rsa modulus as salt. The expected output hash size is passed as -// out_len_bytes. -// -// This method internally calls HKDF with output size of more than -// out_len_bytes and later truncates the output to out_len_bytes. This is done -// so that the output is indifferentiable from truly random bytes. -// https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.html#name-hashing-to-a-finite-field -absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT -PublicMetadataHashWithHKDF(absl::string_view public_metadata, - absl::string_view rsa_modulus_str, - size_t out_len_bytes); - -} // namespace public_metadata_crypto_utils_internal - -// Compute exponent based only on the public metadata. Assumes that n is a safe -// modulus i.e. it produces a strong RSA key pair. If not, the exponent may be -// invalid. -absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT -PublicMetadataExponent(const BIGNUM& n, absl::string_view public_metadata); - -// Computes final exponent by multiplying the public exponent e with the -// exponent derived from public metadata. Assumes that n is a safe modulus i.e. -// it produces a strong RSA key pair. If not, the exponent may be invalid. -absl::StatusOr<bssl::UniquePtr<BIGNUM>> QUICHE_EXPORT -ComputeFinalExponentUnderPublicMetadata(const BIGNUM& n, const BIGNUM& e, - absl::string_view public_metadata); - -// Converts AnonymousTokens RSAPublicKey to RSA under a fixed public_metadata. -// -// If the public_metadata is empty, this method doesn't modify the public -// exponent but instead simply outputs the RSA for the unmodified RSAPublicKey. -// -// TODO(b/271441409): Stop using RSA object from boringssl in -// AnonymousTokensService. Replace with a new internal struct. -absl::StatusOr<bssl::UniquePtr<RSA>> QUICHE_EXPORT -RSAPublicKeyToRSAUnderPublicMetadata(const RSAPublicKey& public_key, - absl::string_view public_metadata); - -} // namespace anonymous_tokens -} // namespace private_membership - -#endif // THIRD_PARTY_ANONYMOUS_TOKENS_CPP_CRYPTO_PUBLIC_METADATA_CRYPTO_UTILS_H_
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc deleted file mode 100644 index 50ea2ab..0000000 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils_test.cc +++ /dev/null
@@ -1,266 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h" - -#include <memory> -#include <string> -#include <utility> - -#include "quiche/common/platform/api/quiche_test.h" -#include "quiche/common/test_tools/quiche_test_utils.h" -#include "absl/strings/escaping.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" -#include "openssl/base.h" -#include "openssl/rsa.h" - -namespace private_membership { -namespace anonymous_tokens { -namespace { - -std::pair<RSAPublicKey, std::string> GetFixedTestPublicKeyAndPublicMetadata() { - RSAPublicKey public_key; - public_key.set_n(absl::HexStringToBytes( - "b2ae391467872a7506468a9ac4e980fa76164666955ef8999917295dbbd89dd7aa9c0e41" - "2dcda3dd1aa867e0c414d80afb9544a7c71c32d83e1b8417f293f325d2ffe2f9e296d28f" - "b89a443de5cc06ab3c516913fc18694539c370315d3e7f4ac5f87faaf3fee751c9f439ae" - "8d53eee249d8c49b33bd3bb7aa060eb462522da98a02f92eff110cc9408ca0ccc54abf2c" - "fcb68b77fb0ec7048d8b76416f61f2b182ea73169ed18f0d1d238dcaf6fc9de067d4831f" - "68f485483dd5c9ec17d9384825ba7284bc38bb1ea5e40d9207d9007e609a19e3fab695a1" - "8c30f1a7c4b03c77ef72211415a0bfeacd3298dccafa7e06e41dc2131f9076b92bb352c8" - "f7bccfe9")); - public_key.set_e(absl::HexStringToBytes("03")); - std::string public_metadata = absl::HexStringToBytes("6d65746164617461"); - return std::make_pair(std::move(public_key), std::move(public_metadata)); -} - -std::string GetFixedTestNewPublicKeyExponentUnderPublicMetadata() { - std::string new_e = absl::HexStringToBytes( - "0b2d80537b4c899c7107eef3b74ddc0dcd931aff9c583ce3cf3527d42483052b27d55dd4" - "d2f831a38430f13d81574c51aa97af6f5c3a6c03b269bc156d029273bd60e7af578fff15" - "c52cbb5c19288fd1ce59f6f756b2d93b6f2586210fb969efb5065700da5598bb8914d395" - "4d97a49c5ca05b2386bc3cf098281958cf372481"); - return new_e; -} - -using CreateTestKeyPairFunction = - absl::StatusOr<std::pair<RSAPublicKey, RSAPrivateKey>>(); - -class PublicMetadataCryptoUtilsTest - : public testing::TestWithParam<CreateTestKeyPairFunction*> { - protected: - void SetUp() override { - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto keys_pair, (*GetParam())()); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - private_key_, AnonymousTokensRSAPrivateKeyToRSA(keys_pair.second)); - public_key_ = std::move(keys_pair.first); - } - - bssl::UniquePtr<RSA> private_key_; - RSAPublicKey public_key_; -}; - -TEST_P(PublicMetadataCryptoUtilsTest, PublicExponentCoprime) { - std::string metadata = "md"; - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> exp, - PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata)); - int rsa_mod_size_bits = BN_num_bits(RSA_get0_n(private_key_.get())); - // Check that exponent is odd. - EXPECT_EQ(BN_is_odd(exp.get()), 1); - // Check that exponent is small enough. - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> sqrt2, - GetRsaSqrtTwo(rsa_mod_size_bits / 2)); - EXPECT_LT(BN_cmp(exp.get(), sqrt2.get()), 0); - EXPECT_LT(BN_cmp(exp.get(), RSA_get0_p(private_key_.get())), 0); - EXPECT_LT(BN_cmp(exp.get(), RSA_get0_q(private_key_.get())), 0); -} - -TEST_P(PublicMetadataCryptoUtilsTest, PublicExponentHash) { - std::string metadata1 = "md1"; - std::string metadata2 = "md2"; - // Check that hash is deterministic. - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> exp1, - PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata1)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> another_exp1, - PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata1)); - EXPECT_EQ(BN_cmp(exp1.get(), another_exp1.get()), 0); - // Check that hashes are distinct for different metadata. - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> exp2, - PublicMetadataExponent(*RSA_get0_n(private_key_.get()), metadata2)); - EXPECT_NE(BN_cmp(exp1.get(), exp2.get()), 0); -} - -TEST_P(PublicMetadataCryptoUtilsTest, FinalExponentCoprime) { - std::string metadata = "md"; - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> final_exponent, - ComputeFinalExponentUnderPublicMetadata(*RSA_get0_n(private_key_.get()), - *RSA_get0_e(private_key_.get()), - metadata)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(BnCtxPtr ctx, GetAndStartBigNumCtx()); - - // Check that exponent is odd. - EXPECT_EQ(BN_is_odd(final_exponent.get()), 1); - // Check that exponent is co-prime to factors of the rsa modulus. - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> gcd_p_fe, - NewBigNum()); - ASSERT_EQ(BN_gcd(gcd_p_fe.get(), RSA_get0_p(private_key_.get()), - final_exponent.get(), ctx.get()), - 1); - EXPECT_EQ(BN_cmp(gcd_p_fe.get(), BN_value_one()), 0); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> gcd_q_fe, - NewBigNum()); - ASSERT_EQ(BN_gcd(gcd_q_fe.get(), RSA_get0_q(private_key_.get()), - final_exponent.get(), ctx.get()), - 1); - EXPECT_EQ(BN_cmp(gcd_q_fe.get(), BN_value_one()), 0); -} - -TEST_P(PublicMetadataCryptoUtilsTest, - DeterministicRSAPublicKeyToRSAUnderPublicMetadata) { - std::string metadata = "md"; - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> rsa_public_key_1, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> rsa_public_key_2, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata)); - EXPECT_EQ(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), - RSA_get0_e(rsa_public_key_2.get())), - 0); -} - -TEST_P(PublicMetadataCryptoUtilsTest, - DifferentPublicMetadataRSAPublicKeyToRSAUnderPublicMetadata) { - std::string metadata_1 = "md1"; - std::string metadata_2 = "md2"; - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> rsa_public_key_1, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata_1)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> rsa_public_key_2, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_, metadata_2)); - // Check that exponent is different in all keys - EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), - RSA_get0_e(rsa_public_key_2.get())), - 0); - EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), - RSA_get0_e(private_key_.get())), - 0); - EXPECT_NE(BN_cmp(RSA_get0_e(rsa_public_key_1.get()), - RSA_get0_e(private_key_.get())), - 0); -} - -TEST_P(PublicMetadataCryptoUtilsTest, - NoPublicMetadataRSAPublicKeyToRSAUnderPublicMetadata) { - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> rsa_public_key, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_, "")); - - // Check that exponent is same in output and input. - EXPECT_EQ( - BN_cmp(RSA_get0_e(rsa_public_key.get()), RSA_get0_e(private_key_.get())), - 0); - // Check that rsa_modulus is correct - EXPECT_EQ( - BN_cmp(RSA_get0_n(rsa_public_key.get()), RSA_get0_n(private_key_.get())), - 0); -} - -INSTANTIATE_TEST_SUITE_P( - PublicMetadataCryptoUtilsTest, PublicMetadataCryptoUtilsTest, - testing::Values(&GetStrongRsaKeys2048, &GetAnotherStrongRsaKeys2048, - &GetStrongRsaKeys3072, &GetStrongRsaKeys4096)); - -TEST(PublicMetadataCryptoUtilsInternalTest, PublicMetadataHashWithHKDF) { - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(BnCtxPtr ctx, GetAndStartBigNumCtx()); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> max_value, - NewBigNum()); - ASSERT_TRUE(BN_set_word(max_value.get(), 4294967296)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair, GetStrongRsaKeys2048()); - std::string input1 = "ro1"; - std::string input2 = "ro2"; - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> output1, - public_metadata_crypto_utils_internal::PublicMetadataHashWithHKDF( - input1, key_pair.first.n(), 1 + input1.size())); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> another_output1, - public_metadata_crypto_utils_internal::PublicMetadataHashWithHKDF( - input1, key_pair.first.n(), 1 + input1.size())); - EXPECT_EQ(BN_cmp(output1.get(), another_output1.get()), 0); - - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> output2, - public_metadata_crypto_utils_internal::PublicMetadataHashWithHKDF( - input2, key_pair.first.n(), 1 + input2.size())); - EXPECT_NE(BN_cmp(output1.get(), output2.get()), 0); - - EXPECT_LT(BN_cmp(output1.get(), max_value.get()), 0); - EXPECT_LT(BN_cmp(output2.get(), max_value.get()), 0); -} - -TEST(PublicMetadataCryptoUtilsTest, PublicExponentHashDifferentModulus) { - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair_1, GetStrongRsaKeys2048()); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(auto key_pair_2, - GetAnotherStrongRsaKeys2048()); - std::string metadata = "md"; - // Check that same metadata and different modulus result in different - // hashes. - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - auto rsa_private_key_1, - AnonymousTokensRSAPrivateKeyToRSA(key_pair_1.second)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> exp1, - PublicMetadataExponent(*RSA_get0_n(rsa_private_key_1.get()), metadata)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - auto rsa_private_key_2, - AnonymousTokensRSAPrivateKeyToRSA(key_pair_2.second)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> exp2, - PublicMetadataExponent(*RSA_get0_n(rsa_private_key_2.get()), metadata)); - EXPECT_NE(BN_cmp(exp1.get(), exp2.get()), 0); -} - -TEST(PublicMetadataCryptoUtilsTest, - FixedTestRSAPublicKeyToRSAUnderPublicMetadata) { - const auto public_key_and_metadata = GetFixedTestPublicKeyAndPublicMetadata(); - const std::string expected_new_e_str = - GetFixedTestNewPublicKeyExponentUnderPublicMetadata(); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<BIGNUM> rsa_modulus, - StringToBignum(public_key_and_metadata.first.n())); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN(bssl::UniquePtr<BIGNUM> expected_new_e, - StringToBignum(expected_new_e_str)); - ANON_TOKENS_QUICHE_EXPECT_OK_AND_ASSIGN( - bssl::UniquePtr<RSA> modified_rsa_public_key, - RSAPublicKeyToRSAUnderPublicMetadata(public_key_and_metadata.first, - public_key_and_metadata.second)); - EXPECT_EQ( - BN_cmp(RSA_get0_n(modified_rsa_public_key.get()), rsa_modulus.get()), 0); - EXPECT_EQ( - BN_cmp(RSA_get0_e(modified_rsa_public_key.get()), expected_new_e.get()), - 0); -} - -} // namespace -} // namespace anonymous_tokens -} // namespace private_membership
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc index abfc34f..a630051 100644 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc +++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blinder.cc
@@ -22,7 +22,6 @@ #include "absl/status/status.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h" #include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h" #include "openssl/digest.h"
diff --git a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc index 29212c5..323a714 100644 --- a/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc +++ b/quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/testing_utils.cc
@@ -29,7 +29,6 @@ #include "absl/strings/string_view.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h" -#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/public_metadata_crypto_utils.h" #include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/status_utils.h" #include "openssl/rsa.h"