From 252a666a37cd2c29ab8d986bcf4055eed053dcde Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Tue, 10 Nov 2015 17:50:08 -0800 Subject: [PATCH] Refactor (de)serializing config files --- src/config/CryCipher.cpp | 6 +- src/config/CryCipher.h | 4 + src/config/crypto/ConcreteInnerEncryptor.h | 95 ------------------- src/config/crypto/CryConfigEncryptor.cpp | 58 ++--------- src/config/crypto/CryConfigEncryptor.h | 15 +-- .../crypto/CryConfigEncryptorFactory.cpp | 43 +++++---- src/config/crypto/CryConfigEncryptorFactory.h | 24 ++--- src/config/crypto/InnerEncryptor.cpp | 21 ---- src/config/crypto/OuterConfig.cpp | 55 +++++++++++ src/config/crypto/OuterConfig.h | 26 +++++ .../{ => inner}/ConcreteInnerEncryptor.cpp | 0 .../crypto/inner/ConcreteInnerEncryptor.h | 61 ++++++++++++ src/config/crypto/inner/InnerConfig.cpp | 55 +++++++++++ src/config/crypto/inner/InnerConfig.h | 25 +++++ src/config/crypto/inner/InnerEncryptor.cpp | 1 + .../crypto/{ => inner}/InnerEncryptor.h | 11 +-- 16 files changed, 280 insertions(+), 220 deletions(-) delete mode 100644 src/config/crypto/ConcreteInnerEncryptor.h delete mode 100644 src/config/crypto/InnerEncryptor.cpp create mode 100644 src/config/crypto/OuterConfig.cpp create mode 100644 src/config/crypto/OuterConfig.h rename src/config/crypto/{ => inner}/ConcreteInnerEncryptor.cpp (100%) create mode 100644 src/config/crypto/inner/ConcreteInnerEncryptor.h create mode 100644 src/config/crypto/inner/InnerConfig.cpp create mode 100644 src/config/crypto/inner/InnerConfig.h create mode 100644 src/config/crypto/inner/InnerEncryptor.cpp rename src/config/crypto/{ => inner}/InnerEncryptor.h (60%) diff --git a/src/config/CryCipher.cpp b/src/config/CryCipher.cpp index c0bdbd94..30c419b8 100644 --- a/src/config/CryCipher.cpp +++ b/src/config/CryCipher.cpp @@ -17,11 +17,15 @@ using blockstore::encrypted::EncryptedBlockStore; using namespace cryfs; using namespace cpputils; +constexpr size_t CryCiphers::MAX_KEY_SIZE; + template class CryCipherInstance: public CryCipher { public: BOOST_CONCEPT_ASSERT((CipherConcept)); + static_assert(Cipher::EncryptionKey::BINARY_LENGTH <= CryCiphers::MAX_KEY_SIZE, "The key size for this cipher is too large. Please modify CryCiphers::MAX_KEY_SIZE"); + CryCipherInstance(const optional warning = none): _warning(warning) { } @@ -86,4 +90,4 @@ vector CryCiphers::supportedCipherNames() { result.push_back(cipher->cipherName()); } return result; -} \ No newline at end of file +} diff --git a/src/config/CryCipher.h b/src/config/CryCipher.h index 416093a9..f3adcef0 100644 --- a/src/config/CryCipher.h +++ b/src/config/CryCipher.h @@ -24,6 +24,10 @@ class CryCiphers { public: static std::vector supportedCipherNames(); + //A static_assert in CryCipherInstance ensures that there is no cipher with a key size larger than specified here. + //TODO Calculate this from SUPPORTED_CIPHERS instead of setting it manually + static constexpr size_t MAX_KEY_SIZE = 56; // in bytes + static const CryCipher& find(const std::string &cipherName); private: diff --git a/src/config/crypto/ConcreteInnerEncryptor.h b/src/config/crypto/ConcreteInnerEncryptor.h deleted file mode 100644 index 728f28b0..00000000 --- a/src/config/crypto/ConcreteInnerEncryptor.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H -#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H - -#include -#include -#include "InnerEncryptor.h" -#include -#include - -namespace cryfs { - //TODO Test - template - class ConcreteInnerEncryptor: public InnerEncryptor { - public: - static constexpr size_t CONFIG_SIZE = 512; // Inner config data is grown to this size before encryption to hide its actual size - - ConcreteInnerEncryptor(typename Cipher::EncryptionKey key); - - cpputils::Data encrypt(const cpputils::Data &plaintext) const override; - boost::optional decrypt(const cpputils::Data &ciphertext) const override; - private: - - cpputils::Data _serialize(const cpputils::Data &data) const; - boost::optional _deserialize(const cpputils::Data &data) const; - - typename Cipher::EncryptionKey _key; - }; - - template - ConcreteInnerEncryptor::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key) - : _key(std::move(key)) { - } - - template - boost::optional ConcreteInnerEncryptor::decrypt(const cpputils::Data &ciphertext) const { - auto data = _deserialize(ciphertext); - if (data == boost::none) { - return boost::none; - } - auto decrypted = Cipher::decrypt(static_cast(data->data()), data->size(), _key); - if (decrypted == boost::none) { - return boost::none; - } - auto configData = cpputils::RandomPadding::remove(*decrypted); - if (configData == boost::none) { - return boost::none; - } - return std::move(*configData); - } - - template - boost::optional ConcreteInnerEncryptor::_deserialize(const cpputils::Data &ciphertext) const { - cpputils::Deserializer deserializer(&ciphertext); - try { - _checkHeader(&deserializer); - std::string readCipherName = deserializer.readString(); - if (readCipherName != Cipher::NAME) { - cpputils::logging::LOG(cpputils::logging::ERROR) << "Wrong inner cipher used"; - return boost::none; - } - auto result = deserializer.readTailData(); - deserializer.finished(); - return std::move(result); // TODO This std::move() is not necessary on newer gcc versions. Remove it and look for other occurrences of the same. - } catch (const std::exception &e) { - cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing inner configuration: " << e.what(); - return boost::none; // This can be caused by invalid input data and does not have to be a programming error. Don't throw exception. - } - } - - template - cpputils::Data ConcreteInnerEncryptor::encrypt(const cpputils::Data &plaintext) const { - auto paddedPlaintext = cpputils::RandomPadding::add(plaintext, CONFIG_SIZE); - auto encrypted = Cipher::encrypt(static_cast(paddedPlaintext.data()), paddedPlaintext.size(), _key); - return _serialize(encrypted); - } - - template - cpputils::Data ConcreteInnerEncryptor::_serialize(const cpputils::Data &ciphertext) const { - try { - cpputils::Serializer serializer(cpputils::Serializer::StringSize(HEADER) - + cpputils::Serializer::StringSize(Cipher::NAME) - + ciphertext.size()); - serializer.writeString(HEADER); - serializer.writeString(Cipher::NAME); - serializer.writeTailData(ciphertext); - return serializer.finished(); - } catch (const std::exception &e) { - cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing inner configuration: " << e.what(); - throw; // This is a programming logic error, pass through exception. - } - } -} - -#endif diff --git a/src/config/crypto/CryConfigEncryptor.cpp b/src/config/crypto/CryConfigEncryptor.cpp index fff1092f..bf1b8f13 100644 --- a/src/config/crypto/CryConfigEncryptor.cpp +++ b/src/config/crypto/CryConfigEncryptor.cpp @@ -1,9 +1,8 @@ #include "CryConfigEncryptor.h" #include +#include "OuterConfig.h" using std::string; -using cpputils::Deserializer; -using cpputils::Serializer; using cpputils::unique_ref; using cpputils::Data; using cpputils::RandomPadding; @@ -13,66 +12,27 @@ using boost::none; using namespace cpputils::logging; namespace cryfs { - const string CryConfigEncryptor::HEADER = "cryfs.config;0;scrypt"; - CryConfigEncryptor::CryConfigEncryptor(unique_ref innerEncryptor, OuterCipher::EncryptionKey outerKey, DerivedKeyConfig keyConfig) : _innerEncryptor(std::move(innerEncryptor)), _outerKey(std::move(outerKey)), _keyConfig(std::move(keyConfig)) { } - void CryConfigEncryptor::checkHeader(Deserializer *deserializer) { - string header = deserializer->readString(); - if (header != HEADER) { - throw std::runtime_error("Invalid header"); - } - } - - void CryConfigEncryptor::writeHeader(Serializer *serializer) { - serializer->writeString(HEADER); - } - Data CryConfigEncryptor::encrypt(const Data &plaintext) { auto inner = _innerEncryptor->encrypt(plaintext); auto padded = RandomPadding::add(inner, CONFIG_SIZE); auto ciphertext = OuterCipher::encrypt(static_cast(padded.data()), padded.size(), _outerKey); - return _serialize(ciphertext); + return OuterConfig{_keyConfig, std::move(ciphertext)}.serialize(); } - Data CryConfigEncryptor::_serialize(const Data &ciphertext) { - try { - Serializer serializer(Serializer::StringSize(HEADER) - + _keyConfig.serializedSize() - + ciphertext.size()); - writeHeader(&serializer); - _keyConfig.serialize(&serializer); - serializer.writeTailData(ciphertext); - return serializer.finished(); - } catch (const std::exception &e) { - cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing CryConfigEncryptor: " << e.what(); - throw; // This is a programming logic error. Pass through exception. + optional CryConfigEncryptor::decrypt(const Data &data) { + auto outerConfig = OuterConfig::deserialize(data); + if (outerConfig == none) { + return none; } + return _decryptInnerConfig(outerConfig->encryptedInnerConfig); } - optional CryConfigEncryptor::decrypt(const Data &plaintext) { - Deserializer deserializer(&plaintext); - try { - checkHeader(&deserializer); - _ignoreKey(&deserializer); - auto result = _loadAndDecryptConfigData(&deserializer); - deserializer.finished(); - return result; - } catch (const std::exception &e) { - LOG(ERROR) << "Error loading configuration: " << e.what(); - return boost::none; // This can be caused by invalid loaded data and is not necessarily a programming logic error. Don't throw exception. - } - } - - void CryConfigEncryptor::_ignoreKey(Deserializer *deserializer) { - DerivedKeyConfig::load(deserializer); - } - - optional CryConfigEncryptor::_loadAndDecryptConfigData(Deserializer *deserializer) { - auto ciphertext = deserializer->readTailData(); - auto inner = OuterCipher::decrypt(static_cast(ciphertext.data()), ciphertext.size(), _outerKey); + optional CryConfigEncryptor::_decryptInnerConfig(const Data &encryptedInnerConfig) { + auto inner = OuterCipher::decrypt(static_cast(encryptedInnerConfig.data()), encryptedInnerConfig.size(), _outerKey); if(inner == none) { return none; } diff --git a/src/config/crypto/CryConfigEncryptor.h b/src/config/crypto/CryConfigEncryptor.h index 23fc46ea..d81a03be 100644 --- a/src/config/crypto/CryConfigEncryptor.h +++ b/src/config/crypto/CryConfigEncryptor.h @@ -5,16 +5,14 @@ #include #include #include -#include "InnerEncryptor.h" +#include "inner/InnerEncryptor.h" #include #include namespace cryfs { //TODO Test //TODO Test that encrypted config data always has the same size, no matter how big the plaintext config data - //TODO Don't only encrypt with the main cipher, but also use user specified cipher. //TODO Use own exception for cpputils::Serializer/cpputils::Deserializer errors and only catch them - //TODO To get rid of many size fields, introduce Serializer::writeNullTerminatedString() and Serializer::writeUnterminatedData() (the latter one just writes until the end) class CryConfigEncryptor { public: using OuterCipher = cpputils::AES256_GCM; @@ -23,21 +21,14 @@ namespace cryfs { CryConfigEncryptor(cpputils::unique_ref innerEncryptor, OuterCipher::EncryptionKey outerKey, cpputils::DerivedKeyConfig keyConfig); cpputils::Data encrypt(const cpputils::Data &plaintext); - boost::optional decrypt(const cpputils::Data &plaintext); - - static void checkHeader(cpputils::Deserializer *deserializer); - static void writeHeader(cpputils::Serializer *serializer); + boost::optional decrypt(const cpputils::Data &data); private: - void _ignoreKey(cpputils::Deserializer *deserializer); - boost::optional _loadAndDecryptConfigData(cpputils::Deserializer *deserializer); - cpputils::Data _serialize(const cpputils::Data &ciphertext); + boost::optional _decryptInnerConfig(const cpputils::Data &encryptedInnerConfig); cpputils::unique_ref _innerEncryptor; OuterCipher::EncryptionKey _outerKey; cpputils::DerivedKeyConfig _keyConfig; - - static const std::string HEADER; }; } diff --git a/src/config/crypto/CryConfigEncryptorFactory.cpp b/src/config/crypto/CryConfigEncryptorFactory.cpp index eeee13cc..0b544890 100644 --- a/src/config/crypto/CryConfigEncryptorFactory.cpp +++ b/src/config/crypto/CryConfigEncryptorFactory.cpp @@ -1,5 +1,6 @@ #include "CryConfigEncryptorFactory.h" #include +#include "OuterConfig.h" using namespace cpputils::logging; using boost::optional; @@ -7,30 +8,40 @@ using boost::none; using cpputils::unique_ref; using cpputils::make_unique_ref; using cpputils::Data; -using cpputils::Deserializer; +using cpputils::DerivedKey; +using cpputils::DerivedKeyConfig; +using cpputils::SCrypt; using std::string; namespace cryfs { constexpr size_t CryConfigEncryptorFactory::OuterKeySize; + constexpr size_t CryConfigEncryptorFactory::MaxTotalKeySize; - optional> CryConfigEncryptorFactory::loadKey(const Data &ciphertext, + optional> CryConfigEncryptorFactory::loadKey(const Data &data, const string &password) { using Cipher = cpputils::AES256_GCM; //TODO Allow other ciphers - Deserializer deserializer(&ciphertext); - try { - CryConfigEncryptor::checkHeader(&deserializer); - auto derivedKey = _loadKey(&deserializer, password); - auto outerKey = derivedKey.key().take(); - auto innerKey = derivedKey.key().drop(); - return make_unique_ref( - make_unique_ref>(innerKey), - outerKey, - derivedKey.moveOutConfig() - ); - } catch (const std::exception &e) { - LOG(ERROR) << "Error loading configuration: " << e.what(); - return none; // This can be caused by invalid loaded data and is not necessarily a programming logic error. Don't throw exception. + + auto outerConfig = OuterConfig::deserialize(data); + if (outerConfig == none) { + return none; } + auto derivedKey = _deriveKey(outerConfig->keyConfig, password); + auto outerKey = derivedKey.key().take(); + auto innerKey = derivedKey.key().drop().take(); + return make_unique_ref( + make_unique_ref>(innerKey), + outerKey, + derivedKey.moveOutConfig() + ); + } + + cpputils::DerivedKey + CryConfigEncryptorFactory::_deriveKey(const DerivedKeyConfig &keyConfig, const std::string &password) { + //TODO It would be better, not to generate a MaxTotalKeySize key here, but to generate the outer key first, and then + // (once we know which inner cipher was used) only generate as many key bytes as we need for the inner cipher. + // This would need a change in the scrypt interface though, because right now we can't continue past key computations. + auto key = SCrypt().generateKeyFromConfig(password, keyConfig); + return DerivedKey(keyConfig, std::move(key)); } } diff --git a/src/config/crypto/CryConfigEncryptorFactory.h b/src/config/crypto/CryConfigEncryptorFactory.h index b1d7135c..46f0b305 100644 --- a/src/config/crypto/CryConfigEncryptorFactory.h +++ b/src/config/crypto/CryConfigEncryptorFactory.h @@ -2,10 +2,11 @@ #ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTORFACTORY_H #define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTORFACTORY_H -#include "ConcreteInnerEncryptor.h" +#include "inner/ConcreteInnerEncryptor.h" #include "CryConfigEncryptor.h" #include #include +#include "../CryCipher.h" namespace cryfs { //TODO Test @@ -14,16 +15,15 @@ namespace cryfs { template static cpputils::unique_ref deriveKey(const std::string &password, const cpputils::SCryptSettings &scryptSettings); - static boost::optional > loadKey(const cpputils::Data &ciphertext, - const std::string &password); + static boost::optional> loadKey(const cpputils::Data &ciphertext, + const std::string &password); private: static constexpr size_t OuterKeySize = CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH; template static constexpr size_t TotalKeySize(); + static constexpr size_t MaxTotalKeySize = OuterKeySize + CryCiphers::MAX_KEY_SIZE; - template - static cpputils::DerivedKey - _loadKey(cpputils::Deserializer *deserializer, const std::string &password); + static cpputils::DerivedKey _deriveKey(const cpputils::DerivedKeyConfig &keyConfig, const std::string &password); }; template constexpr size_t CryConfigEncryptorFactory::TotalKeySize() { @@ -32,6 +32,7 @@ namespace cryfs { template cpputils::unique_ref CryConfigEncryptorFactory::deriveKey(const std::string &password, const cpputils::SCryptSettings &scryptSettings) { + //TODO Use _deriveKey(keyConfig, password) instead and get rid of cpputils::SCryptSettings class in favor of cpputils::DerivedKeyConfig auto derivedKey = cpputils::SCrypt().generateKey()>(password, scryptSettings); auto outerKey = derivedKey.key().template take(); auto innerKey = derivedKey.key().template drop(); @@ -41,17 +42,6 @@ namespace cryfs { derivedKey.moveOutConfig() ); } - - template - cpputils::DerivedKey - CryConfigEncryptorFactory::_loadKey(cpputils::Deserializer *deserializer, const std::string &password) { - auto keyConfig = cpputils::DerivedKeyConfig::load(deserializer); - //TODO This is only kept here to recognize when this is run in tests. After tests are faster, replace this with something in main(), saying something like "Loading configuration file..." - std::cout << "Deriving secure key for config file..." << std::flush; - auto key = cpputils::SCrypt().generateKeyFromConfig()>(password, keyConfig); - std::cout << "done" << std::endl; - return cpputils::DerivedKey()>(std::move(keyConfig), std::move(key)); - } } #endif diff --git a/src/config/crypto/InnerEncryptor.cpp b/src/config/crypto/InnerEncryptor.cpp deleted file mode 100644 index ec8f3b75..00000000 --- a/src/config/crypto/InnerEncryptor.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "InnerEncryptor.h" - -using std::string; -using cpputils::Deserializer; -using cpputils::Serializer; - -namespace cryfs { - const string InnerEncryptor::HEADER = "cryfs.config.inner;0"; - - void InnerEncryptor::_checkHeader(Deserializer *deserializer) { - string header = deserializer->readString(); - if (header != HEADER) { - throw std::runtime_error("Invalid header"); - } - } - - void InnerEncryptor::_writeHeader(Serializer *serializer) { - serializer->writeString(HEADER); - } - -} \ No newline at end of file diff --git a/src/config/crypto/OuterConfig.cpp b/src/config/crypto/OuterConfig.cpp new file mode 100644 index 00000000..2bb5b392 --- /dev/null +++ b/src/config/crypto/OuterConfig.cpp @@ -0,0 +1,55 @@ +#include "OuterConfig.h" + +using std::string; +using std::exception; +using cpputils::Data; +using cpputils::Serializer; +using cpputils::Deserializer; +using cpputils::DerivedKeyConfig; +using boost::optional; +using boost::none; +using namespace cpputils::logging; + +namespace cryfs { + const string OuterConfig::HEADER = "cryfs.config;0;scrypt"; + + void OuterConfig::_checkHeader(Deserializer *deserializer) { + string header = deserializer->readString(); + if (header != HEADER) { + throw std::runtime_error("Invalid header"); + } + } + + void OuterConfig::_writeHeader(Serializer *serializer) { + serializer->writeString(HEADER); + } + + Data OuterConfig::serialize() { + try { + Serializer serializer(Serializer::StringSize(HEADER) + + keyConfig.serializedSize() + + encryptedInnerConfig.size()); + _writeHeader(&serializer); + keyConfig.serialize(&serializer); + serializer.writeTailData(encryptedInnerConfig); + return serializer.finished(); + } catch (const exception &e) { + LOG(ERROR) << "Error serializing CryConfigEncryptor: " << e.what(); + throw; // This is a programming logic error. Pass through exception. + } + } + + optional OuterConfig::deserialize(const Data &data) { + Deserializer deserializer(&data); + try { + _checkHeader(&deserializer); + auto keyConfig = DerivedKeyConfig::deserialize(&deserializer); + auto encryptedInnerConfig = deserializer.readTailData(); + deserializer.finished(); + return OuterConfig {std::move(keyConfig), std::move(encryptedInnerConfig)}; + } catch (const exception &e) { + LOG(ERROR) << "Error deserializing outer configuration: " << e.what(); + return none; // This can be caused by invalid input data and does not have to be a programming error. Don't throw exception. + } + } +} diff --git a/src/config/crypto/OuterConfig.h b/src/config/crypto/OuterConfig.h new file mode 100644 index 00000000..f6f4240e --- /dev/null +++ b/src/config/crypto/OuterConfig.h @@ -0,0 +1,26 @@ +#pragma once +#ifndef CRYFS_OUTERCONFIG_H +#define CRYFS_OUTERCONFIG_H + +#include +#include +#include +#include + +namespace cryfs { + struct OuterConfig { + cpputils::DerivedKeyConfig keyConfig; + cpputils::Data encryptedInnerConfig; + + cpputils::Data serialize(); + static boost::optional deserialize(const cpputils::Data &data); + + private: + static void _checkHeader(cpputils::Deserializer *deserializer); + static void _writeHeader(cpputils::Serializer *serializer); + + static const std::string HEADER; + }; +} + +#endif diff --git a/src/config/crypto/ConcreteInnerEncryptor.cpp b/src/config/crypto/inner/ConcreteInnerEncryptor.cpp similarity index 100% rename from src/config/crypto/ConcreteInnerEncryptor.cpp rename to src/config/crypto/inner/ConcreteInnerEncryptor.cpp diff --git a/src/config/crypto/inner/ConcreteInnerEncryptor.h b/src/config/crypto/inner/ConcreteInnerEncryptor.h new file mode 100644 index 00000000..4bb7d884 --- /dev/null +++ b/src/config/crypto/inner/ConcreteInnerEncryptor.h @@ -0,0 +1,61 @@ +#pragma once +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_CONCRETECRYCONFIGENCRYPTOR_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_CONCRETECRYCONFIGENCRYPTOR_H + +#include +#include + +#include "InnerEncryptor.h" +#include "InnerConfig.h" + +namespace cryfs { + //TODO Test + template + class ConcreteInnerEncryptor: public InnerEncryptor { + public: + static constexpr size_t CONFIG_SIZE = 512; // Inner config data is grown to this size before encryption to hide its actual size + + ConcreteInnerEncryptor(typename Cipher::EncryptionKey key); + + cpputils::Data encrypt(const cpputils::Data &plaintext) const override; + boost::optional decrypt(const cpputils::Data &ciphertext) const override; + private: + + typename Cipher::EncryptionKey _key; + }; + + template + ConcreteInnerEncryptor::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key) + : _key(std::move(key)) { + } + + template + boost::optional ConcreteInnerEncryptor::decrypt(const cpputils::Data &ciphertext) const { + auto innerConfig = InnerConfig::deserialize(ciphertext); + if (innerConfig == boost::none) { + return boost::none; + } + if (innerConfig->cipherName != Cipher::NAME) { + cpputils::logging::LOG(cpputils::logging::ERROR) << "Wrong inner cipher used"; + return boost::none; + } + auto decrypted = Cipher::decrypt(static_cast(innerConfig->encryptedConfig.data()), innerConfig->encryptedConfig.size(), _key); + if (decrypted == boost::none) { + return boost::none; + } + auto configData = cpputils::RandomPadding::remove(*decrypted); + if (configData == boost::none) { + return boost::none; + } + return std::move(*configData); + } + + template + cpputils::Data ConcreteInnerEncryptor::encrypt(const cpputils::Data &plaintext) const { + auto paddedPlaintext = cpputils::RandomPadding::add(plaintext, CONFIG_SIZE); + auto encrypted = Cipher::encrypt(static_cast(paddedPlaintext.data()), paddedPlaintext.size(), _key); + return InnerConfig{Cipher::NAME, std::move(encrypted)}.serialize(); + } +} + +#endif diff --git a/src/config/crypto/inner/InnerConfig.cpp b/src/config/crypto/inner/InnerConfig.cpp new file mode 100644 index 00000000..fa595f9e --- /dev/null +++ b/src/config/crypto/inner/InnerConfig.cpp @@ -0,0 +1,55 @@ +#include "InnerConfig.h" +#include + +using std::string; +using std::exception; +using cpputils::Deserializer; +using cpputils::Serializer; +using cpputils::Data; +using boost::optional; +using boost::none; +using namespace cpputils::logging; + +namespace cryfs { + const string InnerConfig::HEADER = "cryfs.config.inner;0"; + + Data InnerConfig::serialize() { + try { + Serializer serializer(Serializer::StringSize(HEADER) + + Serializer::StringSize(cipherName) + + encryptedConfig.size()); + serializer.writeString(HEADER); + serializer.writeString(cipherName); + serializer.writeTailData(encryptedConfig); + return serializer.finished(); + } catch (const exception &e) { + LOG(ERROR) << "Error serializing inner configuration: " << e.what(); + throw; // This is a programming logic error, pass through exception. + } + } + + optional InnerConfig::deserialize(const Data &data) { + Deserializer deserializer(&data); + try { + _checkHeader(&deserializer); + string cipherName = deserializer.readString(); + auto result = deserializer.readTailData(); + deserializer.finished(); + return InnerConfig {cipherName, std::move(result)}; + } catch (const exception &e) { + LOG(ERROR) << "Error deserializing inner configuration: " << e.what(); + return none; // This can be caused by invalid input data and does not have to be a programming error. Don't throw exception. + } + } + + void InnerConfig::_checkHeader(Deserializer *deserializer) { + string header = deserializer->readString(); + if (header != HEADER) { + throw std::runtime_error("Invalid header"); + } + } + + void InnerConfig::_writeHeader(Serializer *serializer) { + serializer->writeString(HEADER); + } +} diff --git a/src/config/crypto/inner/InnerConfig.h b/src/config/crypto/inner/InnerConfig.h new file mode 100644 index 00000000..e5681a13 --- /dev/null +++ b/src/config/crypto/inner/InnerConfig.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERCONFIG_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERCONFIG_H + +#include +#include +#include + +namespace cryfs { + struct InnerConfig { + std::string cipherName; + cpputils::Data encryptedConfig; + + cpputils::Data serialize(); + static boost::optional deserialize(const cpputils::Data &data); + + private: + static void _checkHeader(cpputils::Deserializer *deserializer); + static void _writeHeader(cpputils::Serializer *serializer); + + static const std::string HEADER; + }; +} + +#endif diff --git a/src/config/crypto/inner/InnerEncryptor.cpp b/src/config/crypto/inner/InnerEncryptor.cpp new file mode 100644 index 00000000..8e670a79 --- /dev/null +++ b/src/config/crypto/inner/InnerEncryptor.cpp @@ -0,0 +1 @@ +#include "InnerEncryptor.h" diff --git a/src/config/crypto/InnerEncryptor.h b/src/config/crypto/inner/InnerEncryptor.h similarity index 60% rename from src/config/crypto/InnerEncryptor.h rename to src/config/crypto/inner/InnerEncryptor.h index 67f541c4..04d584e8 100644 --- a/src/config/crypto/InnerEncryptor.h +++ b/src/config/crypto/inner/InnerEncryptor.h @@ -1,6 +1,6 @@ #pragma once -#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNERENCRYPTOR_H -#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNERENCRYPTOR_H +#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERENCRYPTOR_H +#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERENCRYPTOR_H #include #include @@ -13,13 +13,6 @@ namespace cryfs { public: virtual cpputils::Data encrypt(const cpputils::Data &plaintext) const = 0; virtual boost::optional decrypt(const cpputils::Data &plaintext) const = 0; - - protected: - static void _checkHeader(cpputils::Deserializer *deserializer); - static void _writeHeader(cpputils::Serializer *serializer); - - private: - static const std::string HEADER; }; }