Refactor CryConfigEncryptor: Store instance instead of static
This commit is contained in:
parent
a840bbba47
commit
fd184b45d2
|
@ -8,12 +8,10 @@ ADD_BII_TARGETS()
|
|||
|
||||
ACTIVATE_CPP14()
|
||||
|
||||
ADD_BOOST(program_options)
|
||||
ADD_BOOST(program_options chrono)
|
||||
|
||||
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
|
||||
|
||||
#SET_TARGET_PROPERTIES(${BII_test_main_TARGET} PROPERTIES LINK_FLAGS -rdynamic)
|
||||
|
||||
GIT_VERSION_INIT()
|
||||
|
||||
ENABLE_STYLE_WARNINGS()
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
#include "CryConfigEncryptor.h"
|
||||
|
||||
namespace cryfs {
|
||||
const std::string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
|
||||
}
|
|
@ -7,75 +7,77 @@
|
|||
#include <messmer/cpp-utils/data/Data.h>
|
||||
#include <messmer/cpp-utils/random/Random.h>
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
#include <messmer/cpp-utils/pointer/unique_ref.h>
|
||||
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include "crypto/Scrypt.h"
|
||||
#include "RandomPadding.h"
|
||||
#include <sstream>
|
||||
|
||||
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
|
||||
template<class Cipher>
|
||||
class CryConfigEncryptor {
|
||||
public:
|
||||
using ConfigEncryptionKey = DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH>;
|
||||
static constexpr size_t CONFIG_SIZE = 1024; // Config data is grown to this size before encryption to hide its actual size
|
||||
template<class Cipher> static cpputils::unique_ref<CryConfigEncryptor> deriveKey(const std::string &password);
|
||||
static boost::optional<cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext, const std::string &password);
|
||||
|
||||
static ConfigEncryptionKey deriveKey(const std::string &password);
|
||||
static boost::optional<std::pair<ConfigEncryptionKey, cpputils::Data>> decrypt(const cpputils::Data &ciphertext, const std::string &password);
|
||||
static cpputils::Data encrypt(const cpputils::Data &plaintext, const ConfigEncryptionKey &key);
|
||||
private:
|
||||
static std::pair<ConfigEncryptionKey, cpputils::Data> _decrypt(cpputils::Deserializer *deserializer, const std::string &password);
|
||||
virtual cpputils::Data encrypt(const cpputils::Data &plaintext) = 0;
|
||||
virtual boost::optional<cpputils::Data> decrypt(const cpputils::Data &plaintext) = 0;
|
||||
|
||||
protected:
|
||||
static void _checkHeader(cpputils::Deserializer *deserializer);
|
||||
static ConfigEncryptionKey _loadKey(cpputils::Deserializer *deserializer, const std::string &password);
|
||||
static cpputils::Data _loadAndDecryptConfigData(cpputils::Deserializer *deserializer, const typename Cipher::EncryptionKey &key);
|
||||
static cpputils::Data _serialize(const cpputils::Data &ciphertext, const ConfigEncryptionKey &key);
|
||||
//TODO Test that encrypted config data always has the same size, no matter how big the plaintext config data
|
||||
static cpputils::Data _addPadding(const cpputils::Data &data);
|
||||
static boost::optional<cpputils::Data> _removePadding(const cpputils::Data &data);
|
||||
|
||||
private:
|
||||
template<class Cipher> static DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> _loadKey(cpputils::Deserializer *deserializer, const std::string &password);
|
||||
|
||||
static const std::string HEADER;
|
||||
};
|
||||
|
||||
template<class Cipher> const std::string CryConfigEncryptor<Cipher>::HEADER = "cryfs.config;0.8.1;scrypt";
|
||||
template<class Cipher>
|
||||
class ConcreteCryConfigEncryptor: public CryConfigEncryptor {
|
||||
public:
|
||||
using ConfigEncryptionKey = DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH>;
|
||||
static constexpr size_t CONFIG_SIZE = 1024; // Config data is grown to this size before encryption to hide its actual size
|
||||
|
||||
ConcreteCryConfigEncryptor(ConfigEncryptionKey key);
|
||||
|
||||
cpputils::Data encrypt(const cpputils::Data &plaintext) override;
|
||||
boost::optional<cpputils::Data> decrypt(const cpputils::Data &ciphertext) override;
|
||||
private:
|
||||
void _ignoreKey(cpputils::Deserializer *deserializer);
|
||||
cpputils::Data _loadAndDecryptConfigData(cpputils::Deserializer *deserializer);
|
||||
cpputils::Data _serialize(const cpputils::Data &ciphertext);
|
||||
|
||||
ConfigEncryptionKey _key;
|
||||
};
|
||||
|
||||
template<class Cipher>
|
||||
typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey CryConfigEncryptor<Cipher>::deriveKey(const std::string &password) {
|
||||
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptor::deriveKey(const std::string &password) {
|
||||
//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 = SCrypt().generateKey<Cipher::EncryptionKey::BINARY_LENGTH>(password);
|
||||
std::cout << "done" << std::endl;
|
||||
return key;
|
||||
return cpputils::make_unique_ref<ConcreteCryConfigEncryptor<Cipher>>(std::move(key));
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
boost::optional<std::pair<typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey, cpputils::Data>>
|
||||
CryConfigEncryptor<Cipher>::decrypt(const cpputils::Data &data, const std::string &password) {
|
||||
cpputils::Deserializer deserializer(&data);
|
||||
inline boost::optional<cpputils::unique_ref<CryConfigEncryptor>> CryConfigEncryptor::loadKey(const cpputils::Data &ciphertext, const std::string &password) {
|
||||
cpputils::Deserializer deserializer(&ciphertext);
|
||||
try {
|
||||
auto result = _decrypt(&deserializer, password);
|
||||
deserializer.finished();
|
||||
return result;
|
||||
_checkHeader(&deserializer);
|
||||
auto key = _loadKey<blockstore::encrypted::AES256_GCM>(&deserializer, password); //TODO Allow other ciphers
|
||||
return boost::optional<cpputils::unique_ref<CryConfigEncryptor>>(cpputils::make_unique_ref<ConcreteCryConfigEncryptor<blockstore::encrypted::AES256_GCM>>(std::move(key))); //TODO Allow other ciphers
|
||||
} catch (const std::exception &e) {
|
||||
cpputils::logging::LOG(cpputils::logging::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.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
std::pair<typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey, cpputils::Data>
|
||||
CryConfigEncryptor<Cipher>::_decrypt(cpputils::Deserializer *deserializer, const std::string &password) {
|
||||
_checkHeader(deserializer);
|
||||
auto key = _loadKey(deserializer, password);
|
||||
auto configData = _loadAndDecryptConfigData(deserializer, key.key());
|
||||
|
||||
return std::make_pair(std::move(key), std::move(configData));
|
||||
};
|
||||
|
||||
template<class Cipher>
|
||||
void CryConfigEncryptor<Cipher>::_checkHeader(cpputils::Deserializer *deserializer) {
|
||||
inline void CryConfigEncryptor::_checkHeader(cpputils::Deserializer *deserializer) {
|
||||
std::string header = deserializer->readString();
|
||||
if (header != HEADER) {
|
||||
throw std::runtime_error("Invalid header");
|
||||
|
@ -83,23 +85,47 @@ namespace cryfs {
|
|||
}
|
||||
|
||||
template<class Cipher>
|
||||
typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey CryConfigEncryptor<Cipher>::_loadKey(cpputils::Deserializer *deserializer, const std::string &password) {
|
||||
DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> CryConfigEncryptor::_loadKey(cpputils::Deserializer *deserializer, const std::string &password) {
|
||||
auto keyConfig = 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 = SCrypt().generateKeyFromConfig<Cipher::EncryptionKey::BINARY_LENGTH>(password, keyConfig);
|
||||
std::cout << "done" << std::endl;
|
||||
return ConfigEncryptionKey(std::move(keyConfig), std::move(key));
|
||||
return DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH>(std::move(keyConfig), std::move(key));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Cipher>
|
||||
ConcreteCryConfigEncryptor<Cipher>::ConcreteCryConfigEncryptor(ConfigEncryptionKey key): _key(std::move(key)) {
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data CryConfigEncryptor<Cipher>::_loadAndDecryptConfigData(cpputils::Deserializer *deserializer, const typename Cipher::EncryptionKey &key) {
|
||||
boost::optional<cpputils::Data> ConcreteCryConfigEncryptor<Cipher>::decrypt(const cpputils::Data &data) {
|
||||
cpputils::Deserializer deserializer(&data);
|
||||
try {
|
||||
_checkHeader(&deserializer);
|
||||
_ignoreKey(&deserializer);
|
||||
return _loadAndDecryptConfigData(&deserializer);
|
||||
} catch (const std::exception &e) {
|
||||
cpputils::logging::LOG(cpputils::logging::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.
|
||||
}
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
void ConcreteCryConfigEncryptor<Cipher>::_ignoreKey(cpputils::Deserializer *deserializer) {
|
||||
DerivedKeyConfig::load(deserializer);
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data ConcreteCryConfigEncryptor<Cipher>::_loadAndDecryptConfigData(cpputils::Deserializer *deserializer) {
|
||||
auto ciphertext = deserializer->readData();
|
||||
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(), key);
|
||||
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(), _key.key());
|
||||
if (decrypted == boost::none) {
|
||||
throw std::runtime_error("Couldn't decrypt config file. Wrong password?");
|
||||
}
|
||||
auto configData = _removePadding(*decrypted);
|
||||
auto configData = RandomPadding::remove(*decrypted);
|
||||
if (configData == boost::none) {
|
||||
throw std::runtime_error("Couldn't decrypt config file because of wrong padding");
|
||||
}
|
||||
|
@ -107,20 +133,20 @@ namespace cryfs {
|
|||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data CryConfigEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext, const ConfigEncryptionKey &key) {
|
||||
auto paddedPlaintext = _addPadding(plaintext);
|
||||
auto ciphertext = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), key.key());
|
||||
return _serialize(ciphertext, key);
|
||||
cpputils::Data ConcreteCryConfigEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) {
|
||||
auto paddedPlaintext = RandomPadding::add(plaintext, CONFIG_SIZE);
|
||||
auto ciphertext = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), _key.key());
|
||||
return _serialize(ciphertext);
|
||||
}
|
||||
|
||||
template <class Cipher>
|
||||
cpputils::Data CryConfigEncryptor<Cipher>::_serialize(const cpputils::Data &ciphertext, const ConfigEncryptionKey &key) {
|
||||
cpputils::Data ConcreteCryConfigEncryptor<Cipher>::_serialize(const cpputils::Data &ciphertext) {
|
||||
try {
|
||||
cpputils::Serializer serializer(cpputils::Serializer::StringSize(HEADER)
|
||||
+ key.config().serializedSize()
|
||||
+ _key.config().serializedSize()
|
||||
+ cpputils::Serializer::DataSize(ciphertext));
|
||||
serializer.writeString(HEADER);
|
||||
key.config().serialize(&serializer);
|
||||
_key.config().serialize(&serializer);
|
||||
serializer.writeData(ciphertext);
|
||||
return serializer.finished();
|
||||
} catch (const std::exception &e) {
|
||||
|
@ -128,32 +154,6 @@ namespace cryfs {
|
|||
throw; // This is a programming logic error. Pass through exception.
|
||||
}
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data CryConfigEncryptor<Cipher>::_addPadding(const cpputils::Data &data) {
|
||||
uint32_t size = data.size();
|
||||
ASSERT(size < CONFIG_SIZE - sizeof(size), "Config data too large. We should increase CONFIG_SIZE.");
|
||||
cpputils::Data randomData = cpputils::Random::PseudoRandom().get(CONFIG_SIZE-sizeof(size)-size);
|
||||
ASSERT(sizeof(size) + size + randomData.size() == CONFIG_SIZE, "Calculated size of randomData incorrectly");
|
||||
cpputils::Data result(CONFIG_SIZE);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), &size, sizeof(size));
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size))), reinterpret_cast<const char*>(data.data()), size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size)+size)), reinterpret_cast<const char*>(randomData.data()), randomData.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
boost::optional<cpputils::Data> CryConfigEncryptor<Cipher>::_removePadding(const cpputils::Data &data) {
|
||||
uint32_t size;
|
||||
std::memcpy(&size, reinterpret_cast<const char*>(data.data()), sizeof(size));
|
||||
if(sizeof(size) + size >= data.size()) {
|
||||
cpputils::logging::LOG(cpputils::logging::ERROR) << "Config file is invalid: Invalid padding.";
|
||||
return boost::none;
|
||||
};
|
||||
cpputils::Data result(size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), reinterpret_cast<const char*>(data.dataOffset(sizeof(size))), size);
|
||||
return std::move(result);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,46 +15,51 @@ using std::ostringstream;
|
|||
using std::stringstream;
|
||||
using std::istream;
|
||||
using cpputils::Data;
|
||||
using cpputils::unique_ref;
|
||||
namespace bf = boost::filesystem;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
CryConfigFile::~CryConfigFile() {
|
||||
//We do not call save() here, because we do not want the config file to be re-encrypted on each filesystem run
|
||||
}
|
||||
|
||||
CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config, const string &password) {
|
||||
using ConfigCipher = blockstore::encrypted::AES256_GCM; // TODO Take cipher from config instead
|
||||
if (bf::exists(path)) {
|
||||
throw std::runtime_error("Config file exists already.");
|
||||
}
|
||||
auto configEncKey = Encryptor::deriveKey(password);
|
||||
auto result = CryConfigFile(path, std::move(config), std::move(configEncKey));
|
||||
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptor::deriveKey<ConfigCipher>(password));
|
||||
result.save();
|
||||
return result;
|
||||
}
|
||||
|
||||
CryConfigFile::~CryConfigFile() {
|
||||
//We do not call save() here, because we do not want the config file to be re-encrypted on each filesystem run
|
||||
}
|
||||
|
||||
optional<CryConfigFile> CryConfigFile::load(const bf::path &path, const string &password) {
|
||||
auto encryptedConfigData = Data::LoadFromFile(path);
|
||||
if (encryptedConfigData == none) {
|
||||
LOG(ERROR) << "Config file not found";
|
||||
return none;
|
||||
}
|
||||
auto decrypted = Encryptor::decrypt(*encryptedConfigData, password);
|
||||
auto encryptor = CryConfigEncryptor::loadKey(*encryptedConfigData, password);
|
||||
if (encryptor == none) {
|
||||
return none;
|
||||
}
|
||||
auto decrypted = (*encryptor)->decrypt(*encryptedConfigData);
|
||||
if (decrypted == none) {
|
||||
return none;
|
||||
}
|
||||
CryConfig config = CryConfig::load(decrypted->second);
|
||||
return CryConfigFile(path, std::move(config), std::move(decrypted->first));
|
||||
CryConfig config = CryConfig::load(*decrypted);
|
||||
return CryConfigFile(path, std::move(config), std::move(*encryptor));
|
||||
}
|
||||
|
||||
CryConfigFile::CryConfigFile(const bf::path &path, CryConfig config, ConfigEncryptionKey configEncKey)
|
||||
: _path (path), _config(std::move(config)), _configEncKey(std::move(configEncKey)) {
|
||||
CryConfigFile::CryConfigFile(const bf::path &path, CryConfig config, unique_ref<CryConfigEncryptor> encryptor)
|
||||
: _path (path), _config(std::move(config)), _encryptor(std::move(encryptor)) {
|
||||
}
|
||||
|
||||
void CryConfigFile::save() const {
|
||||
Data configData = _config.save();
|
||||
auto encrypted = Encryptor::encrypt(configData, _configEncKey);
|
||||
auto encrypted = _encryptor->encrypt(configData);
|
||||
encrypted.StoreToFile(_path);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
namespace cryfs {
|
||||
class CryConfigFile final {
|
||||
public:
|
||||
using ConfigCipher = blockstore::encrypted::AES256_GCM;
|
||||
using ConfigEncryptionKey = DerivedKey<ConfigCipher::EncryptionKey::BINARY_LENGTH>;
|
||||
|
||||
CryConfigFile(CryConfigFile &&rhs) = default;
|
||||
~CryConfigFile();
|
||||
|
||||
|
@ -24,16 +21,11 @@ namespace cryfs {
|
|||
CryConfig *config();
|
||||
|
||||
private:
|
||||
CryConfigFile(const boost::filesystem::path &path, CryConfig config, ConfigEncryptionKey configEncKey);
|
||||
|
||||
static ConfigEncryptionKey _deriveKey(const std::string &password);
|
||||
static std::string _decrypt(cpputils::Data content, const ConfigEncryptionKey &configEncKey);
|
||||
static cpputils::Data _encrypt(const std::string &content, const ConfigEncryptionKey &configEncKey);
|
||||
CryConfigFile(const boost::filesystem::path &path, CryConfig config, cpputils::unique_ref<CryConfigEncryptor> encryptor);
|
||||
|
||||
boost::filesystem::path _path;
|
||||
CryConfig _config;
|
||||
ConfigEncryptionKey _configEncKey;
|
||||
using Encryptor = CryConfigEncryptor<ConfigCipher>;
|
||||
cpputils::unique_ref<CryConfigEncryptor> _encryptor;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CryConfigFile);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "CryConfigFile.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <messmer/cpp-utils/random/Random.h>
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
using cpputils::unique_ref;
|
||||
|
@ -15,6 +16,7 @@ using boost::none;
|
|||
using std::vector;
|
||||
using std::string;
|
||||
using std::function;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
|
@ -22,7 +24,7 @@ CryConfigLoader::CryConfigLoader(unique_ref<Console> console, RandomGenerator &k
|
|||
: _creator(std::move(console), keyGenerator), _askPassword(askPassword) {
|
||||
}
|
||||
|
||||
CryConfigFile CryConfigLoader::loadOrCreate(const bf::path &filename) {
|
||||
optional<CryConfigFile> CryConfigLoader::loadOrCreate(const bf::path &filename) {
|
||||
if (bf::exists(filename)) {
|
||||
return _loadConfig(filename);
|
||||
} else {
|
||||
|
@ -30,12 +32,12 @@ CryConfigFile CryConfigLoader::loadOrCreate(const bf::path &filename) {
|
|||
}
|
||||
}
|
||||
|
||||
CryConfigFile CryConfigLoader::_loadConfig(const bf::path &filename) {
|
||||
optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
|
||||
string password = _askPassword();
|
||||
auto config = CryConfigFile::load(filename, password);
|
||||
if (config == none) {
|
||||
std::cerr << "Could not load config file. Wrong password?" << std::endl;
|
||||
exit(1);
|
||||
LOG(ERROR) << "Could not load config file. Wrong password?";
|
||||
return none;
|
||||
}
|
||||
return std::move(*config);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ public:
|
|||
CryConfigLoader(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, std::function<std::string()> askPassword);
|
||||
CryConfigLoader(CryConfigLoader &&rhs) = default;
|
||||
|
||||
CryConfigFile loadOrCreate(const boost::filesystem::path &filename);
|
||||
boost::optional<CryConfigFile> loadOrCreate(const boost::filesystem::path &filename);
|
||||
|
||||
private:
|
||||
CryConfigFile _loadConfig(const boost::filesystem::path &filename);
|
||||
boost::optional<CryConfigFile> _loadConfig(const boost::filesystem::path &filename);
|
||||
CryConfigFile _createConfig(const boost::filesystem::path &filename);
|
||||
|
||||
CryConfigCreator _creator;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#include "RandomPadding.h"
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
#include <messmer/cpp-utils/random/Random.h>
|
||||
|
||||
using cpputils::Data;
|
||||
using cpputils::Random;
|
||||
using boost::optional;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cryfs {
|
||||
Data RandomPadding::add(const Data &data, size_t targetSize) {
|
||||
uint32_t size = data.size();
|
||||
ASSERT(size < targetSize - sizeof(size), "Config data too large. We should increase padding target size.");
|
||||
Data randomData = Random::PseudoRandom().get(targetSize-sizeof(size)-size);
|
||||
ASSERT(sizeof(size) + size + randomData.size() == targetSize, "Calculated size of randomData incorrectly");
|
||||
Data result(targetSize);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), &size, sizeof(size));
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size))), reinterpret_cast<const char*>(data.data()), size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.dataOffset(sizeof(size)+size)), reinterpret_cast<const char*>(randomData.data()), randomData.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<Data> RandomPadding::remove(const Data &data) {
|
||||
uint32_t size;
|
||||
std::memcpy(&size, reinterpret_cast<const char*>(data.data()), sizeof(size));
|
||||
if(sizeof(size) + size >= data.size()) {
|
||||
LOG(ERROR) << "Config file is invalid: Invalid padding.";
|
||||
return boost::none;
|
||||
};
|
||||
Data result(size);
|
||||
std::memcpy(reinterpret_cast<char*>(result.data()), reinterpret_cast<const char*>(data.dataOffset(sizeof(size))), size);
|
||||
return std::move(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_SRC_CONFIG_PADDING_H
|
||||
#define MESSMER_CRYFS_SRC_CONFIG_PADDING_H
|
||||
|
||||
#include <messmer/cpp-utils/data/Data.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace cryfs {
|
||||
//TODO Test
|
||||
class RandomPadding {
|
||||
public:
|
||||
static cpputils::Data add(const cpputils::Data &data, size_t targetSize);
|
||||
static boost::optional<cpputils::Data> remove(const cpputils::Data &data);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -91,7 +91,11 @@ CryConfigFile loadOrCreateConfig(const ProgramOptions &options) {
|
|||
auto configFile = determineConfigFile(options);
|
||||
auto console = make_unique_ref<IOStreamConsole>();
|
||||
auto &keyGenerator = Random::OSRandom();
|
||||
return CryConfigLoader(std::move(console), keyGenerator, &askPassword).loadOrCreate(configFile);
|
||||
auto config = CryConfigLoader(std::move(console), keyGenerator, &askPassword).loadOrCreate(configFile);
|
||||
if (config == none) {
|
||||
std::cerr << "Could not load config file. Did you enter the correct password?" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
|
|
|
@ -26,28 +26,28 @@ public:
|
|||
|
||||
CryConfigFile Create(const string &password = "mypassword") {
|
||||
EXPECT_FALSE(file.exists());
|
||||
return loader(password).loadOrCreate(file.path());
|
||||
return loader(password).loadOrCreate(file.path()).value();
|
||||
}
|
||||
|
||||
CryConfigFile Load(const string &password = "mypassword") {
|
||||
optional<CryConfigFile> Load(const string &password = "mypassword") {
|
||||
EXPECT_TRUE(file.exists());
|
||||
return loader(password).loadOrCreate(file.path());
|
||||
}
|
||||
|
||||
void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
||||
cfg.config()->SetRootBlob(rootBlob);
|
||||
cfg.save();
|
||||
}
|
||||
|
||||
void CreateWithCipher(const string &cipher, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
||||
cfg.config()->SetCipher(cipher);
|
||||
cfg.save();
|
||||
}
|
||||
|
||||
void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
auto cfg = loader(password).loadOrCreate(file.path()).value();
|
||||
cfg.config()->SetEncryptionKey(encKey);
|
||||
cfg.save();
|
||||
}
|
||||
|
@ -66,24 +66,15 @@ TEST_F(CryConfigLoaderTest, DoesntCrashIfExisting) {
|
|||
Load();
|
||||
}
|
||||
|
||||
//Giving the test case a "DeathTest" suffix causes gtest to run it before other tests.
|
||||
//This is necessary, because otherwise the call to exit() will fail and deadlock because the DeathTest is run
|
||||
//in a forked process. Some of the other tests here access global singletons that create a thread and want to join
|
||||
//it on process exit. But threads aren't forked by the fork syscall, so it waits forever.
|
||||
using CryConfigLoaderTest_DeathTest = CryConfigLoaderTest;
|
||||
|
||||
TEST_F(CryConfigLoaderTest_DeathTest, DoesntLoadIfWrongPassword) {
|
||||
TEST_F(CryConfigLoaderTest, DoesntLoadIfWrongPassword) {
|
||||
Create("mypassword");
|
||||
EXPECT_EXIT(
|
||||
Load("mypassword2"),
|
||||
::testing::ExitedWithCode(1),
|
||||
"Wrong password"
|
||||
);
|
||||
auto loaded = Load("mypassword2");
|
||||
EXPECT_EQ(none, loaded);
|
||||
}
|
||||
|
||||
TEST_F(CryConfigLoaderTest, RootBlob_Load) {
|
||||
CreateWithRootBlob("rootblobid");
|
||||
auto loaded = Load();
|
||||
auto loaded = Load().value();
|
||||
EXPECT_EQ("rootblobid", loaded.config()->RootBlob());
|
||||
}
|
||||
|
||||
|
@ -94,7 +85,7 @@ TEST_F(CryConfigLoaderTest, RootBlob_Create) {
|
|||
|
||||
TEST_F(CryConfigLoaderTest, EncryptionKey_Load) {
|
||||
CreateWithEncryptionKey("encryptionkey");
|
||||
auto loaded = Load();
|
||||
auto loaded = Load().value();
|
||||
EXPECT_EQ("encryptionkey", loaded.config()->EncryptionKey());
|
||||
}
|
||||
|
||||
|
@ -106,7 +97,7 @@ TEST_F(CryConfigLoaderTest, EncryptionKey_Create) {
|
|||
|
||||
TEST_F(CryConfigLoaderTest, Cipher_Load) {
|
||||
CreateWithCipher("ciphername");
|
||||
auto loaded = Load();
|
||||
auto loaded = Load().value();
|
||||
EXPECT_EQ("ciphername", loaded.config()->Cipher());
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
}
|
||||
|
||||
CryConfigFile loadOrCreateConfig() {
|
||||
return CryConfigLoader(mockConsole(), Random::PseudoRandom(), [] {return "mypassword";}).loadOrCreate(config.path());
|
||||
return CryConfigLoader(mockConsole(), Random::PseudoRandom(), [] {return "mypassword";}).loadOrCreate(config.path()).value();
|
||||
}
|
||||
|
||||
unique_ref<OnDiskBlockStore> blockStore() {
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
unique_ref<Device> createDevice() override {
|
||||
auto blockStore = cpputils::make_unique_ref<FakeBlockStore>();
|
||||
auto config = CryConfigLoader(mockConsole(), Random::PseudoRandom(), [] {return "mypassword";})
|
||||
.loadOrCreate(configFile.path());
|
||||
.loadOrCreate(configFile.path()).value();
|
||||
return make_unique_ref<CryDevice>(std::move(config), std::move(blockStore));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue