/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include "nss.h" #include "pk11pub.h" #include "secerr.h" #include "sechash.h" #include "scoped_ptrs.h" #include "gcm-vectors.h" #include "gtest/gtest.h" #include "util.h" namespace nss_test { class Pkcs11AesGcmTest : public ::testing::TestWithParam { protected: void RunTest(const gcm_kat_value val) { std::vector key = hex_string_to_bytes(val.key); std::vector iv = hex_string_to_bytes(val.iv); std::vector plaintext = hex_string_to_bytes(val.plaintext); std::vector aad = hex_string_to_bytes(val.additional_data); std::vector result = hex_string_to_bytes(val.result); // Ignore GHASH-only vectors. if (key.empty()) { return; } // Prepare AEAD params. CK_GCM_PARAMS gcmParams; gcmParams.pIv = iv.data(); gcmParams.ulIvLen = iv.size(); gcmParams.pAAD = aad.data(); gcmParams.ulAADLen = aad.size(); gcmParams.ulTagBits = 128; SECItem params = {siBuffer, reinterpret_cast(&gcmParams), sizeof(gcmParams)}; ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); SECItem keyItem = {siBuffer, key.data(), static_cast(key.size())}; // Import key. ScopedPK11SymKey symKey(PK11_ImportSymKey( slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr)); EXPECT_TRUE(!!symKey); // Encrypt. unsigned int outputLen = 0; std::vector output(plaintext.size() + gcmParams.ulTagBits / 8); SECStatus rv = PK11_Encrypt(symKey.get(), mech, ¶ms, output.data(), &outputLen, output.size(), plaintext.data(), plaintext.size()); EXPECT_EQ(rv, SECSuccess); ASSERT_EQ(outputLen, output.size()); // Check ciphertext and tag. EXPECT_EQ(result, output); // Decrypt. unsigned int decryptedLen = 0; // The PK11 AES API is stupid, it expects an explicit IV and thus wants // a block more of available output memory. std::vector decrypted(output.size()); rv = PK11_Decrypt(symKey.get(), mech, ¶ms, decrypted.data(), &decryptedLen, decrypted.size(), output.data(), outputLen); EXPECT_EQ(rv, SECSuccess); ASSERT_EQ(decryptedLen, plaintext.size()); // Check the plaintext. EXPECT_EQ(plaintext, std::vector(decrypted.begin(), decrypted.begin() + decryptedLen)); } SECStatus EncryptWithIV(std::vector& iv) { // Generate a random key. ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ScopedPK11SymKey symKey( PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr)); EXPECT_TRUE(!!symKey); std::vector data(17); std::vector output(33); std::vector aad(0); // Prepare AEAD params. CK_GCM_PARAMS gcmParams; gcmParams.pIv = iv.data(); gcmParams.ulIvLen = iv.size(); gcmParams.pAAD = aad.data(); gcmParams.ulAADLen = aad.size(); gcmParams.ulTagBits = 128; SECItem params = {siBuffer, reinterpret_cast(&gcmParams), sizeof(gcmParams)}; // Try to encrypt. unsigned int outputLen = 0; return PK11_Encrypt(symKey.get(), mech, ¶ms, output.data(), &outputLen, output.size(), data.data(), data.size()); } const CK_MECHANISM_TYPE mech = CKM_AES_GCM; }; TEST_P(Pkcs11AesGcmTest, TestVectors) { RunTest(GetParam()); } INSTANTIATE_TEST_CASE_P(NISTTestVector, Pkcs11AesGcmTest, ::testing::ValuesIn(kGcmKatValues)); TEST_F(Pkcs11AesGcmTest, ZeroLengthIV) { std::vector iv(0); EXPECT_EQ(EncryptWithIV(iv), SECFailure); } TEST_F(Pkcs11AesGcmTest, AllZeroIV) { std::vector iv(16, 0); EXPECT_EQ(EncryptWithIV(iv), SECSuccess); } TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) { std::vector iv(12, 0); EXPECT_EQ(EncryptWithIV(iv), SECSuccess); } } // namespace nss_test