Refactor (de)serializing config files
This commit is contained in:
parent
4cedaa5bf4
commit
252a666a37
@ -17,11 +17,15 @@ using blockstore::encrypted::EncryptedBlockStore;
|
||||
using namespace cryfs;
|
||||
using namespace cpputils;
|
||||
|
||||
constexpr size_t CryCiphers::MAX_KEY_SIZE;
|
||||
|
||||
template<typename Cipher>
|
||||
class CryCipherInstance: public CryCipher {
|
||||
public:
|
||||
BOOST_CONCEPT_ASSERT((CipherConcept<Cipher>));
|
||||
|
||||
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<string> warning = none): _warning(warning) {
|
||||
}
|
||||
|
||||
@ -86,4 +90,4 @@ vector<string> CryCiphers::supportedCipherNames() {
|
||||
result.push_back(cipher->cipherName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ class CryCiphers {
|
||||
public:
|
||||
static std::vector<std::string> 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:
|
||||
|
@ -1,95 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H
|
||||
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H
|
||||
|
||||
#include <messmer/cpp-utils/data/Serializer.h>
|
||||
#include <messmer/cpp-utils/data/Deserializer.h>
|
||||
#include "InnerEncryptor.h"
|
||||
#include <messmer/cpp-utils/crypto/RandomPadding.h>
|
||||
#include <messmer/cpp-utils/crypto/kdf/DerivedKey.h>
|
||||
|
||||
namespace cryfs {
|
||||
//TODO Test
|
||||
template<class Cipher>
|
||||
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<cpputils::Data> decrypt(const cpputils::Data &ciphertext) const override;
|
||||
private:
|
||||
|
||||
cpputils::Data _serialize(const cpputils::Data &data) const;
|
||||
boost::optional<cpputils::Data> _deserialize(const cpputils::Data &data) const;
|
||||
|
||||
typename Cipher::EncryptionKey _key;
|
||||
};
|
||||
|
||||
template<class Cipher>
|
||||
ConcreteInnerEncryptor<Cipher>::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key)
|
||||
: _key(std::move(key)) {
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::decrypt(const cpputils::Data &ciphertext) const {
|
||||
auto data = _deserialize(ciphertext);
|
||||
if (data == boost::none) {
|
||||
return boost::none;
|
||||
}
|
||||
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(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<class Cipher>
|
||||
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::_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<class Cipher>
|
||||
cpputils::Data ConcreteInnerEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) const {
|
||||
auto paddedPlaintext = cpputils::RandomPadding::add(plaintext, CONFIG_SIZE);
|
||||
auto encrypted = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), _key);
|
||||
return _serialize(encrypted);
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data ConcreteInnerEncryptor<Cipher>::_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
|
@ -1,9 +1,8 @@
|
||||
#include "CryConfigEncryptor.h"
|
||||
#include <messmer/cpp-utils/crypto/RandomPadding.h>
|
||||
#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> 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<const uint8_t*>(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<Data> CryConfigEncryptor::decrypt(const Data &data) {
|
||||
auto outerConfig = OuterConfig::deserialize(data);
|
||||
if (outerConfig == none) {
|
||||
return none;
|
||||
}
|
||||
return _decryptInnerConfig(outerConfig->encryptedInnerConfig);
|
||||
}
|
||||
|
||||
optional<Data> 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<Data> CryConfigEncryptor::_loadAndDecryptConfigData(Deserializer *deserializer) {
|
||||
auto ciphertext = deserializer->readTailData();
|
||||
auto inner = OuterCipher::decrypt(static_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(), _outerKey);
|
||||
optional<Data> CryConfigEncryptor::_decryptInnerConfig(const Data &encryptedInnerConfig) {
|
||||
auto inner = OuterCipher::decrypt(static_cast<const uint8_t*>(encryptedInnerConfig.data()), encryptedInnerConfig.size(), _outerKey);
|
||||
if(inner == none) {
|
||||
return none;
|
||||
}
|
||||
|
@ -5,16 +5,14 @@
|
||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||
#include <messmer/cpp-utils/data/Deserializer.h>
|
||||
#include <messmer/cpp-utils/data/Serializer.h>
|
||||
#include "InnerEncryptor.h"
|
||||
#include "inner/InnerEncryptor.h"
|
||||
#include <messmer/cpp-utils/crypto/kdf/DerivedKeyConfig.h>
|
||||
#include <messmer/cpp-utils/crypto/symmetric/ciphers.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 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> innerEncryptor, OuterCipher::EncryptionKey outerKey, cpputils::DerivedKeyConfig keyConfig);
|
||||
|
||||
cpputils::Data encrypt(const cpputils::Data &plaintext);
|
||||
boost::optional <cpputils::Data> decrypt(const cpputils::Data &plaintext);
|
||||
|
||||
static void checkHeader(cpputils::Deserializer *deserializer);
|
||||
static void writeHeader(cpputils::Serializer *serializer);
|
||||
boost::optional <cpputils::Data> decrypt(const cpputils::Data &data);
|
||||
|
||||
private:
|
||||
void _ignoreKey(cpputils::Deserializer *deserializer);
|
||||
boost::optional<cpputils::Data> _loadAndDecryptConfigData(cpputils::Deserializer *deserializer);
|
||||
cpputils::Data _serialize(const cpputils::Data &ciphertext);
|
||||
boost::optional<cpputils::Data> _decryptInnerConfig(const cpputils::Data &encryptedInnerConfig);
|
||||
|
||||
cpputils::unique_ref<InnerEncryptor> _innerEncryptor;
|
||||
OuterCipher::EncryptionKey _outerKey;
|
||||
cpputils::DerivedKeyConfig _keyConfig;
|
||||
|
||||
static const std::string HEADER;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "CryConfigEncryptorFactory.h"
|
||||
#include <messmer/cpp-utils/crypto/symmetric/ciphers.h>
|
||||
#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<unique_ref<CryConfigEncryptor>> CryConfigEncryptorFactory::loadKey(const Data &ciphertext,
|
||||
optional<unique_ref<CryConfigEncryptor>> 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<Cipher>(&deserializer, password);
|
||||
auto outerKey = derivedKey.key().take<OuterKeySize>();
|
||||
auto innerKey = derivedKey.key().drop<OuterKeySize>();
|
||||
return make_unique_ref<CryConfigEncryptor>(
|
||||
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(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<OuterKeySize>();
|
||||
auto innerKey = derivedKey.key().drop<OuterKeySize>().take<Cipher::EncryptionKey::BINARY_LENGTH>();
|
||||
return make_unique_ref<CryConfigEncryptor>(
|
||||
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
|
||||
outerKey,
|
||||
derivedKey.moveOutConfig()
|
||||
);
|
||||
}
|
||||
|
||||
cpputils::DerivedKey<CryConfigEncryptorFactory::MaxTotalKeySize>
|
||||
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<MaxTotalKeySize>(password, keyConfig);
|
||||
return DerivedKey<MaxTotalKeySize>(keyConfig, std::move(key));
|
||||
}
|
||||
}
|
||||
|
@ -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 <messmer/cpp-utils/pointer/unique_ref.h>
|
||||
#include <messmer/cpp-utils/crypto/kdf/Scrypt.h>
|
||||
#include "../CryCipher.h"
|
||||
|
||||
namespace cryfs {
|
||||
//TODO Test
|
||||
@ -14,16 +15,15 @@ namespace cryfs {
|
||||
template<class Cipher>
|
||||
static cpputils::unique_ref<CryConfigEncryptor> deriveKey(const std::string &password, const cpputils::SCryptSettings &scryptSettings);
|
||||
|
||||
static boost::optional <cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext,
|
||||
const std::string &password);
|
||||
static boost::optional<cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext,
|
||||
const std::string &password);
|
||||
|
||||
private:
|
||||
static constexpr size_t OuterKeySize = CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH;
|
||||
template<class Cipher> static constexpr size_t TotalKeySize();
|
||||
static constexpr size_t MaxTotalKeySize = OuterKeySize + CryCiphers::MAX_KEY_SIZE;
|
||||
|
||||
template<class Cipher>
|
||||
static cpputils::DerivedKey<CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH + Cipher::EncryptionKey::BINARY_LENGTH>
|
||||
_loadKey(cpputils::Deserializer *deserializer, const std::string &password);
|
||||
static cpputils::DerivedKey<MaxTotalKeySize> _deriveKey(const cpputils::DerivedKeyConfig &keyConfig, const std::string &password);
|
||||
};
|
||||
|
||||
template<class Cipher> constexpr size_t CryConfigEncryptorFactory::TotalKeySize() {
|
||||
@ -32,6 +32,7 @@ namespace cryfs {
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::unique_ref<CryConfigEncryptor> 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<TotalKeySize<Cipher>()>(password, scryptSettings);
|
||||
auto outerKey = derivedKey.key().template take<OuterKeySize>();
|
||||
auto innerKey = derivedKey.key().template drop<OuterKeySize>();
|
||||
@ -41,17 +42,6 @@ namespace cryfs {
|
||||
derivedKey.moveOutConfig()
|
||||
);
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::DerivedKey<CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH + Cipher::EncryptionKey::BINARY_LENGTH>
|
||||
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<TotalKeySize<Cipher>()>(password, keyConfig);
|
||||
std::cout << "done" << std::endl;
|
||||
return cpputils::DerivedKey<TotalKeySize<Cipher>()>(std::move(keyConfig), std::move(key));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
55
src/config/crypto/OuterConfig.cpp
Normal file
55
src/config/crypto/OuterConfig.cpp
Normal file
@ -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> 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.
|
||||
}
|
||||
}
|
||||
}
|
26
src/config/crypto/OuterConfig.h
Normal file
26
src/config/crypto/OuterConfig.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#ifndef CRYFS_OUTERCONFIG_H
|
||||
#define CRYFS_OUTERCONFIG_H
|
||||
|
||||
#include <messmer/cpp-utils/crypto/kdf/DerivedKeyConfig.h>
|
||||
#include <messmer/cpp-utils/data/Data.h>
|
||||
#include <messmer/cpp-utils/data/Serializer.h>
|
||||
#include <messmer/cpp-utils/data/Deserializer.h>
|
||||
|
||||
namespace cryfs {
|
||||
struct OuterConfig {
|
||||
cpputils::DerivedKeyConfig keyConfig;
|
||||
cpputils::Data encryptedInnerConfig;
|
||||
|
||||
cpputils::Data serialize();
|
||||
static boost::optional<OuterConfig> deserialize(const cpputils::Data &data);
|
||||
|
||||
private:
|
||||
static void _checkHeader(cpputils::Deserializer *deserializer);
|
||||
static void _writeHeader(cpputils::Serializer *serializer);
|
||||
|
||||
static const std::string HEADER;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
61
src/config/crypto/inner/ConcreteInnerEncryptor.h
Normal file
61
src/config/crypto/inner/ConcreteInnerEncryptor.h
Normal file
@ -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 <messmer/cpp-utils/crypto/RandomPadding.h>
|
||||
#include <messmer/cpp-utils/crypto/kdf/DerivedKey.h>
|
||||
|
||||
#include "InnerEncryptor.h"
|
||||
#include "InnerConfig.h"
|
||||
|
||||
namespace cryfs {
|
||||
//TODO Test
|
||||
template<class Cipher>
|
||||
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<cpputils::Data> decrypt(const cpputils::Data &ciphertext) const override;
|
||||
private:
|
||||
|
||||
typename Cipher::EncryptionKey _key;
|
||||
};
|
||||
|
||||
template<class Cipher>
|
||||
ConcreteInnerEncryptor<Cipher>::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key)
|
||||
: _key(std::move(key)) {
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::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<const uint8_t*>(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<class Cipher>
|
||||
cpputils::Data ConcreteInnerEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) const {
|
||||
auto paddedPlaintext = cpputils::RandomPadding::add(plaintext, CONFIG_SIZE);
|
||||
auto encrypted = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), _key);
|
||||
return InnerConfig{Cipher::NAME, std::move(encrypted)}.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
55
src/config/crypto/inner/InnerConfig.cpp
Normal file
55
src/config/crypto/inner/InnerConfig.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "InnerConfig.h"
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
|
||||
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> 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);
|
||||
}
|
||||
}
|
25
src/config/crypto/inner/InnerConfig.h
Normal file
25
src/config/crypto/inner/InnerConfig.h
Normal file
@ -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 <messmer/cpp-utils/data/Data.h>
|
||||
#include <messmer/cpp-utils/data/Serializer.h>
|
||||
#include <messmer/cpp-utils/data/Deserializer.h>
|
||||
|
||||
namespace cryfs {
|
||||
struct InnerConfig {
|
||||
std::string cipherName;
|
||||
cpputils::Data encryptedConfig;
|
||||
|
||||
cpputils::Data serialize();
|
||||
static boost::optional<InnerConfig> deserialize(const cpputils::Data &data);
|
||||
|
||||
private:
|
||||
static void _checkHeader(cpputils::Deserializer *deserializer);
|
||||
static void _writeHeader(cpputils::Serializer *serializer);
|
||||
|
||||
static const std::string HEADER;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
1
src/config/crypto/inner/InnerEncryptor.cpp
Normal file
1
src/config/crypto/inner/InnerEncryptor.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "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 <messmer/cpp-utils/data/Data.h>
|
||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||
@ -13,13 +13,6 @@ namespace cryfs {
|
||||
public:
|
||||
virtual cpputils::Data encrypt(const cpputils::Data &plaintext) const = 0;
|
||||
virtual boost::optional<cpputils::Data> 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;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user