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 cryfs;
|
||||||
using namespace cpputils;
|
using namespace cpputils;
|
||||||
|
|
||||||
|
constexpr size_t CryCiphers::MAX_KEY_SIZE;
|
||||||
|
|
||||||
template<typename Cipher>
|
template<typename Cipher>
|
||||||
class CryCipherInstance: public CryCipher {
|
class CryCipherInstance: public CryCipher {
|
||||||
public:
|
public:
|
||||||
BOOST_CONCEPT_ASSERT((CipherConcept<Cipher>));
|
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) {
|
CryCipherInstance(const optional<string> warning = none): _warning(warning) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,10 @@ class CryCiphers {
|
|||||||
public:
|
public:
|
||||||
static std::vector<std::string> supportedCipherNames();
|
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);
|
static const CryCipher& find(const std::string &cipherName);
|
||||||
|
|
||||||
private:
|
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 "CryConfigEncryptor.h"
|
||||||
#include <messmer/cpp-utils/crypto/RandomPadding.h>
|
#include <messmer/cpp-utils/crypto/RandomPadding.h>
|
||||||
|
#include "OuterConfig.h"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using cpputils::Deserializer;
|
|
||||||
using cpputils::Serializer;
|
|
||||||
using cpputils::unique_ref;
|
using cpputils::unique_ref;
|
||||||
using cpputils::Data;
|
using cpputils::Data;
|
||||||
using cpputils::RandomPadding;
|
using cpputils::RandomPadding;
|
||||||
@ -13,66 +12,27 @@ using boost::none;
|
|||||||
using namespace cpputils::logging;
|
using namespace cpputils::logging;
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
const string CryConfigEncryptor::HEADER = "cryfs.config;0;scrypt";
|
|
||||||
|
|
||||||
CryConfigEncryptor::CryConfigEncryptor(unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, DerivedKeyConfig keyConfig)
|
CryConfigEncryptor::CryConfigEncryptor(unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, DerivedKeyConfig keyConfig)
|
||||||
: _innerEncryptor(std::move(innerEncryptor)), _outerKey(std::move(outerKey)), _keyConfig(std::move(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) {
|
Data CryConfigEncryptor::encrypt(const Data &plaintext) {
|
||||||
auto inner = _innerEncryptor->encrypt(plaintext);
|
auto inner = _innerEncryptor->encrypt(plaintext);
|
||||||
auto padded = RandomPadding::add(inner, CONFIG_SIZE);
|
auto padded = RandomPadding::add(inner, CONFIG_SIZE);
|
||||||
auto ciphertext = OuterCipher::encrypt(static_cast<const uint8_t*>(padded.data()), padded.size(), _outerKey);
|
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) {
|
optional<Data> CryConfigEncryptor::decrypt(const Data &data) {
|
||||||
try {
|
auto outerConfig = OuterConfig::deserialize(data);
|
||||||
Serializer serializer(Serializer::StringSize(HEADER)
|
if (outerConfig == none) {
|
||||||
+ _keyConfig.serializedSize()
|
return none;
|
||||||
+ 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.
|
|
||||||
}
|
}
|
||||||
|
return _decryptInnerConfig(outerConfig->encryptedInnerConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<Data> CryConfigEncryptor::decrypt(const Data &plaintext) {
|
optional<Data> CryConfigEncryptor::_decryptInnerConfig(const Data &encryptedInnerConfig) {
|
||||||
Deserializer deserializer(&plaintext);
|
auto inner = OuterCipher::decrypt(static_cast<const uint8_t*>(encryptedInnerConfig.data()), encryptedInnerConfig.size(), _outerKey);
|
||||||
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);
|
|
||||||
if(inner == none) {
|
if(inner == none) {
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,14 @@
|
|||||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||||
#include <messmer/cpp-utils/data/Deserializer.h>
|
#include <messmer/cpp-utils/data/Deserializer.h>
|
||||||
#include <messmer/cpp-utils/data/Serializer.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/kdf/DerivedKeyConfig.h>
|
||||||
#include <messmer/cpp-utils/crypto/symmetric/ciphers.h>
|
#include <messmer/cpp-utils/crypto/symmetric/ciphers.h>
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
//TODO Test
|
//TODO Test
|
||||||
//TODO Test that encrypted config data always has the same size, no matter how big the plaintext config data
|
//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 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 {
|
class CryConfigEncryptor {
|
||||||
public:
|
public:
|
||||||
using OuterCipher = cpputils::AES256_GCM;
|
using OuterCipher = cpputils::AES256_GCM;
|
||||||
@ -23,21 +21,14 @@ namespace cryfs {
|
|||||||
CryConfigEncryptor(cpputils::unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, cpputils::DerivedKeyConfig keyConfig);
|
CryConfigEncryptor(cpputils::unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, cpputils::DerivedKeyConfig keyConfig);
|
||||||
|
|
||||||
cpputils::Data encrypt(const cpputils::Data &plaintext);
|
cpputils::Data encrypt(const cpputils::Data &plaintext);
|
||||||
boost::optional <cpputils::Data> decrypt(const cpputils::Data &plaintext);
|
boost::optional <cpputils::Data> decrypt(const cpputils::Data &data);
|
||||||
|
|
||||||
static void checkHeader(cpputils::Deserializer *deserializer);
|
|
||||||
static void writeHeader(cpputils::Serializer *serializer);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _ignoreKey(cpputils::Deserializer *deserializer);
|
boost::optional<cpputils::Data> _decryptInnerConfig(const cpputils::Data &encryptedInnerConfig);
|
||||||
boost::optional<cpputils::Data> _loadAndDecryptConfigData(cpputils::Deserializer *deserializer);
|
|
||||||
cpputils::Data _serialize(const cpputils::Data &ciphertext);
|
|
||||||
|
|
||||||
cpputils::unique_ref<InnerEncryptor> _innerEncryptor;
|
cpputils::unique_ref<InnerEncryptor> _innerEncryptor;
|
||||||
OuterCipher::EncryptionKey _outerKey;
|
OuterCipher::EncryptionKey _outerKey;
|
||||||
cpputils::DerivedKeyConfig _keyConfig;
|
cpputils::DerivedKeyConfig _keyConfig;
|
||||||
|
|
||||||
static const std::string HEADER;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "CryConfigEncryptorFactory.h"
|
#include "CryConfigEncryptorFactory.h"
|
||||||
#include <messmer/cpp-utils/crypto/symmetric/ciphers.h>
|
#include <messmer/cpp-utils/crypto/symmetric/ciphers.h>
|
||||||
|
#include "OuterConfig.h"
|
||||||
|
|
||||||
using namespace cpputils::logging;
|
using namespace cpputils::logging;
|
||||||
using boost::optional;
|
using boost::optional;
|
||||||
@ -7,30 +8,40 @@ using boost::none;
|
|||||||
using cpputils::unique_ref;
|
using cpputils::unique_ref;
|
||||||
using cpputils::make_unique_ref;
|
using cpputils::make_unique_ref;
|
||||||
using cpputils::Data;
|
using cpputils::Data;
|
||||||
using cpputils::Deserializer;
|
using cpputils::DerivedKey;
|
||||||
|
using cpputils::DerivedKeyConfig;
|
||||||
|
using cpputils::SCrypt;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
|
|
||||||
constexpr size_t CryConfigEncryptorFactory::OuterKeySize;
|
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) {
|
const string &password) {
|
||||||
using Cipher = cpputils::AES256_GCM; //TODO Allow other ciphers
|
using Cipher = cpputils::AES256_GCM; //TODO Allow other ciphers
|
||||||
Deserializer deserializer(&ciphertext);
|
|
||||||
try {
|
auto outerConfig = OuterConfig::deserialize(data);
|
||||||
CryConfigEncryptor::checkHeader(&deserializer);
|
if (outerConfig == none) {
|
||||||
auto derivedKey = _loadKey<Cipher>(&deserializer, password);
|
return none;
|
||||||
|
}
|
||||||
|
auto derivedKey = _deriveKey(outerConfig->keyConfig, password);
|
||||||
auto outerKey = derivedKey.key().take<OuterKeySize>();
|
auto outerKey = derivedKey.key().take<OuterKeySize>();
|
||||||
auto innerKey = derivedKey.key().drop<OuterKeySize>();
|
auto innerKey = derivedKey.key().drop<OuterKeySize>().take<Cipher::EncryptionKey::BINARY_LENGTH>();
|
||||||
return make_unique_ref<CryConfigEncryptor>(
|
return make_unique_ref<CryConfigEncryptor>(
|
||||||
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
|
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
|
||||||
outerKey,
|
outerKey,
|
||||||
derivedKey.moveOutConfig()
|
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.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTORFACTORY_H
|
||||||
#define 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 "CryConfigEncryptor.h"
|
||||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||||
#include <messmer/cpp-utils/crypto/kdf/Scrypt.h>
|
#include <messmer/cpp-utils/crypto/kdf/Scrypt.h>
|
||||||
|
#include "../CryCipher.h"
|
||||||
|
|
||||||
namespace cryfs {
|
namespace cryfs {
|
||||||
//TODO Test
|
//TODO Test
|
||||||
@ -14,16 +15,15 @@ namespace cryfs {
|
|||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
static cpputils::unique_ref<CryConfigEncryptor> deriveKey(const std::string &password, const cpputils::SCryptSettings &scryptSettings);
|
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,
|
static boost::optional<cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext,
|
||||||
const std::string &password);
|
const std::string &password);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t OuterKeySize = CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH;
|
static constexpr size_t OuterKeySize = CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH;
|
||||||
template<class Cipher> static constexpr size_t TotalKeySize();
|
template<class Cipher> static constexpr size_t TotalKeySize();
|
||||||
|
static constexpr size_t MaxTotalKeySize = OuterKeySize + CryCiphers::MAX_KEY_SIZE;
|
||||||
|
|
||||||
template<class Cipher>
|
static cpputils::DerivedKey<MaxTotalKeySize> _deriveKey(const cpputils::DerivedKeyConfig &keyConfig, const std::string &password);
|
||||||
static cpputils::DerivedKey<CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH + Cipher::EncryptionKey::BINARY_LENGTH>
|
|
||||||
_loadKey(cpputils::Deserializer *deserializer, const std::string &password);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Cipher> constexpr size_t CryConfigEncryptorFactory::TotalKeySize() {
|
template<class Cipher> constexpr size_t CryConfigEncryptorFactory::TotalKeySize() {
|
||||||
@ -32,6 +32,7 @@ namespace cryfs {
|
|||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptorFactory::deriveKey(const std::string &password, const cpputils::SCryptSettings &scryptSettings) {
|
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 derivedKey = cpputils::SCrypt().generateKey<TotalKeySize<Cipher>()>(password, scryptSettings);
|
||||||
auto outerKey = derivedKey.key().template take<OuterKeySize>();
|
auto outerKey = derivedKey.key().template take<OuterKeySize>();
|
||||||
auto innerKey = derivedKey.key().template drop<OuterKeySize>();
|
auto innerKey = derivedKey.key().template drop<OuterKeySize>();
|
||||||
@ -41,17 +42,6 @@ namespace cryfs {
|
|||||||
derivedKey.moveOutConfig()
|
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
|
#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
|
#pragma once
|
||||||
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNERENCRYPTOR_H
|
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERENCRYPTOR_H
|
||||||
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNERENCRYPTOR_H
|
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_INNER_INNERENCRYPTOR_H
|
||||||
|
|
||||||
#include <messmer/cpp-utils/data/Data.h>
|
#include <messmer/cpp-utils/data/Data.h>
|
||||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||||
@ -13,13 +13,6 @@ namespace cryfs {
|
|||||||
public:
|
public:
|
||||||
virtual cpputils::Data encrypt(const cpputils::Data &plaintext) const = 0;
|
virtual cpputils::Data encrypt(const cpputils::Data &plaintext) const = 0;
|
||||||
virtual boost::optional<cpputils::Data> decrypt(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…
x
Reference in New Issue
Block a user