azure-protected-vm-secrets/SecretsProvsioningUT/BcryptTests.cpp (291 lines of code) (raw):
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#ifndef PLATFORM_UNIX
#define UMDF_USING_NTSTATUS
#include <windows.h>
#include "BcryptError.h"
#endif
#include "AesWrapper.h"
#ifdef PLATFORM_UNIX
#include "Linux/OsslAesWrapper.h"
#include "Linux/OsslError.h"
#include "Linux/OsslECDiffieHellman.h"
#include "Linux/OsslHKDF.h"
#else
#include "Windows/BcryptAesWrapper.h"
#include "Windows/BcryptECDiffieHellman.h"
#include "Windows/BcryptHKDF.h"
#endif // PLATFORM_UNIX
// Unit test for AesWrapper
TEST(AesWrapperTest, ConstructorTest)
{
// Test that the constructor initializes the AesWrapper object
std::unique_ptr<AesWrapper> aesWrapper;
std::unique_ptr<AesCreator> aesCreator;
try {
#ifndef PLATFORM_UNIX
aesCreator = std::make_unique<GcmCreator>();
#else
aesCreator = std::make_unique<OsslGcmCreator>();
#endif // !PLATFORM_UNIX
aesWrapper = aesCreator->CreateAesWrapper();
ASSERT_NE(aesWrapper, nullptr);
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
TEST(AesWrapperTest, AesEncryptDecryptTest)
{
std::vector<unsigned char> decryptedData;
std::vector<unsigned char> plaintextData(121, 0x01);
std::vector<unsigned char> encryptedData;
std::unique_ptr<AesWrapper> aesWrapper, decryptAesWrapper;
std::unique_ptr<AesCreator> aesCreator;
std::unique_ptr<AesChainingInfo> aesChainingInfo;
// Test the AesEncrypt method
try {
#ifdef PLATFORM_UNIX
aesCreator = std::make_unique<OsslGcmCreator>();
#else
aesCreator = std::make_unique<GcmCreator>();
#endif // PLATFORM_UNIX
aesWrapper = aesCreator->CreateAesWrapper();
decryptAesWrapper= aesCreator->CreateAesWrapper();
std::vector<unsigned char> key(32, 0);
aesWrapper->SetKey(key);
aesChainingInfo = aesWrapper->SetChainingInfo(std::vector<unsigned char>(12, 0));
encryptedData = aesWrapper->Encrypt(plaintextData, aesChainingInfo.get());
// Explicitly delete as we reset the pointer
delete aesChainingInfo.release();
decryptAesWrapper->SetKey(key);
aesChainingInfo = decryptAesWrapper->SetChainingInfo(std::vector<unsigned char>(12, 0));
decryptedData = decryptAesWrapper->Decrypt(encryptedData, aesChainingInfo.get());
}
#ifndef PLATFORM_UNIX
catch (BcryptError e) {
printf("Bcrypt status 0x%x occurred\n Message %s\t Bcrypt Info%s",
e.getStatusCode(), e.what(), e.getErrorInfo());
}
#else
catch (OsslError err) {
printf("Openssl Error\n Message %s\t Bcrypt Info%s",
err.what(), err.getErrorInfo());
}
#endif
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
ASSERT_EQ(encryptedData.size(), plaintextData.size() + 16);
ASSERT_EQ(decryptedData.size(), plaintextData.size());
ASSERT_EQ(decryptedData, plaintextData);
}
TEST(AesWrapperTest, AesEncryptTestFail)
{
std::vector<unsigned char> decryptedData;
std::vector<unsigned char> plaintextData = { 0x01, 0x02, 0x03, 0x04 };
std::vector<unsigned char> encryptedData;
std::unique_ptr<AesWrapper> aesWrapper;
std::unique_ptr<AesCreator> aesCreator;
std::unique_ptr<AesChainingInfo> aesChainingInfo;
std::vector<unsigned char> key(16, 0);
#ifdef PLATFORM_UNIX
aesCreator = std::make_unique<OsslGcmCreator>();
#else
aesCreator = std::make_unique<GcmCreator>();
#endif // PLATFORM_UNIX
aesWrapper = aesCreator->CreateAesWrapper();
aesWrapper->SetKey(key);
// Test the AesDecrypt method
EXPECT_THROW( {
encryptedData = aesWrapper->Encrypt(plaintextData, nullptr);
}, std::exception);
}
TEST(AesWrapperTest, AesDecryptTestFail)
{
std::vector<unsigned char> decryptedData;
std::vector<unsigned char> plaintextData = { 0x01, 0x02, 0x03, 0x04 };
std::vector<unsigned char> encryptedData;
std::unique_ptr<AesWrapper> aesWrapper;
std::unique_ptr<AesCreator> aesCreator;
std::unique_ptr<AesChainingInfo> aesChainingInfo;
std::vector<unsigned char> key(16, 0);
try {
#ifdef PLATFORM_UNIX
aesCreator = std::make_unique<OsslGcmCreator>();
#else
aesCreator = std::make_unique<GcmCreator>();
#endif // PLATFORM_UNIX
aesWrapper = aesCreator->CreateAesWrapper();
aesWrapper->SetKey(key);
aesChainingInfo = aesWrapper->SetChainingInfo(std::vector<unsigned char>(12, 0));
encryptedData = aesWrapper->Encrypt(plaintextData, aesChainingInfo.get());
}
#ifndef PLATFORM_UNIX
catch (BcryptError e) {
printf("Bcrypt status 0x%x occurred\n Message %s\t Bcrypt Info%s",
e.getStatusCode(), e.what(), e.getErrorInfo());
}
#endif
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
// Test the AesDecrypt method. Expected fail as the chaining info is nullptr.
EXPECT_THROW({
decryptedData = aesWrapper->Decrypt(encryptedData, nullptr);
}, std::exception);
}
TEST(AesWrapperTest, AesDecryptMacFail)
{
std::vector<unsigned char> decryptedData;
std::vector<unsigned char> plaintextData = { 0x01, 0x02, 0x03, 0x04 };
std::vector<unsigned char> encryptedData;
std::unique_ptr<AesWrapper> aesWrapper;
std::unique_ptr<AesCreator> aesCreator;
std::unique_ptr<AesChainingInfo> aesChainingInfo;
std::vector<unsigned char> key(16, 0);
try {
#ifdef PLATFORM_UNIX
aesCreator = std::make_unique<OsslGcmCreator>();
#else
aesCreator = std::make_unique<GcmCreator>();
#endif // PLATFORM_UNIX
aesWrapper = aesCreator->CreateAesWrapper();
aesWrapper->SetKey(key);
aesChainingInfo = aesWrapper->SetChainingInfo(std::vector<unsigned char>(12, 0));
encryptedData = aesWrapper->Encrypt(plaintextData, aesChainingInfo.get());
// Explicitly delete as we reset the pointer
delete aesChainingInfo.release();
}
#ifndef PLATFORM_UNIX
catch (BcryptError e) {
printf("Bcrypt status 0x%x occurred\n Message %s\t Bcrypt Info%s",
e.getStatusCode(), e.what(), e.getErrorInfo());
}
#endif
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
// Modify the Mac
encryptedData[encryptedData.size() - 1] = 0x00;
aesChainingInfo = aesWrapper->SetChainingInfo(std::vector<unsigned char>(12, 0));
// Test the AesDecrypt method. Expect a BcryptError.
#ifdef PLATFORM_UNIX
EXPECT_THROW({
decryptedData = aesWrapper->Decrypt(encryptedData, aesChainingInfo.get());
}, std::exception);
#else
EXPECT_THROW({
decryptedData = aesWrapper->Decrypt(encryptedData, aesChainingInfo.get());
}, BcryptError);
#endif
}
// Unit test for ECDiffieHellman
TEST(ECDiffieHellmanTest, ConstructorTest)
{
// Test that the constructor initializes the ECDiffieHellman object
try {
#ifndef PLATFORM_UNIX
std::unique_ptr<BcryptECDiffieHellman> ecDiffieHellman;
ecDiffieHellman = std::make_unique<BcryptECDiffieHellman>();
#else
std::unique_ptr<OsslECDiffieHellman> ecDiffieHellman;
ecDiffieHellman = std::make_unique<OsslECDiffieHellman>();
#endif // !PLATFORM_UNIX
ASSERT_NE(ecDiffieHellman, nullptr);
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
TEST(ECDiffieHellmanTest, ImportExportTest)
{
std::vector<unsigned char> publicKey;
std::vector<unsigned char> privateKey;
#ifdef PLATFORM_UNIX
std::unique_ptr<OsslECDiffieHellman> ecDiffieHellmanA, ecDiffieHellmanB, importKeyA, imporKeyB;
#else
std::unique_ptr<BcryptECDiffieHellman> ecDiffieHellmanA, ecDiffieHellmanB, importKeyA, imporKeyB;
#endif // PLATFORM_UNIX
// Test the GenerateKeyPair method
try {
#ifdef PLATFORM_UNIX
ecDiffieHellmanA = std::make_unique<OsslECDiffieHellman>();
ecDiffieHellmanB = std::make_unique<OsslECDiffieHellman>();
importKeyA = std::make_unique<OsslECDiffieHellman>();
imporKeyB = std::make_unique<OsslECDiffieHellman>();
#else
ecDiffieHellmanA = std::make_unique<BcryptECDiffieHellman>();
ecDiffieHellmanB = std::make_unique<BcryptECDiffieHellman>();
importKeyA = std::make_unique<BcryptECDiffieHellman>();
imporKeyB = std::make_unique<BcryptECDiffieHellman>();
#endif // PLATFORM_UNIX
ecDiffieHellmanA->GenerateKeyPair();
ecDiffieHellmanB->GenerateKeyPair();
publicKey = ecDiffieHellmanA->ExportSubjectPublicKeyInfo();
privateKey = ecDiffieHellmanB->ExportPkcs8PrivateKey();
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
ASSERT_NO_THROW(
importKeyA->ImportSubjectPublicKeyInfo(publicKey);
imporKeyB->ImportPkcs8PrivateKey(privateKey);
);
}
TEST(ECDiffieHellmanTest, KeyGenTest)
{
std::vector<unsigned char> publicKey;
std::vector<unsigned char> privateKey;
std::vector<unsigned char> testKDFInput = std::vector<unsigned char>(16, 0);
std::vector<unsigned char> derivedSecretA, derivedSecretB;
#ifdef PLATFORM_UNIX
std::unique_ptr<OsslECDiffieHellman> ecDiffieHellmanA, ecDiffieHellmanB, importKeyA, importKeyB;
std::unique_ptr<OsslHKDF> hkdfA, hkdfB;
std::vector<unsigned char> secretA, secretB;
#else
std::unique_ptr<BcryptECDiffieHellman> ecDiffieHellmanA, ecDiffieHellmanB, importKeyA, importKeyB;
std::unique_ptr<BcryptHKDF> hkdfA, hkdfB;
BCRYPT_SECRET_HANDLE secretA, secretB;
#endif // PLATFORM_UNIX
// Test the GenerateKeyPair method
try {
#ifdef PLATFORM_UNIX
ecDiffieHellmanA = std::make_unique<OsslECDiffieHellman>();
ecDiffieHellmanB = std::make_unique<OsslECDiffieHellman>();
importKeyA = std::make_unique<OsslECDiffieHellman>();
importKeyB = std::make_unique<OsslECDiffieHellman>();
#else
ecDiffieHellmanA = std::make_unique<BcryptECDiffieHellman>();
ecDiffieHellmanB = std::make_unique<BcryptECDiffieHellman>();
importKeyA = std::make_unique<BcryptECDiffieHellman>();
importKeyB = std::make_unique<BcryptECDiffieHellman>();
#endif // PLATFORM_UNIX
ecDiffieHellmanA->GenerateKeyPair();
ecDiffieHellmanB->GenerateKeyPair();
publicKey = ecDiffieHellmanA->ExportSubjectPublicKeyInfo();
privateKey = ecDiffieHellmanB->ExportPkcs8PrivateKey();
importKeyA->ImportSubjectPublicKeyInfo(publicKey);
importKeyB->ImportPkcs8PrivateKey(privateKey);
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
#ifdef PLATFORM_UNIX
ASSERT_NO_THROW(
secretA = ecDiffieHellmanA->DeriveSecret(*ecDiffieHellmanB);
secretB = importKeyB->DeriveSecret(*importKeyA);
hkdfA = std::make_unique<OsslHKDF>(secretA);
hkdfB = std::make_unique<OsslHKDF>(secretB);
derivedSecretA = hkdfA->DeriveKey(testKDFInput, testKDFInput, 32);
derivedSecretB = hkdfB->DeriveKey(testKDFInput, testKDFInput, 32);
);
ASSERT_EQ(secretA, secretB);
#else
ASSERT_NO_THROW(
secretA = ecDiffieHellmanA->DeriveSecret(*ecDiffieHellmanB);
secretB = importKeyB->DeriveSecret(*importKeyA);
hkdfA = std::make_unique<BcryptHKDF>(secretA);
hkdfB = std::make_unique<BcryptHKDF>(secretB);
derivedSecretA = hkdfA->DeriveKey(testKDFInput, testKDFInput, 32);
derivedSecretB = hkdfB->DeriveKey(testKDFInput, testKDFInput, 32);
);
#endif // PLATFORM_UNIX
ASSERT_EQ(derivedSecretA.size(), 32);
ASSERT_EQ(derivedSecretB.size(), 32);
ASSERT_EQ(derivedSecretA, derivedSecretB);
}