blob: 3911b3bdf95835842739ff6c7242b651924bf6b4 [file] [log] [blame]
// 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
//
// http://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 "tink/aead/kms_envelope_aead.h"
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/internal/endian.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "tink/aead/aead_config.h"
#include "tink/aead/aead_key_templates.h"
#include "tink/mac/mac_key_templates.h"
#include "tink/registry.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
#include "proto/aes_gcm.pb.h"
namespace crypto {
namespace tink {
namespace {
using crypto::tink::test::DummyAead;
using crypto::tink::test::IsOk;
using crypto::tink::test::StatusIs;
using testing::HasSubstr;
TEST(KmsEnvelopeAeadTest, BasicEncryptDecrypt) {
EXPECT_THAT(AeadConfig::Register(), IsOk());
auto dek_template = AeadKeyTemplates::Aes128Eax();
std::string remote_aead_name = "kms-backed-aead";
auto remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
auto aead_result = KmsEnvelopeAead::New(dek_template, std::move(remote_aead));
EXPECT_THAT(aead_result.status(), IsOk());
auto aead = std::move(aead_result.ValueOrDie());
std::string message = "Some data to encrypt.";
std::string aad = "Some data to authenticate.";
auto encrypt_result = aead->Encrypt(message, aad);
EXPECT_THAT(encrypt_result.status(), IsOk());
auto decrypt_result = aead->Decrypt(encrypt_result.ValueOrDie(), aad);
EXPECT_THAT(decrypt_result.status(), IsOk());
EXPECT_EQ(decrypt_result.ValueOrDie(), message);
}
TEST(KmsEnvelopeAeadTest, NullAead) {
auto dek_template = AeadKeyTemplates::Aes128Eax();
auto aead_result = KmsEnvelopeAead::New(dek_template, nullptr);
EXPECT_THAT(aead_result.status(),
StatusIs(util::error::INVALID_ARGUMENT, HasSubstr("non-null")));
}
TEST(KmsEnvelopeAeadTest, MissingDekKeyManager) {
Registry::Reset();
auto dek_template = AeadKeyTemplates::Aes128Eax();
std::string remote_aead_name = "kms-backed-aead";
auto remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
auto aead_result = KmsEnvelopeAead::New(dek_template, std::move(remote_aead));
EXPECT_THAT(aead_result.status(),
StatusIs(util::error::NOT_FOUND, HasSubstr("AesEaxKey")));
}
TEST(KmsEnvelopeAeadTest, WrongDekPrimitive) {
EXPECT_THAT(AeadConfig::Register(), IsOk());
auto dek_template = MacKeyTemplates::HmacSha256();
std::string remote_aead_name = "kms-backed-aead";
auto remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
auto aead_result = KmsEnvelopeAead::New(dek_template, std::move(remote_aead));
EXPECT_THAT(aead_result.status(),
StatusIs(util::error::INVALID_ARGUMENT,
HasSubstr("not among supported primitives")));
}
TEST(KmsEnvelopeAeadTest, DecryptionErrors) {
EXPECT_THAT(AeadConfig::Register(), IsOk());
auto dek_template = AeadKeyTemplates::Aes128Gcm();
std::string remote_aead_name = "kms-backed-aead";
auto remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
auto aead_result = KmsEnvelopeAead::New(dek_template, std::move(remote_aead));
EXPECT_THAT(aead_result.status(), IsOk());
auto aead = std::move(aead_result.ValueOrDie());
std::string message = "Some data to encrypt.";
std::string aad = "Some data to authenticate.";
auto encrypt_result = aead->Encrypt(message, aad);
EXPECT_THAT(encrypt_result.status(), IsOk());
auto ct = encrypt_result.ValueOrDie();
// Empty ciphertext.
auto decrypt_result = aead->Decrypt("", aad);
EXPECT_THAT(decrypt_result.status(),
StatusIs(util::error::INVALID_ARGUMENT, HasSubstr("too short")));
// Short ciphertext.
decrypt_result = aead->Decrypt("sh", aad);
EXPECT_THAT(decrypt_result.status(),
StatusIs(util::error::INVALID_ARGUMENT, HasSubstr("too short")));
// Truncated ciphertext.
decrypt_result = aead->Decrypt(ct.substr(2), aad);
EXPECT_THAT(decrypt_result.status(),
StatusIs(util::error::INVALID_ARGUMENT, HasSubstr("invalid")));
// Corrupted ciphertext.
auto ct_copy = ct;
ct_copy[4] = 'a'; // corrupt serialized DEK.
decrypt_result = aead->Decrypt(ct_copy, aad);
EXPECT_THAT(decrypt_result.status(),
StatusIs(util::error::INVALID_ARGUMENT, HasSubstr("invalid")));
// Wrong associated data.
decrypt_result = aead->Decrypt(ct, "wrong aad");
EXPECT_THAT(
decrypt_result.status(),
StatusIs(util::error::INTERNAL, HasSubstr("Authentication failed")));
}
TEST(KmsEnvelopeAeadTest, KeyFormat) {
EXPECT_THAT(AeadConfig::Register(), IsOk());
auto dek_template = AeadKeyTemplates::Aes128Gcm();
// Construct a remote AEAD which uses same key template for this test.
std::string remote_aead_name = "kms-backed-aead";
auto remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
// Create envelope AEAD and encrypt some data.
auto aead_result = KmsEnvelopeAead::New(dek_template, std::move(remote_aead));
EXPECT_THAT(aead_result.status(), IsOk());
auto aead = std::move(aead_result.ValueOrDie());
std::string message = "Some data to encrypt.";
std::string aad = "Some data to authenticate.";
auto encrypt_result = aead->Encrypt(message, aad);
EXPECT_THAT(encrypt_result.status(), IsOk());
auto ct = encrypt_result.ValueOrDie();
// Recover DEK from ciphertext
auto enc_dek_size =
absl::big_endian::Load32(reinterpret_cast<const uint8_t*>(ct.data()));
remote_aead = absl::make_unique<DummyAead>(remote_aead_name);
auto dek_decrypt_result =
remote_aead->Decrypt(ct.substr(4, enc_dek_size), "");
// Check if we can deserialize a GCM key proto from the decrypted DEK.
google::crypto::tink::AesGcmKey key;
EXPECT_THAT(key.ParseFromString(dek_decrypt_result.ValueOrDie()), true);
EXPECT_THAT(key.key_value().size(), testing::Eq(16));
}
} // namespace
} // namespace tink
} // namespace crypto