aboutsummaryrefslogtreecommitdiff
path: root/cc/aead
diff options
context:
space:
mode:
authorfelobato <felobato@google.com>2023-05-11 07:30:27 -0700
committerCopybara-Service <copybara-worker@google.com>2023-05-11 07:31:47 -0700
commit18f2959fbef5ffffb5fe16947088c231ee4bf64c (patch)
tree5bbb30c2f425845e1510242df8c0260422a885bb /cc/aead
parentce73a91a7bf6f420453089403c5d5e0059a9e10b (diff)
downloadtink-18f2959fbef5ffffb5fe16947088c231ee4bf64c.tar.gz
Add Key Derivation for AesCtrHmac KeyManager
#tinkApiChange PiperOrigin-RevId: 531196327
Diffstat (limited to 'cc/aead')
-rw-r--r--cc/aead/BUILD.bazel3
-rw-r--r--cc/aead/CMakeLists.txt3
-rw-r--r--cc/aead/aes_ctr_hmac_aead_key_manager.cc63
-rw-r--r--cc/aead/aes_ctr_hmac_aead_key_manager.h4
-rw-r--r--cc/aead/aes_ctr_hmac_aead_key_manager_test.cc110
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