Refactor config file handling

This commit is contained in:
Sebastian Messmer 2015-10-19 02:46:47 +02:00
parent 03ad5cbe45
commit 2104a85e95
10 changed files with 229 additions and 132 deletions

View File

@ -8,33 +8,36 @@ namespace bf = boost::filesystem;
using boost::property_tree::ptree;
using std::string;
using std::istream;
using std::ostream;
namespace cryfs {
CryConfig::CryConfig(const bf::path &configfile)
:_configfile(configfile), _rootBlob(""), _encKey(""), _cipher("") {
if (bf::exists(_configfile)) {
load();
}
CryConfig::CryConfig()
: _rootBlob(""), _encKey(""), _cipher("") {
}
void CryConfig::load() {
CryConfig::CryConfig(CryConfig &&rhs)
: _rootBlob(std::move(rhs._rootBlob)), _encKey(std::move(rhs._encKey)), _cipher(std::move(rhs._cipher)) {
}
void CryConfig::load(istream &loadSource) {
ptree pt;
read_json(_configfile.native(), pt);
read_json(loadSource, pt);
_rootBlob = pt.get("cryfs.rootblob", "");
_encKey = pt.get("cryfs.key", "");
_cipher = pt.get("cryfs.cipher", "");
}
void CryConfig::save() const {
void CryConfig::save(ostream &writeDestination) const {
ptree pt;
pt.put("cryfs.rootblob", _rootBlob);
pt.put("cryfs.key", _encKey);
pt.put("cryfs.cipher", _cipher);
write_json(_configfile.native(), pt);
write_json(writeDestination, pt);
}
const std::string &CryConfig::RootBlob() const {
@ -61,8 +64,4 @@ void CryConfig::SetCipher(const std::string &value) {
_cipher = value;
}
CryConfig::~CryConfig() {
save();
}
}

View File

@ -5,13 +5,14 @@
#include <boost/filesystem/path.hpp>
#include "messmer/cpp-utils/macros.h"
#include <iostream>
namespace cryfs {
class CryConfig {
class CryConfig final {
public:
explicit CryConfig(const boost::filesystem::path &configfile);
virtual ~CryConfig();
CryConfig();
CryConfig(CryConfig &&rhs);
const std::string &RootBlob() const;
void SetRootBlob(const std::string &value);
@ -22,13 +23,10 @@ public:
const std::string &Cipher() const;
void SetCipher(const std::string &value);
void save() const;
void load(std::istream &loadSource);
void save(std::ostream &destination) const;
private:
boost::filesystem::path _configfile;
void load();
std::string _rootBlob;
std::string _encKey;
std::string _cipher;

View File

@ -0,0 +1,72 @@
#include "CryConfigCreator.h"
#include "CryCipher.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
using cpputils::Console;
using cpputils::unique_ref;
using std::string;
using std::vector;
namespace cryfs {
CryConfigCreator::CryConfigCreator(unique_ref<Console> console)
:_console(std::move(console)) {
}
CryConfig CryConfigCreator::create() {
CryConfig config;
config.SetCipher(_generateCipher());
config.SetEncryptionKey(_generateEncKey(config.Cipher()));
config.SetRootBlob(_generateRootBlobKey());
return config;
}
CryConfig CryConfigCreator::createForTest() {
CryConfig config;
config.SetCipher(_generateCipherForTest());
config.SetEncryptionKey(_generateEncKeyForTest(config.Cipher()));
config.SetRootBlob(_generateRootBlobKey());
return config;
}
string CryConfigCreator::_generateCipher() {
vector<string> ciphers = CryCiphers::supportedCipherNames();
string cipherName = "";
bool askAgain = true;
while(askAgain) {
int cipherIndex = _console->ask("Which block cipher do you want to use?", ciphers);
cipherName = ciphers[cipherIndex];
askAgain = !_showWarningForCipherAndReturnIfOk(cipherName);
};
return cipherName;
}
bool CryConfigCreator::_showWarningForCipherAndReturnIfOk(const string &cipherName) {
auto warning = CryCiphers::find(cipherName).warning();
if (warning == boost::none) {
return true;
}
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?");
}
string CryConfigCreator::_generateEncKey(const std::string &cipher) {
_console->print("\nGenerating secure encryption key...");
auto key = CryCiphers::find(cipher).createKey();
_console->print("done\n");
return key;
}
string CryConfigCreator::_generateCipherForTest() {
return "aes-256-gcm";
}
string CryConfigCreator::_generateEncKeyForTest(const std::string &) {
return blockstore::encrypted::AES256_GCM::EncryptionKey::CreatePseudoRandom().ToString();
}
string CryConfigCreator::_generateRootBlobKey() {
//An empty root blob entry will tell CryDevice to create a new root blob
return "";
}
}

View File

@ -0,0 +1,31 @@
#ifndef CRYFS_SRC_CONFIG_CRYCONFIGCREATOR_H
#define CRYFS_SRC_CONFIG_CRYCONFIGCREATOR_H
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include <messmer/cpp-utils/io/Console.h>
#include "CryConfig.h"
namespace cryfs {
class CryConfigCreator final {
public:
CryConfigCreator(cpputils::unique_ref<cpputils::Console> console);
CryConfig create();
CryConfig createForTest();
private:
std::string _generateCipher();
std::string _generateEncKey(const std::string &cipher);
std::string _generateRootBlobKey();
bool _showWarningForCipherAndReturnIfOk(const std::string &cipherName);
//TODO Don't have these functions here, but use a CryConfigCreator interface and mock it in the tests
std::string _generateEncKeyForTest(const std::string &cipher);
std::string _generateCipherForTest();
cpputils::unique_ref<cpputils::Console> _console;
DISALLOW_COPY_AND_ASSIGN(CryConfigCreator);
};
}
#endif

View File

@ -0,0 +1,44 @@
#include "CryConfigFile.h"
#include <fstream>
#include <boost/filesystem.hpp>
using boost::optional;
using boost::none;
using std::ifstream;
using std::ofstream;
namespace bf = boost::filesystem;
namespace cryfs {
CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config) {
return CryConfigFile(path, std::move(config));
}
optional<CryConfigFile> CryConfigFile::load(const bf::path &path) {
if (!bf::exists(path)) {
return none;
}
ifstream file(path.native());
CryConfig config;
config.load(file);
return CryConfigFile(path, std::move(config));
}
CryConfigFile::CryConfigFile(const bf::path &path, CryConfig config)
: _path (path), _config(std::move(config)) {
}
CryConfigFile::CryConfigFile(CryConfigFile &&rhs)
: _path(std::move(rhs._path)), _config(std::move(rhs._config)) {
}
void CryConfigFile::save() const {
ofstream file(_path.native(), ofstream::out|ofstream::binary|ofstream::trunc);
_config.save(file);
}
CryConfig *CryConfigFile::config() {
return &_config;
}
}

View File

@ -0,0 +1,29 @@
#ifndef CRYFS_SRC_CONFIG_CRYCONFIGFILE_H
#define CRYFS_SRC_CONFIG_CRYCONFIGFILE_H
#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
#include "CryConfig.h"
namespace cryfs {
class CryConfigFile final {
public:
CryConfigFile(CryConfigFile &&rhs);
static CryConfigFile create(const boost::filesystem::path &path, CryConfig config);
static boost::optional<CryConfigFile> load(const boost::filesystem::path &path);
void save() const;
CryConfig *config();
private:
CryConfigFile(const boost::filesystem::path &path, CryConfig config);
boost::filesystem::path _path;
CryConfig _config;
DISALLOW_COPY_AND_ASSIGN(CryConfigFile);
};
}
#endif

View File

@ -1,4 +1,5 @@
#include "CryConfigLoader.h"
#include "CryConfigFile.h"
#include <boost/filesystem.hpp>
namespace bf = boost::filesystem;
@ -15,95 +16,36 @@ namespace cryfs {
CryConfigLoader::CryConfigLoader(): CryConfigLoader(make_unique_ref<IOStreamConsole>()) {}
CryConfigLoader::CryConfigLoader(unique_ref<Console> console) : _console(std::move(console)) {}
CryConfigLoader::CryConfigLoader(unique_ref<Console> console) : _creator(std::move(console)) {}
unique_ref<CryConfig> CryConfigLoader::loadOrCreate(const bf::path &filename) {
auto config = loadExisting(filename);
CryConfigFile CryConfigLoader::loadOrCreate(const bf::path &filename) {
auto config = CryConfigFile::load(filename);
if (config != none) {
return std::move(*config);
}
return createNew(filename);
}
unique_ref<CryConfig> CryConfigLoader::createNew(const bf::path &filename) {
auto config = make_unique_ref<CryConfig>(filename);
_initializeConfig(config.get());
config->save();
return config;
CryConfigFile CryConfigLoader::createNew(const bf::path &filename) {
auto config = _creator.create();
auto configFile = CryConfigFile::create(filename, std::move(config));
configFile.save();
return configFile;
}
void CryConfigLoader::_initializeConfig(CryConfig *config) {
_generateCipher(config);
_generateEncKey(config);
_generateRootBlobKey(config);
}
void CryConfigLoader::_initializeConfigWithWeakKey(CryConfig *config) {
_generateTestCipher(config);
_generateWeakEncKey(config);
_generateRootBlobKey(config);
}
void CryConfigLoader::_generateCipher(CryConfig *config) {
vector<string> ciphers = CryCiphers::supportedCipherNames();
string cipherName = "";
bool askAgain = true;
while(askAgain) {
int cipherIndex = _console->ask("Which block cipher do you want to use?", ciphers);
cipherName = ciphers[cipherIndex];
askAgain = !_showWarningForCipherAndReturnIfOk(cipherName);
};
config->SetCipher(cipherName);
}
bool CryConfigLoader::_showWarningForCipherAndReturnIfOk(const string &cipherName) {
auto warning = CryCiphers::find(cipherName).warning();
if (warning == boost::none) {
return true;
}
return _console->askYesNo(string() + (*warning) + " Do you want to take this cipher nevertheless?");
}
void CryConfigLoader::_generateEncKey(CryConfig *config) {
_console->print("\nGenerating secure encryption key...");
config->SetEncryptionKey(CryCiphers::find(config->Cipher()).createKey());
_console->print("done\n");
}
void CryConfigLoader::_generateTestCipher(CryConfig *config) {
config->SetCipher("aes-256-gcm");
}
void CryConfigLoader::_generateWeakEncKey(CryConfig *config) {
auto new_key = blockstore::encrypted::AES256_GCM::EncryptionKey::CreatePseudoRandom();
config->SetEncryptionKey(new_key.ToString());
}
void CryConfigLoader::_generateRootBlobKey(CryConfig *config) {
//An empty root blob entry will tell CryDevice to create a new root blob
config->SetRootBlob("");
}
optional<unique_ref<CryConfig>> CryConfigLoader::loadExisting(const bf::path &filename) {
if (bf::exists(filename)) {
return make_unique_ref<CryConfig>(filename);
}
return none;
}
unique_ref<CryConfig> CryConfigLoader::loadOrCreateWithWeakKey(const bf::path &filename) {
auto config = loadExisting(filename);
CryConfigFile CryConfigLoader::loadOrCreateForTest(const bf::path &filename) {
auto config = CryConfigFile::load(filename);
if (config != none) {
return std::move(*config);
}
return createNewWithWeakKey(filename);
return createNewForTest(filename);
}
unique_ref<CryConfig> CryConfigLoader::createNewWithWeakKey(const bf::path &filename) {
auto config = make_unique_ref<CryConfig>(filename);
_initializeConfigWithWeakKey(config.get());
config->save();
return config;
CryConfigFile CryConfigLoader::createNewForTest(const bf::path &filename) {
auto config = _creator.createForTest();
auto configFile = CryConfigFile::create(filename, std::move(config));
configFile.save();
return configFile;
}
}

View File

@ -4,10 +4,9 @@
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include <boost/filesystem/path.hpp>
#include "CryConfig.h"
#include "CryConfigFile.h"
#include "CryCipher.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
#include <messmer/cpp-utils/io/Console.h>
#include "CryConfigCreator.h"
namespace cryfs {
@ -16,28 +15,15 @@ public:
CryConfigLoader();
explicit CryConfigLoader(cpputils::unique_ref<cpputils::Console> console);
cpputils::unique_ref<CryConfig> loadOrCreate(const boost::filesystem::path &filename);
CryConfigFile loadOrCreate(const boost::filesystem::path &filename);
CryConfigFile createNew(const boost::filesystem::path &filename);
cpputils::unique_ref<CryConfig> createNew(const boost::filesystem::path &filename);
boost::optional<cpputils::unique_ref<CryConfig>> loadExisting(const boost::filesystem::path &filename);
//This method is only for testing purposes, because creating weak keys is much faster than creating strong keys.
cpputils::unique_ref<CryConfig> loadOrCreateWithWeakKey(const boost::filesystem::path &filename);
cpputils::unique_ref<CryConfig> createNewWithWeakKey(const boost::filesystem::path &filename);
//This methods are only for testing purposes, because creating weak keys is much faster than creating strong keys.
CryConfigFile loadOrCreateForTest(const boost::filesystem::path &filename);
CryConfigFile createNewForTest(const boost::filesystem::path &filename);
private:
void _initializeConfig(CryConfig *config);
void _generateCipher(CryConfig *config);
void _generateEncKey(CryConfig *config);
void _generateRootBlobKey(CryConfig *config);
void _initializeConfigWithWeakKey(CryConfig *config); // TODO Rename to _initializeConfigForTest
void _generateWeakEncKey(CryConfig *config); // TODO Rename to _generateTestEncKey
void _generateTestCipher(CryConfig *config);
bool _showWarningForCipherAndReturnIfOk(const std::string &cipherName);
cpputils::unique_ref<cpputils::Console> _console;
CryConfigCreator _creator;
};
}

View File

@ -46,27 +46,24 @@ namespace cryfs {
constexpr uint32_t CryDevice::BLOCKSIZE_BYTES;
CryDevice::CryDevice(unique_ref<CryConfig> config, unique_ref<BlockStore> blockStore)
CryDevice::CryDevice(CryConfigFile configFile, unique_ref<BlockStore> blockStore)
: _fsBlobStore(
make_unique_ref<ParallelAccessFsBlobStore>(
make_unique_ref<CachingFsBlobStore>(
make_unique_ref<FsBlobStore>(
make_unique_ref<BlobStoreOnBlocks>(
make_unique_ref<CachingBlockStore>(
CreateEncryptedBlockStore(*config, std::move(blockStore))
CreateEncryptedBlockStore(*configFile.config(), std::move(blockStore))
), BLOCKSIZE_BYTES)))
)
),
_rootKey(GetOrCreateRootKey(config.get())) {
_rootKey(GetOrCreateRootKey(&configFile)) {
}
Key CryDevice::CreateRootBlobAndReturnKey() {
return _fsBlobStore->createDirBlob()->key();
}
CryDevice::~CryDevice() {
}
optional<unique_ref<fspp::Node>> CryDevice::Load(const bf::path &path) {
ASSERT(path.is_absolute(), "Non absolute path given");
@ -149,12 +146,12 @@ void CryDevice::RemoveBlob(const blockstore::Key &key) {
_fsBlobStore->remove(std::move(*blob));
}
Key CryDevice::GetOrCreateRootKey(CryConfig *config) {
string root_key = config->RootBlob();
Key CryDevice::GetOrCreateRootKey(CryConfigFile *configFile) {
string root_key = configFile->config()->RootBlob();
if (root_key == "") {
auto new_key = CreateRootBlobAndReturnKey();
config->SetRootBlob(new_key.ToString());
config->save();
configFile->config()->SetRootBlob(new_key.ToString());
configFile->save();
return new_key;
}

View File

@ -15,12 +15,11 @@
namespace cryfs {
class CryDevice: public fspp::Device {
class CryDevice final: public fspp::Device {
public:
static constexpr uint32_t BLOCKSIZE_BYTES = 32 * 1024;
CryDevice(cpputils::unique_ref<CryConfig> config, cpputils::unique_ref<blockstore::BlockStore> blockStore);
virtual ~CryDevice();
CryDevice(CryConfigFile config, cpputils::unique_ref<blockstore::BlockStore> blockStore);
void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) override;
@ -41,7 +40,7 @@ private:
blockstore::Key _rootKey;
blockstore::Key GetOrCreateRootKey(CryConfig *config);
blockstore::Key GetOrCreateRootKey(CryConfigFile *config);
blockstore::Key CreateRootBlobAndReturnKey();
static cpputils::unique_ref<blockstore::BlockStore> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore> baseBlockStore);