diff options
author | felobato <felobato@google.com> | 2023-05-11 07:30:27 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-05-11 07:31:47 -0700 |
commit | 18f2959fbef5ffffb5fe16947088c231ee4bf64c (patch) | |
tree | 5bbb30c2f425845e1510242df8c0260422a885bb /cc/aead | |
parent | ce73a91a7bf6f420453089403c5d5e0059a9e10b (diff) | |
download | tink-18f2959fbef5ffffb5fe16947088c231ee4bf64c.tar.gz |
Add Key Derivation for AesCtrHmac KeyManager
#tinkApiChange
PiperOrigin-RevId: 531196327
Diffstat (limited to 'cc/aead')
-rw-r--r-- | cc/aead/BUILD.bazel | 3 | ||||
-rw-r--r-- | cc/aead/CMakeLists.txt | 3 | ||||
-rw-r--r-- | cc/aead/aes_ctr_hmac_aead_key_manager.cc | 63 | ||||
-rw-r--r-- | cc/aead/aes_ctr_hmac_aead_key_manager.h | 4 | ||||
-rw-r--r-- | cc/aead/aes_ctr_hmac_aead_key_manager_test.cc | 110 |
5 files changed, 174 insertions, 9 deletions
diff --git a/cc/aead/BUILD.bazel b/cc/aead/BUILD.bazel index ac1ba24c2..db654c4e3 100644 --- a/cc/aead/BUILD.bazel +++ b/cc/aead/BUILD.bazel @@ -214,6 +214,7 @@ cc_library( "//subtle:random", "//util:constants", "//util:enums", + "//util:input_stream_util", "//util:secret_data", "//util:status", "//util:statusor", @@ -516,7 +517,6 @@ cc_test( deps = [ ":aes_ctr_hmac_aead_key_manager", "//:aead", - "//:mac", "//proto:aes_ctr_cc_proto", "//proto:aes_ctr_hmac_aead_cc_proto", "//proto:common_cc_proto", @@ -526,6 +526,7 @@ cc_test( "//subtle:aead_test_util", "//subtle:aes_ctr_boringssl", "//util:enums", + "//util:istream_input_stream", "//util:secret_data", "//util:status", "//util:statusor", diff --git a/cc/aead/CMakeLists.txt b/cc/aead/CMakeLists.txt index 6ca31e861..485cd557f 100644 --- a/cc/aead/CMakeLists.txt +++ b/cc/aead/CMakeLists.txt @@ -199,6 +199,7 @@ tink_cc_library( tink::subtle::random tink::util::constants tink::util::enums + tink::util::input_stream_util tink::util::secret_data tink::util::status tink::util::statusor @@ -488,11 +489,11 @@ tink_cc_test( gmock absl::status tink::core::aead - tink::core::mac tink::subtle::subtle tink::subtle::aead_test_util tink::subtle::aes_ctr_boringssl tink::util::enums + tink::util::istream_input_stream tink::util::secret_data tink::util::status tink::util::statusor diff --git a/cc/aead/aes_ctr_hmac_aead_key_manager.cc b/cc/aead/aes_ctr_hmac_aead_key_manager.cc index ffe78672b..10a06343e 100644 --- a/cc/aead/aes_ctr_hmac_aead_key_manager.cc +++ b/cc/aead/aes_ctr_hmac_aead_key_manager.cc @@ -34,6 +34,7 @@ #include "tink/subtle/ind_cpa_cipher.h" #include "tink/subtle/random.h" #include "tink/util/enums.h" +#include "tink/util/input_stream_util.h" #include "tink/util/secret_data.h" #include "tink/util/status.h" #include "tink/util/statusor.h" @@ -52,12 +53,14 @@ constexpr int kMinIvSizeInBytes = 12; constexpr int kMinTagSizeInBytes = 10; } -using crypto::tink::util::Enums; -using crypto::tink::util::Status; -using crypto::tink::util::StatusOr; -using google::crypto::tink::AesCtrHmacAeadKey; -using google::crypto::tink::AesCtrHmacAeadKeyFormat; -using google::crypto::tink::HashType; +using ::crypto::tink::util::Enums; +using ::crypto::tink::util::Status; +using ::crypto::tink::util::StatusOr; +using ::google::crypto::tink::AesCtrHmacAeadKey; +using ::google::crypto::tink::AesCtrHmacAeadKeyFormat; +using ::google::crypto::tink::AesCtrKey; +using ::google::crypto::tink::HashType; +using ::google::crypto::tink::HmacKey; StatusOr<AesCtrHmacAeadKey> AesCtrHmacAeadKeyManager::CreateKey( const AesCtrHmacAeadKeyFormat& aes_ctr_hmac_aead_key_format) const { @@ -176,5 +179,53 @@ Status AesCtrHmacAeadKeyManager::ValidateKeyFormat( return HmacKeyManager().ValidateKeyFormat(key_format.hmac_key_format()); } +// To ensure the resulting key can provide key commitment, the AES-CTR key must +// be derived first, then the HMAC key. This avoids situation where it's +// possible to brute force raw key material so that the 32th byte of the +// keystream is a 0 Give party A a key with this raw key material, saying that +// the size of the HMAC key is 32 bytes and the size of the AES key is 16 bytes. +// Give party B a key with this raw key material, saying that the size of the +// HMAC key is 31 bytes and the size of the AES key is 16 bytes. Since HMAC will +// pad the key with zeroes, this leads to both parties using the same HMAC key, +// but a different AES key (offset by 1 byte) +StatusOr<AesCtrHmacAeadKey> AesCtrHmacAeadKeyManager::DeriveKey( + const AesCtrHmacAeadKeyFormat& key_format, + InputStream* input_stream) const { + Status status = ValidateKeyFormat(key_format); + if (!status.ok()) { + return status; + } + StatusOr<std::string> aes_ctr_randomness = ReadBytesFromStream( + key_format.aes_ctr_key_format().key_size(), input_stream); + if (!aes_ctr_randomness.ok()) { + if (absl::IsOutOfRange(aes_ctr_randomness.status())) { + return crypto::tink::util::Status( + absl::StatusCode::kInvalidArgument, + "Could not get enough pseudorandomness from input stream"); + } + return aes_ctr_randomness.status(); + } + StatusOr<HmacKey> hmac_key = + HmacKeyManager().DeriveKey(key_format.hmac_key_format(), input_stream); + if (!hmac_key.ok()) { + return hmac_key.status(); + } + + google::crypto::tink::AesCtrHmacAeadKey key; + key.set_version(get_version()); + *key.mutable_hmac_key() = hmac_key.value(); + + AesCtrKey* aes_ctr_key = key.mutable_aes_ctr_key(); + aes_ctr_key->set_version(get_version()); + aes_ctr_key->set_key_value(aes_ctr_randomness.value()); + *aes_ctr_key->mutable_params() = key_format.aes_ctr_key_format().params(); + + status = ValidateKey(key); + if (!status.ok()) { + return status; + } + return key; +} + } // namespace tink } // namespace crypto diff --git a/cc/aead/aes_ctr_hmac_aead_key_manager.h b/cc/aead/aes_ctr_hmac_aead_key_manager.h index a241a9cf0..e3b2f424a 100644 --- a/cc/aead/aes_ctr_hmac_aead_key_manager.h +++ b/cc/aead/aes_ctr_hmac_aead_key_manager.h @@ -67,6 +67,10 @@ class AesCtrHmacAeadKeyManager CreateKey(const google::crypto::tink::AesCtrHmacAeadKeyFormat& key_format) const override; + crypto::tink::util::StatusOr<google::crypto::tink::AesCtrHmacAeadKey> + DeriveKey(const google::crypto::tink::AesCtrHmacAeadKeyFormat& key_format, + InputStream* input_stream) const override; + internal::FipsCompatibility FipsStatus() const override { return internal::FipsCompatibility::kRequiresBoringCrypto; } diff --git a/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc b/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc index 493055953..b84711a79 100644 --- a/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc +++ b/cc/aead/aes_ctr_hmac_aead_key_manager_test.cc @@ -19,6 +19,7 @@ #include <stdint.h> #include <memory> +#include <sstream> #include <string> #include <utility> @@ -26,13 +27,13 @@ #include "gtest/gtest.h" #include "absl/status/status.h" #include "tink/aead.h" -#include "tink/mac.h" #include "tink/subtle/aead_test_util.h" #include "tink/subtle/aes_ctr_boringssl.h" #include "tink/subtle/encrypt_then_authenticate.h" #include "tink/subtle/hmac_boringssl.h" #include "tink/subtle/ind_cpa_cipher.h" #include "tink/util/enums.h" +#include "tink/util/istream_input_stream.h" #include "tink/util/secret_data.h" #include "tink/util/status.h" #include "tink/util/statusor.h" @@ -48,6 +49,7 @@ namespace tink { using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; +using ::crypto::tink::util::IstreamInputStream; using ::crypto::tink::util::StatusOr; using ::google::crypto::tink::AesCtrHmacAeadKey; using ::google::crypto::tink::AesCtrHmacAeadKeyFormat; @@ -145,14 +147,24 @@ TEST(AesCtrHmacAeadKeyManagerTest, ValidateKeyFormatKeySizes) { AesCtrHmacAeadKeyFormat key_format = CreateValidKeyFormat(); for (int len = 0; len < 42; ++len) { key_format.mutable_aes_ctr_key_format()->set_key_size(len); + IstreamInputStream input_stream{absl::make_unique<std::stringstream>( + "0123456789abcde0123456789abcdefghijklmnopqrztuvwxyz0123456789abcde01" + "23456789abcdefghijklmnopqrztuvwxyz0123456789abcde0123456789abcdefghi" + "jklmnopqrztuvwxyz")}; if (len == 16 || len == 32) { EXPECT_THAT(AesCtrHmacAeadKeyManager().ValidateKeyFormat(key_format), IsOk()) << "for length " << len; + EXPECT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(key_format, &input_stream), + IsOk()); } else { EXPECT_THAT(AesCtrHmacAeadKeyManager().ValidateKeyFormat(key_format), Not(IsOk())) << "for length " << len; + EXPECT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(key_format, &input_stream), + Not(IsOk())); } } } @@ -161,14 +173,24 @@ TEST(AesCtrHmacAeadKeyManagerTest, ValidateKeyFormatHmacKeySizes) { AesCtrHmacAeadKeyFormat key_format = CreateValidKeyFormat(); for (int len = 0; len < 42; ++len) { key_format.mutable_hmac_key_format()->set_key_size(len); + IstreamInputStream input_stream{absl::make_unique<std::stringstream>( + "0123456789abcde0123456789abcdefghijklmnopqrztuvwxyz0123456789abcde01" + "23456789abcdefghijklmnopqrztuvwxyz0123456789abcde0123456789abcdefghi" + "jklmnopqrztuvwxyz")}; if (len >= 16) { EXPECT_THAT(AesCtrHmacAeadKeyManager().ValidateKeyFormat(key_format), IsOk()) << "for length " << len; + EXPECT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(key_format, &input_stream), + IsOk()); } else { EXPECT_THAT(AesCtrHmacAeadKeyManager().ValidateKeyFormat(key_format), Not(IsOk())) << "for length " << len; + EXPECT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(key_format, &input_stream), + Not(IsOk())); } } } @@ -221,6 +243,92 @@ TEST(AesCtrHmacAeadKeyManagerTest, CreateAead) { IsOk()); } +TEST(AesCtrHmacAeadKeyManagerTest, Derive16ByteKey) { + AesCtrHmacAeadKeyFormat key_format; + key_format.mutable_aes_ctr_key_format()->set_key_size(16); + key_format.mutable_aes_ctr_key_format()->mutable_params()->set_iv_size(16); + key_format.mutable_hmac_key_format()->set_key_size(16); + key_format.mutable_hmac_key_format()->mutable_params()->set_tag_size(16); + key_format.mutable_hmac_key_format()->mutable_params()->set_hash( + google::crypto::tink::SHA256); + key_format.mutable_hmac_key_format()->set_version(0); + + IstreamInputStream input_stream{absl::make_unique<std::stringstream>( + "0123456789abcde_YELLOW_SUBMARINE_EXTRA")}; + + StatusOr<AesCtrHmacAeadKey> derived_key = + AesCtrHmacAeadKeyManager().DeriveKey(key_format, &input_stream); + ASSERT_THAT(derived_key, IsOk()); + EXPECT_THAT(derived_key.value().aes_ctr_key().key_value(), + Eq("0123456789abcde_")); + EXPECT_THAT(derived_key.value().hmac_key().key_value(), + Eq("YELLOW_SUBMARINE")); + EXPECT_THAT(derived_key.value().hmac_key().params().hash(), + key_format.hmac_key_format().params().hash()); + EXPECT_THAT(derived_key.value().hmac_key().params().tag_size(), + key_format.hmac_key_format().params().tag_size()); + EXPECT_THAT(derived_key.value().aes_ctr_key().params().iv_size(), + Eq(key_format.aes_ctr_key_format().params().iv_size())); +} + +TEST(AesCtrHmacAeadKeyManagerTest, Derive32ByteKey) { + AesCtrHmacAeadKeyFormat format; + format.mutable_aes_ctr_key_format()->set_key_size(32); + format.mutable_aes_ctr_key_format()->mutable_params()->set_iv_size(16); + format.mutable_hmac_key_format()->set_key_size(32); + format.mutable_hmac_key_format()->mutable_params()->set_tag_size(16); + format.mutable_hmac_key_format()->mutable_params()->set_hash( + google::crypto::tink::SHA256); + format.mutable_hmac_key_format()->set_version(0); + + IstreamInputStream input_stream{absl::make_unique<std::stringstream>( + "0123456789abcde0123456789abcdef_YELLOW_SUBMARINE_YELLOW_SUBMARIN")}; + + StatusOr<AesCtrHmacAeadKey> derived_key = + AesCtrHmacAeadKeyManager().DeriveKey(format, &input_stream); + ASSERT_THAT(derived_key, IsOk()); + EXPECT_THAT(derived_key.value().aes_ctr_key().key_value(), + Eq("0123456789abcde0123456789abcdef_")); + EXPECT_THAT(derived_key.value().hmac_key().key_value(), + Eq("YELLOW_SUBMARINE_YELLOW_SUBMARIN")); +} + +TEST(AesCtrHmacAeadKeyManagerTest, DeriveKeyNotEnoughRandomnessForAesCtrKey) { + AesCtrHmacAeadKeyFormat format; + format.mutable_aes_ctr_key_format()->set_key_size(32); + format.mutable_aes_ctr_key_format()->mutable_params()->set_iv_size(16); + format.mutable_hmac_key_format()->set_key_size(32); + format.mutable_hmac_key_format()->mutable_params()->set_tag_size(16); + format.mutable_hmac_key_format()->mutable_params()->set_hash( + google::crypto::tink::SHA256); + format.mutable_hmac_key_format()->set_version(0); + + IstreamInputStream input_stream{ + absl::make_unique<std::stringstream>("0123456789")}; + + ASSERT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(format, &input_stream).status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST(AesCtrHmacAeadKeyManagerTest, DeriveKeyNotEnoughRandomnessForHmacKey) { + AesCtrHmacAeadKeyFormat format; + format.mutable_aes_ctr_key_format()->set_key_size(16); + format.mutable_aes_ctr_key_format()->mutable_params()->set_iv_size(16); + format.mutable_hmac_key_format()->set_key_size(32); + format.mutable_hmac_key_format()->mutable_params()->set_tag_size(16); + format.mutable_hmac_key_format()->mutable_params()->set_hash( + google::crypto::tink::SHA256); + format.mutable_hmac_key_format()->set_version(0); + + IstreamInputStream input_stream{ + absl::make_unique<std::stringstream>("YELLOW_SUBMARINE")}; + + ASSERT_THAT( + AesCtrHmacAeadKeyManager().DeriveKey(format, &input_stream).status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + } // namespace } // namespace tink } // namespace crypto |