1362 lines
69 KiB
C++
1362 lines
69 KiB
C++
/**
|
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
* SPDX-License-Identifier: Apache-2.0.
|
|
*/
|
|
|
|
#define AWS_DISABLE_DEPRECATION
|
|
#ifndef NO_SYMMETRIC_ENCRYPTION
|
|
|
|
#include <aws/external/gtest.h>
|
|
#include <aws/core/Aws.h>
|
|
#include <aws/core/auth/AWSCredentialsProvider.h>
|
|
#include <aws/core/utils/Outcome.h>
|
|
#include <aws/core/client/ClientConfiguration.h>
|
|
#include <aws/core/utils/StringUtils.h>
|
|
#include <aws/core/utils/HashingUtils.h>
|
|
#include <aws/core/utils/crypto/ContentCryptoScheme.h>
|
|
#include <aws/core/utils/crypto/CryptoStream.h>
|
|
#include <aws/core/utils/HashingUtils.h>
|
|
#include <aws/core/utils/Array.h>
|
|
|
|
#include <aws/s3-encryption/modules/CryptoModule.h>
|
|
#include <aws/s3-encryption/modules/CryptoModuleFactory.h>
|
|
#include <aws/s3-encryption/materials/KMSEncryptionMaterials.h>
|
|
#include <aws/s3-encryption/materials/SimpleEncryptionMaterials.h>
|
|
#include <aws/s3-encryption/CryptoConfiguration.h>
|
|
#include <aws/s3-encryption/handlers/InstructionFileHandler.h>
|
|
#include <aws/s3-encryption/S3EncryptionClient.h>
|
|
#include <aws/s3/model/PutObjectRequest.h>
|
|
#include <aws/s3/model/GetObjectRequest.h>
|
|
#include <aws/s3/model/CreateBucketRequest.h>
|
|
#include <aws/s3/model/DeleteBucketRequest.h>
|
|
#include <aws/s3/model/DeleteObjectRequest.h>
|
|
|
|
#include <aws/kms/KMSClient.h>
|
|
#include <aws/kms/model/GenerateDataKeyRequest.h>
|
|
#include <aws/kms/model/EncryptRequest.h>
|
|
#include <aws/kms/model/DecryptRequest.h>
|
|
|
|
namespace
|
|
{
|
|
static const char* const ALLOCATION_TAG = "CryptoModuleTests";
|
|
static const char* const BUCKET_TEST_NAME = "testbucket";
|
|
static const char* const KEY_TEST_NAME = "testKey";
|
|
static const char* const BODY_STREAM_TEST = "This is a test message for encryption and decryption.";
|
|
static const char* const TEST_CMK_ID = "ARN:SOME_COMBINATION_OF_LETTERS_AND_NUMBERS";
|
|
static size_t const CBC_IV_SIZE_BYTES = 16u;
|
|
|
|
static const char* const BYTES_SPECIFIER = "bytes=0-10";
|
|
static const char* const GET_RANGE_SPECIFIER = "bytes=20-40";
|
|
static const char* const GET_RANGE_OUTPUT = "ge for encryption and";
|
|
static size_t const GCM_TAG_LENGTH = 128u;
|
|
static size_t const GCM_IV_SIZE_BYTES = 12u;
|
|
|
|
using namespace Aws::Auth;
|
|
using namespace Aws::Client;
|
|
using namespace Aws::S3Encryption;
|
|
using namespace Aws::Utils::Crypto;
|
|
using namespace Aws::Utils::Crypto::ContentCryptoSchemeMapper;
|
|
using namespace Aws::Utils::Crypto::KeyWrapAlgorithmMapper;
|
|
using namespace Aws::S3Encryption::Modules;
|
|
using namespace Aws::S3Encryption::Materials;
|
|
using namespace Aws::S3::Model;
|
|
using namespace Aws::S3;
|
|
using namespace Aws::KMS;
|
|
using namespace Aws::KMS::Model;
|
|
|
|
/*
|
|
* This is a class that represents a mock KMS Client which is used to encrypt/decrypt the content encryption key
|
|
* in the S3 Encryption Client module. When encrypt is called, it will take the plain text key and store it and
|
|
* return the user a different generated key to take place as the encrypted key. Then when decrypt is called, the
|
|
* plaintext key will be returned to the user. This does not actually decrypt or encrypt anything, but acts in
|
|
* the same fashion as an actual KMS Client.
|
|
*/
|
|
class MockKMSClient : public KMSClient
|
|
{
|
|
public:
|
|
MockKMSClient(ClientConfiguration clientConfiguration = ClientConfiguration()) :
|
|
KMSClient(Aws::Auth::AWSCredentials("", ""), clientConfiguration), m_encryptCalledCount(0), m_genDataKeyCalledCount(0), m_decryptCalledCount(0),
|
|
m_encryptedKey(Aws::Utils::Crypto::SymmetricCipher::GenerateKey()), m_decryptedKey(Aws::Utils::Crypto::SymmetricCipher::GenerateKey()),
|
|
m_triggerDecryptFailure(false), m_triggerCorruptedDecryption(false)
|
|
{
|
|
}
|
|
|
|
EncryptOutcome Encrypt(const EncryptRequest& request) const override
|
|
{
|
|
Aws::Utils::CryptoBuffer buffer(request.GetPlaintext().GetUnderlyingData(), request.GetPlaintext().GetLength());
|
|
m_decryptedKey = buffer;
|
|
|
|
m_encryptCalledCount++;
|
|
return PopulateSuccessfulEncryptOutcome();
|
|
}
|
|
|
|
GenerateDataKeyOutcome GenerateDataKey(const GenerateDataKeyRequest&) const override
|
|
{
|
|
m_genDataKeyCalledCount++;
|
|
return PopulateSuccessfulGenDataKeyOutcome();
|
|
}
|
|
|
|
DecryptOutcome Decrypt(const DecryptRequest&) const override
|
|
{
|
|
m_decryptCalledCount++;
|
|
if (m_triggerDecryptFailure)
|
|
{
|
|
return PopulateFailedDecryptOutcome();
|
|
}
|
|
if (m_triggerCorruptedDecryption)
|
|
{
|
|
return PopulateCorruptedDecryptOutcome();
|
|
}
|
|
return PopulateSuccessfulDecryptOutcome();
|
|
}
|
|
|
|
mutable size_t m_encryptCalledCount;
|
|
mutable size_t m_genDataKeyCalledCount;
|
|
mutable size_t m_decryptCalledCount;
|
|
Aws::Utils::CryptoBuffer m_encryptedKey;
|
|
mutable Aws::Utils::CryptoBuffer m_decryptedKey;
|
|
mutable bool m_triggerDecryptFailure;
|
|
mutable bool m_triggerCorruptedDecryption;
|
|
|
|
private:
|
|
EncryptOutcome PopulateSuccessfulEncryptOutcome() const
|
|
{
|
|
EncryptOutcome outcome;
|
|
EncryptResult result(outcome.GetResult());
|
|
result.SetCiphertextBlob(m_encryptedKey);
|
|
return result;
|
|
}
|
|
|
|
GenerateDataKeyOutcome PopulateSuccessfulGenDataKeyOutcome() const
|
|
{
|
|
GenerateDataKeyOutcome outcome;
|
|
GenerateDataKeyResult result(outcome.GetResult());
|
|
result.SetPlaintext(m_decryptedKey);
|
|
result.SetCiphertextBlob(m_encryptedKey);
|
|
return result;
|
|
}
|
|
|
|
DecryptOutcome PopulateSuccessfulDecryptOutcome() const
|
|
{
|
|
DecryptOutcome outcome;
|
|
DecryptResult result(outcome.GetResult());
|
|
result.SetPlaintext(m_decryptedKey);
|
|
return result;
|
|
}
|
|
|
|
DecryptOutcome PopulateFailedDecryptOutcome() const
|
|
{
|
|
return KMSError();
|
|
}
|
|
|
|
DecryptOutcome PopulateCorruptedDecryptOutcome() const
|
|
{
|
|
DecryptOutcome outcome;
|
|
DecryptResult result(outcome.GetResult());
|
|
result.SetPlaintext(Aws::Utils::CryptoBuffer(m_decryptedKey.GetUnderlyingData(), m_decryptedKey.GetLength() / 2));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
/*
|
|
* This is a class that represents a S3 Client which is used to mimic the put/get operations of a actual s3 client.
|
|
* During a put object, the body of the request is stored as well as the metadata of the request. This data is then
|
|
* populated into a get object result when a get operation is called. If a get request has a range specifying the
|
|
* last 16 bytes of data, we know this is the crypto tag stored at the end of the body for GCM encryption, and we
|
|
* return this. If the range is everything but the last 16 bytes then we only return that part of the body to the
|
|
* result.
|
|
*/
|
|
class MockS3Client : public Aws::S3::S3Client
|
|
{
|
|
public:
|
|
MockS3Client(Aws::Client::ClientConfiguration clientConfiguration = Aws::Client::ClientConfiguration()) :
|
|
S3Client(Aws::Auth::AWSCredentials("", ""), clientConfiguration), m_putObjectCalled(0), m_getObjectCalled(0), m_body(nullptr)
|
|
{
|
|
}
|
|
|
|
Aws::S3::Model::PutObjectOutcome PutObject(const Aws::S3::Model::PutObjectRequest& request) const override
|
|
{
|
|
m_putObjectCalled++;
|
|
if (request.GetKey().find(Aws::S3Encryption::Handlers::DEFAULT_INSTRUCTION_FILE_SUFFIX) != Aws::String::npos)
|
|
{
|
|
|
|
Aws::S3::Model::PutObjectOutcome outcome;
|
|
Aws::S3::Model::PutObjectResult result(outcome.GetResultWithOwnership());
|
|
return result;
|
|
}
|
|
m_metadata = request.GetMetadata();
|
|
m_requestContentLength = static_cast< size_t >(request.GetContentLength());
|
|
|
|
std::shared_ptr<Aws::IOStream> body = request.GetBody();
|
|
Aws::String tempBodyString((Aws::IStreamBufIterator(*body)), Aws::IStreamBufIterator());
|
|
bodyString = tempBodyString;
|
|
|
|
Aws::S3::Model::PutObjectOutcome outcome;
|
|
Aws::S3::Model::PutObjectResult result(outcome.GetResultWithOwnership());
|
|
return result;
|
|
}
|
|
|
|
Aws::S3::Model::GetObjectOutcome GetObject(const Aws::S3::Model::GetObjectRequest& request) const override
|
|
{
|
|
m_getObjectCalled++;
|
|
auto factory = request.GetResponseStreamFactory();
|
|
Aws::Utils::Stream::ResponseStream responseStream(factory);
|
|
|
|
Aws::String range = request.GetRange();
|
|
size_t written = 0;
|
|
if (!range.empty())
|
|
{
|
|
auto bytes = m_requestContentLength;
|
|
auto rangeBytes = CryptoModule::ParseGetObjectRequestRange(range, bytes);
|
|
responseStream.GetUnderlyingStream().write((const char*)bodyString.c_str() + rangeBytes.first, rangeBytes.second - rangeBytes.first + 1);
|
|
written = static_cast< size_t >(rangeBytes.second - rangeBytes.first);
|
|
}
|
|
else
|
|
{
|
|
responseStream.GetUnderlyingStream().write((const char*)bodyString.c_str(), m_requestContentLength);
|
|
written = m_requestContentLength;
|
|
}
|
|
|
|
responseStream.GetUnderlyingStream().flush();
|
|
Aws::AmazonWebServiceResult<Aws::Utils::Stream::ResponseStream> awsStream(std::move(responseStream), Aws::Http::HeaderValueCollection());
|
|
Aws::S3::Model::GetObjectResult getObjectResult(std::move(awsStream));
|
|
getObjectResult.SetContentLength(written);
|
|
getObjectResult.SetMetadata(m_metadata);
|
|
return Aws::S3::Model::GetObjectOutcome(std::move(getObjectResult));
|
|
}
|
|
|
|
Aws::S3::Model::HeadObjectOutcome HeadObject(const Aws::S3::Model::HeadObjectRequest&) const override
|
|
{
|
|
Aws::S3::Model::HeadObjectOutcome outcome;
|
|
Aws::S3::Model::HeadObjectResult result(outcome.GetResultWithOwnership());
|
|
result.SetMetadata(m_metadata);
|
|
result.SetContentLength(m_requestContentLength);
|
|
return result;
|
|
}
|
|
|
|
const Aws::Map<Aws::String, Aws::String>& GetMetadata() const
|
|
{
|
|
return m_metadata;
|
|
}
|
|
|
|
size_t GetRequestContentLength() const
|
|
{
|
|
return m_requestContentLength;
|
|
}
|
|
|
|
mutable size_t m_putObjectCalled;
|
|
mutable size_t m_getObjectCalled;
|
|
mutable Aws::String bodyString;
|
|
mutable Aws::Map<Aws::String, Aws::String> m_metadata;
|
|
mutable std::shared_ptr<Aws::IOStream> m_body;
|
|
mutable std::shared_ptr<Aws::IOStream> m_instructionBody;
|
|
mutable size_t m_requestContentLength;
|
|
};
|
|
|
|
class CryptoModulesTest : public ::testing::Test
|
|
{
|
|
protected:
|
|
/*
|
|
* Function to check if metadata map contains content crypto material.
|
|
* Use this function to make sure a put object request contains all the material after
|
|
* a PutObjectSecurely call.
|
|
*/
|
|
static void MetadataFilled(Aws::Map<Aws::String, Aws::String> metadataMap)
|
|
{
|
|
auto metadataEnd = metadataMap.end();
|
|
ASSERT_TRUE(metadataMap.find(CONTENT_KEY_HEADER) != metadataEnd && metadataMap.find(IV_HEADER) != metadataEnd
|
|
&& metadataMap.find(CRYPTO_TAG_LENGTH_HEADER) != metadataEnd && metadataMap.find(CONTENT_CRYPTO_SCHEME_HEADER) != metadataEnd
|
|
&& metadataMap.find(KEY_WRAP_ALGORITHM) != metadataEnd && metadataMap.find(MATERIALS_DESCRIPTION_HEADER) != metadataEnd);
|
|
ASSERT_TRUE(metadataMap[CONTENT_KEY_HEADER].size() > 0u);
|
|
ASSERT_TRUE(metadataMap[IV_HEADER].size() > 0u);
|
|
ASSERT_TRUE(metadataMap[CRYPTO_TAG_LENGTH_HEADER].size() > 0u);
|
|
ASSERT_TRUE(metadataMap[CONTENT_CRYPTO_SCHEME_HEADER].size() > 0u);
|
|
ASSERT_TRUE(metadataMap[KEY_WRAP_ALGORITHM].size() > 0u);
|
|
ASSERT_TRUE(metadataMap[MATERIALS_DESCRIPTION_HEADER].size() > 0u);
|
|
}
|
|
};
|
|
|
|
TEST_F(CryptoModulesTest, EncryptionOnlyOperationsTestWithSimpleEncryptionMaterials)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterials materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, 0u);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), CBC_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::CBC);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_KEY_WRAP);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(BODY_STREAM_TEST, ss.str().c_str());
|
|
ASSERT_EQ(s3Client.GetMetadata(), getOutcome.GetResult().GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 1u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithSimpleEncryptionMaterials)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterials materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_KEY_WRAP);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(BODY_STREAM_TEST, ss.str().c_str());
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
|
|
TEST_F(CryptoModulesTest, StrictAuthenticatedEncryptionOperationsTestWithSimpleEncryptionMaterials)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterials materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::STRICT_AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_KEY_WRAP);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, EncryptionOnlyOperationsTestWithSimpleEncryptionMaterialsWithGCMAAD)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterialsWithGCMAAD materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, 0u);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), CBC_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::CBC);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_GCM);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(BODY_STREAM_TEST, ss.str().c_str());
|
|
ASSERT_EQ(s3Client.GetMetadata(), getOutcome.GetResult().GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 1u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithSimpleEncryptionMaterialsWithGCMAAD)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterialsWithGCMAAD materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_GCM);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(BODY_STREAM_TEST, ss.str().c_str());
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
|
|
TEST_F(CryptoModulesTest, StrictAuthenticatedEncryptionOperationsTestWithSimpleEncryptionMaterialsWithGCMAAD)
|
|
{
|
|
Aws::Utils::CryptoBuffer masterKey = Aws::Utils::Crypto::SymmetricCipher::GenerateKey();
|
|
SimpleEncryptionMaterialsWithGCMAAD materials(masterKey);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::STRICT_AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_GCM);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, EncryptionOnlyOperationsTestWithKMSWithContextEncryptionMaterials)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
KMSWithContextEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, 0u);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), CBC_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::CBC);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS_CONTEXT);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
ASSERT_EQ(contentCryptoMaterial.GetEncryptedContentEncryptionKey(), kmsClient->m_encryptedKey);
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 1u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_encryptCalledCount, 0u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, EncryptionOnlyOperationsTestWithKMSEncryptionMaterials)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
KMSEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, 0u);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), CBC_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::CBC);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
ASSERT_EQ(contentCryptoMaterial.GetEncryptedContentEncryptionKey(), kmsClient->m_encryptedKey);
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 1u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 0u);
|
|
ASSERT_EQ(kmsClient->m_encryptCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithKMSEncryptionMaterials)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
KMSEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 0u);
|
|
ASSERT_EQ(kmsClient->m_encryptCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithKMSWithContextEncryptionMaterials)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
KMSWithContextEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS_CONTEXT);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithKMSWithContextEncryptionMaterialsWithFailedKMSDecryption)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
kmsClient->m_triggerDecryptFailure = true;
|
|
KMSWithContextEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS_CONTEXT);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_FALSE(getOutcome.IsSuccess());
|
|
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 0u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AuthenticatedEncryptionOperationsTestWithKMSWithContextEncryptionMaterialsWithCorruptedKMSDecryption)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
kmsClient->m_triggerCorruptedDecryption = true;
|
|
KMSWithContextEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS_CONTEXT);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_FALSE(getOutcome.IsSuccess());
|
|
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, AERangeGet)
|
|
{
|
|
SimpleEncryptionMaterials materials(Aws::Utils::Crypto::SymmetricCipher::GenerateKey());
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(GCM_TAG_LENGTH, cryptoTagLength);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(GCM_IV_SIZE_BYTES, ivBuffer.GetLength());
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(ContentCryptoScheme::GCM, scheme);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(KeyWrapAlgorithm::AES_KEY_WRAP, keyWrapAlgorithm);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
getRequest.SetRange(GET_RANGE_SPECIFIER);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(GET_RANGE_OUTPUT, ss.str().c_str());
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
//we should not have pulled a tag here.
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 1u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
}
|
|
|
|
|
|
TEST_F(CryptoModulesTest, StrictAuthenticatedEncryptionOperationsTestWithKMSWithContextEncryptionMaterials)
|
|
{
|
|
auto kmsClient = Aws::MakeShared<MockKMSClient>(ALLOCATION_TAG, ClientConfiguration());
|
|
KMSWithContextEncryptionMaterials materials(TEST_CMK_ID, kmsClient);
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::STRICT_AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::KMS_CONTEXT);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<KMSWithContextEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto getOutcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_TRUE(getOutcome.IsSuccess());
|
|
Aws::OStream& ostream = getOutcome.GetResult().GetBody();
|
|
Aws::OStringStream ss;
|
|
ss << ostream.rdbuf();
|
|
|
|
ASSERT_STREQ(ss.str().c_str(), BODY_STREAM_TEST);
|
|
ASSERT_EQ(getOutcome.GetResult().GetMetadata(), s3Client.GetMetadata());
|
|
ASSERT_EQ(s3Client.m_getObjectCalled, 2u);
|
|
ASSERT_EQ(s3Client.m_putObjectCalled, 1u);
|
|
ASSERT_EQ(kmsClient->m_genDataKeyCalledCount, 1u);
|
|
ASSERT_EQ(kmsClient->m_decryptCalledCount, 1u);
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, StrictAERangeGet)
|
|
{
|
|
SimpleEncryptionMaterials materials(Aws::Utils::Crypto::SymmetricCipher::GenerateKey());
|
|
CryptoConfiguration cryptoConfig(StorageMethod::METADATA, CryptoMode::STRICT_AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, GCM_TAG_LENGTH);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), GCM_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::GCM);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_KEY_WRAP);
|
|
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), cryptoConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
getRequest.SetRange(BYTES_SPECIFIER);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto outcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_FALSE(outcome.IsSuccess());
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, StrictAEDecryptionFailure)
|
|
{
|
|
SimpleEncryptionMaterials materials(Aws::Utils::Crypto::SymmetricCipher::GenerateKey());
|
|
CryptoConfiguration eoConfig(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
CryptoConfiguration strictAEConfig(StorageMethod::METADATA, CryptoMode::STRICT_AUTHENTICATED_ENCRYPTION);
|
|
|
|
MockS3Client s3Client;
|
|
|
|
CryptoModuleFactory factory;
|
|
auto module = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), eoConfig);
|
|
|
|
PutObjectRequest putRequest;
|
|
putRequest.SetBucket(BUCKET_TEST_NAME);
|
|
std::shared_ptr<Aws::IOStream> objectStream = Aws::MakeShared<Aws::StringStream>(ALLOCATION_TAG);
|
|
*objectStream << BODY_STREAM_TEST;
|
|
objectStream->flush();
|
|
putRequest.SetBody(objectStream);
|
|
putRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
auto putObjectFunction = [&s3Client](Aws::S3::Model::PutObjectRequest putRequest) -> Aws::S3::Model::PutObjectOutcome { return s3Client.PutObject(putRequest); };
|
|
auto putOutcome = module->PutObjectSecurely(putRequest, putObjectFunction);
|
|
ASSERT_TRUE(putOutcome.IsSuccess());
|
|
|
|
auto metadata = s3Client.GetMetadata();
|
|
MetadataFilled(metadata);
|
|
|
|
size_t cryptoTagLength = static_cast<size_t>(Aws::Utils::StringUtils::ConvertToInt64(metadata[CRYPTO_TAG_LENGTH_HEADER].c_str()));
|
|
ASSERT_EQ(cryptoTagLength, 0u);
|
|
|
|
Aws::Utils::CryptoBuffer ivBuffer = Aws::Utils::HashingUtils::Base64Decode(metadata[IV_HEADER]);
|
|
ASSERT_EQ(ivBuffer.GetLength(), CBC_IV_SIZE_BYTES);
|
|
|
|
ContentCryptoScheme scheme = ContentCryptoSchemeMapper::GetContentCryptoSchemeForName(metadata[CONTENT_CRYPTO_SCHEME_HEADER]);
|
|
ASSERT_EQ(scheme, ContentCryptoScheme::CBC);
|
|
|
|
KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithmMapper::GetKeyWrapAlgorithmForName(metadata[KEY_WRAP_ALGORITHM]);
|
|
ASSERT_EQ(keyWrapAlgorithm, KeyWrapAlgorithm::AES_KEY_WRAP);
|
|
|
|
//check to make sure content length is now padded since StrictAE appends the tag to the end of the body
|
|
ASSERT_TRUE(s3Client.GetRequestContentLength() > strlen(BODY_STREAM_TEST));
|
|
|
|
auto decryptionModule = factory.FetchCryptoModule(Aws::MakeShared<SimpleEncryptionMaterials>(ALLOCATION_TAG, materials), strictAEConfig);
|
|
GetObjectRequest getRequest;
|
|
getRequest.SetBucket(BUCKET_TEST_NAME);
|
|
getRequest.SetKey(KEY_TEST_NAME);
|
|
|
|
HeadObjectRequest headObject;
|
|
headObject.WithBucket(BUCKET_TEST_NAME);
|
|
headObject.WithKey(KEY_TEST_NAME);
|
|
HeadObjectOutcome headOutcome = s3Client.HeadObject(headObject);
|
|
|
|
Aws::S3Encryption::Handlers::MetadataHandler handler;
|
|
ContentCryptoMaterial contentCryptoMaterial = handler.ReadContentCryptoMaterial(headOutcome.GetResult());
|
|
|
|
auto getObjectFunction = [&s3Client](Aws::S3::Model::GetObjectRequest getRequest) -> Aws::S3::Model::GetObjectOutcome { return s3Client.GetObject(getRequest); };
|
|
auto outcome = decryptionModule->GetObjectSecurely(getRequest, headOutcome.GetResult(), contentCryptoMaterial, getObjectFunction);
|
|
ASSERT_FALSE(outcome.IsSuccess());
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, RangeParserSuccess)
|
|
{
|
|
SimpleEncryptionMaterials materials(Aws::Utils::Crypto::SymmetricCipher::GenerateKey());
|
|
CryptoConfiguration config(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
CryptoModuleFactory factory;
|
|
|
|
int64_t contentLength = 90;
|
|
Aws::Vector<Aws::String> rangeOptions = { "bytes=10-20", "bytes=-20", "bytes=20-", "bytes=1-9" };
|
|
Aws::Vector<std::pair<int64_t, int64_t>> resultPairs = {
|
|
std::make_pair(10LL, 20LL),
|
|
std::make_pair(70LL, contentLength - 1),
|
|
std::make_pair(20LL, contentLength - 1),
|
|
std::make_pair(1LL, 9LL)
|
|
};
|
|
|
|
for (size_t i = 0; i < rangeOptions.size(); ++i)
|
|
{
|
|
auto pair = CryptoModule::ParseGetObjectRequestRange(rangeOptions[i], contentLength);
|
|
ASSERT_EQ(pair, resultPairs[i]);
|
|
}
|
|
}
|
|
|
|
TEST_F(CryptoModulesTest, RangeParserFailure)
|
|
{
|
|
SimpleEncryptionMaterials materials(Aws::Utils::Crypto::SymmetricCipher::GenerateKey());
|
|
CryptoConfiguration config(StorageMethod::METADATA, CryptoMode::ENCRYPTION_ONLY);
|
|
CryptoModuleFactory factory;
|
|
|
|
int64_t contentLength = 90;
|
|
Aws::Vector<Aws::String> rangeOptions = { "bytes10-20", "bytes=20", "20=-", "bytes19" };
|
|
|
|
for (size_t i = 0; i < rangeOptions.size(); ++i)
|
|
{
|
|
auto pair = CryptoModule::ParseGetObjectRequestRange(rangeOptions[i], contentLength);
|
|
ASSERT_EQ(pair, std::make_pair(static_cast<int64_t>(0), static_cast<int64_t>(0)));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|