From 10cbb06a4b1f80b98011c03a1c63f918b4bf39a0 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 11 Nov 2015 14:33:39 -0800 Subject: [PATCH] Added test cases for CryConfigEncryptor --- src/config/crypto/CryConfigEncryptor.h | 3 - src/config/crypto/inner/InnerConfig.cpp | 2 +- src/config/crypto/inner/InnerConfig.h | 2 +- src/config/crypto/outer/OuterConfig.cpp | 2 +- src/config/crypto/outer/OuterConfig.h | 2 +- test/config/crypto/CryConfigEncryptorTest.cpp | 135 ++++++++++++++++++ 6 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 test/config/crypto/CryConfigEncryptorTest.cpp diff --git a/src/config/crypto/CryConfigEncryptor.h b/src/config/crypto/CryConfigEncryptor.h index 702e4695..a771d444 100644 --- a/src/config/crypto/CryConfigEncryptor.h +++ b/src/config/crypto/CryConfigEncryptor.h @@ -13,9 +13,6 @@ #include "../CryCipher.h" namespace cryfs { - //TODO Test - //TODO Test that encrypted config data always has the same size, no matter how big the plaintext config data - //TODO Test that specified inner cipher is used (e.g. can't be decrypted with other cipher) //TODO Use own exception for cpputils::Serializer/cpputils::Deserializer errors and only catch them class CryConfigEncryptor { public: diff --git a/src/config/crypto/inner/InnerConfig.cpp b/src/config/crypto/inner/InnerConfig.cpp index fa595f9e..a529b359 100644 --- a/src/config/crypto/inner/InnerConfig.cpp +++ b/src/config/crypto/inner/InnerConfig.cpp @@ -13,7 +13,7 @@ using namespace cpputils::logging; namespace cryfs { const string InnerConfig::HEADER = "cryfs.config.inner;0"; - Data InnerConfig::serialize() { + Data InnerConfig::serialize() const { try { Serializer serializer(Serializer::StringSize(HEADER) + Serializer::StringSize(cipherName) diff --git a/src/config/crypto/inner/InnerConfig.h b/src/config/crypto/inner/InnerConfig.h index e5681a13..5bbfb494 100644 --- a/src/config/crypto/inner/InnerConfig.h +++ b/src/config/crypto/inner/InnerConfig.h @@ -11,7 +11,7 @@ namespace cryfs { std::string cipherName; cpputils::Data encryptedConfig; - cpputils::Data serialize(); + cpputils::Data serialize() const; static boost::optional deserialize(const cpputils::Data &data); private: diff --git a/src/config/crypto/outer/OuterConfig.cpp b/src/config/crypto/outer/OuterConfig.cpp index 2bb5b392..a206399c 100644 --- a/src/config/crypto/outer/OuterConfig.cpp +++ b/src/config/crypto/outer/OuterConfig.cpp @@ -24,7 +24,7 @@ namespace cryfs { serializer->writeString(HEADER); } - Data OuterConfig::serialize() { + Data OuterConfig::serialize() const { try { Serializer serializer(Serializer::StringSize(HEADER) + keyConfig.serializedSize() diff --git a/src/config/crypto/outer/OuterConfig.h b/src/config/crypto/outer/OuterConfig.h index 5208c55f..5e6c0ab6 100644 --- a/src/config/crypto/outer/OuterConfig.h +++ b/src/config/crypto/outer/OuterConfig.h @@ -12,7 +12,7 @@ namespace cryfs { cpputils::DerivedKeyConfig keyConfig; cpputils::Data encryptedInnerConfig; - cpputils::Data serialize(); + cpputils::Data serialize() const; static boost::optional deserialize(const cpputils::Data &data); private: diff --git a/test/config/crypto/CryConfigEncryptorTest.cpp b/test/config/crypto/CryConfigEncryptorTest.cpp new file mode 100644 index 00000000..aca1958b --- /dev/null +++ b/test/config/crypto/CryConfigEncryptorTest.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include "../../../src/config/crypto/CryConfigEncryptor.h" + +using std::ostream; +using cpputils::unique_ref; +using cpputils::make_unique_ref; +using cpputils::DataFixture; +using cpputils::Data; +using cpputils::DerivedKeyConfig; +using cpputils::DerivedKey; +using cpputils::AES128_CFB; +using cpputils::AES256_GCM; +using cpputils::Twofish256_GCM; +using cpputils::Twofish128_CFB; +using boost::none; +using namespace cryfs; + +// This is needed for google test +namespace boost { + inline ostream &operator<<(ostream &stream, const CryConfigEncryptor::Decrypted &) { + return stream << "CryConfigEncryptor::Decrypted()"; + } +} + +class CryConfigEncryptorTest: public ::testing::Test { +public: + + unique_ref makeEncryptor() { + return make_unique_ref(_derivedKey()); + } + + Data changeInnerCipherFieldTo(Data data, const string &newCipherName) { + InnerConfig innerConfig = _decryptInnerConfig(data); + innerConfig.cipherName = newCipherName; + return _encryptInnerConfig(innerConfig); + } + +private: + DerivedKey _derivedKey() { + auto salt = DataFixture::generate(128, 2); + auto keyConfig = DerivedKeyConfig(std::move(salt), 1024, 1, 2); + auto key = DataFixture::generateFixedSize(3); + return DerivedKey(std::move(keyConfig), std::move(key)); + } + + unique_ref _outerEncryptor() { + auto outerKey = _derivedKey().key().take(); + return make_unique_ref(outerKey, _derivedKey().config()); + } + + InnerConfig _decryptInnerConfig(const Data &data) { + OuterConfig outerConfig = OuterConfig::deserialize(data).value(); + Data serializedInnerConfig = _outerEncryptor()->decrypt(outerConfig).value(); + return InnerConfig::deserialize(serializedInnerConfig).value(); + } + + Data _encryptInnerConfig(const InnerConfig &innerConfig) { + Data serializedInnerConfig = innerConfig.serialize(); + OuterConfig outerConfig = _outerEncryptor()->encrypt(serializedInnerConfig); + return outerConfig.serialize(); + } +}; + +TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Data_AES) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); + auto decrypted = encryptor->decrypt(encrypted).value(); + EXPECT_EQ(DataFixture::generate(400), decrypted.data); +} + +TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Data_Twofish) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), Twofish128_CFB::NAME); + auto decrypted = encryptor->decrypt(encrypted).value(); + EXPECT_EQ(DataFixture::generate(400), decrypted.data); +} + +TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Cipher_AES) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); + auto decrypted = encryptor->decrypt(encrypted).value(); + EXPECT_EQ(AES256_GCM::NAME, decrypted.cipherName); +} + +TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Cipher_Twofish) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), Twofish128_CFB::NAME); + auto decrypted = encryptor->decrypt(encrypted).value(); + EXPECT_EQ(Twofish128_CFB::NAME, decrypted.cipherName); +} + +TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_EmptyData) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(Data(0), AES256_GCM::NAME); + auto decrypted = encryptor->decrypt(encrypted).value(); + EXPECT_EQ(Data(0), decrypted.data); +} + +TEST_F(CryConfigEncryptorTest, InvalidCiphertext) { + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); + *(char*)encrypted.data() = *(char*)encrypted.data()+1; //Modify ciphertext + auto decrypted = encryptor->decrypt(encrypted); + EXPECT_EQ(none, decrypted); +} + +TEST_F(CryConfigEncryptorTest, DoesntEncryptWhenTooLarge) { + auto encryptor = makeEncryptor(); + EXPECT_THROW( + encryptor->encrypt(DataFixture::generate(2000), AES256_GCM::NAME), + std::runtime_error + ); +} + +TEST_F(CryConfigEncryptorTest, EncryptionIsFixedSize) { + auto encryptor = makeEncryptor(); + Data encrypted1 = encryptor->encrypt(DataFixture::generate(100), AES128_CFB::NAME); + Data encrypted2 = encryptor->encrypt(DataFixture::generate(200), Twofish256_GCM::NAME); + Data encrypted3 = encryptor->encrypt(Data(0), AES256_GCM::NAME); + + EXPECT_EQ(encrypted1.size(), encrypted2.size()); + EXPECT_EQ(encrypted1.size(), encrypted3.size()); +} + +TEST_F(CryConfigEncryptorTest, SpecifiedInnerCipherIsUsed) { + //Tests that it can't be decrypted if the inner cipher field stores the wrong cipher + auto encryptor = makeEncryptor(); + Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); + encrypted = changeInnerCipherFieldTo(std::move(encrypted), Twofish256_GCM::NAME); + auto decrypted = encryptor->decrypt(encrypted); + EXPECT_EQ(none, decrypted); +}