Config file is AES256_GCM encrypted, the config file key is generated with scrypt
This commit is contained in:
parent
7988cc406d
commit
371303ae6a
@ -3,13 +3,14 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
using boost::property_tree::ptree;
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using std::stringstream;
|
||||
using cpputils::Data;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
@ -21,23 +22,29 @@ CryConfig::CryConfig(CryConfig &&rhs)
|
||||
: _rootBlob(std::move(rhs._rootBlob)), _encKey(std::move(rhs._encKey)), _cipher(std::move(rhs._cipher)) {
|
||||
}
|
||||
|
||||
void CryConfig::load(istream &loadSource) {
|
||||
CryConfig CryConfig::load(const Data &data) {
|
||||
stringstream stream;
|
||||
data.StoreToStream(stream);
|
||||
ptree pt;
|
||||
read_json(loadSource, pt);
|
||||
read_json(stream, pt);
|
||||
|
||||
_rootBlob = pt.get("cryfs.rootblob", "");
|
||||
_encKey = pt.get("cryfs.key", "");
|
||||
_cipher = pt.get("cryfs.cipher", "");
|
||||
CryConfig cfg;
|
||||
cfg._rootBlob = pt.get("cryfs.rootblob", "");
|
||||
cfg._encKey = pt.get("cryfs.key", "");
|
||||
cfg._cipher = pt.get("cryfs.cipher", "");
|
||||
return cfg;
|
||||
}
|
||||
|
||||
void CryConfig::save(ostream &writeDestination) const {
|
||||
Data CryConfig::save() const {
|
||||
ptree pt;
|
||||
|
||||
pt.put("cryfs.rootblob", _rootBlob);
|
||||
pt.put("cryfs.key", _encKey);
|
||||
pt.put("cryfs.cipher", _cipher);
|
||||
|
||||
write_json(writeDestination, pt);
|
||||
stringstream stream;
|
||||
write_json(stream, pt);
|
||||
return Data::LoadFromStream(stream);
|
||||
}
|
||||
|
||||
const std::string &CryConfig::RootBlob() const {
|
||||
|
@ -4,13 +4,14 @@
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "messmer/cpp-utils/macros.h"
|
||||
#include <messmer/cpp-utils/data/Data.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CryConfig final {
|
||||
public:
|
||||
//TODO No default constructor, pass in config values instead!
|
||||
CryConfig();
|
||||
CryConfig(CryConfig &&rhs);
|
||||
|
||||
@ -23,8 +24,8 @@ public:
|
||||
const std::string &Cipher() const;
|
||||
void SetCipher(const std::string &value);
|
||||
|
||||
void load(std::istream &loadSource);
|
||||
void save(std::ostream &destination) const;
|
||||
static CryConfig load(const cpputils::Data &data);
|
||||
cpputils::Data save() const;
|
||||
|
||||
private:
|
||||
std::string _rootBlob;
|
||||
|
@ -11,6 +11,7 @@ namespace cryfs {
|
||||
class CryConfigCreator final {
|
||||
public:
|
||||
CryConfigCreator(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &encryptionKeyGenerator);
|
||||
CryConfigCreator(CryConfigCreator &&rhs) = default;
|
||||
|
||||
CryConfig create();
|
||||
private:
|
||||
|
1
src/config/CryConfigEncryptor.cpp
Normal file
1
src/config/CryConfigEncryptor.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "CryConfigEncryptor.h"
|
111
src/config/CryConfigEncryptor.h
Normal file
111
src/config/CryConfigEncryptor.h
Normal file
@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGENCRYPTOR_H
|
||||
#define MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGENCRYPTOR_H
|
||||
|
||||
#include <messmer/cpp-utils/data/Data.h>
|
||||
#include <messmer/cpp-utils/random/Random.h>
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include "crypto/Scrypt.h"
|
||||
|
||||
namespace cryfs {
|
||||
//TODO Test
|
||||
//TODO Don't only encrypt with the main cipher, but also use user specified cipher.
|
||||
//TODO Refactor. Functions too large.
|
||||
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
|
||||
|
||||
//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);
|
||||
|
||||
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 const std::string header;
|
||||
};
|
||||
|
||||
template<class Cipher> const std::string CryConfigEncryptor<Cipher>::header = "scrypt";
|
||||
|
||||
template<class Cipher>
|
||||
typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey CryConfigEncryptor<Cipher>::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;
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
boost::optional<std::pair<typename CryConfigEncryptor<Cipher>::ConfigEncryptionKey, cpputils::Data>>
|
||||
CryConfigEncryptor<Cipher>::decrypt(const cpputils::Data &ciphertext, const std::string &password) {
|
||||
std::stringstream stream;
|
||||
ciphertext.StoreToStream(stream);
|
||||
char readHeader[header.size()+1];
|
||||
stream.read(readHeader, header.size()+1);
|
||||
if (readHeader[header.size()] != '\0' || header != std::string(readHeader)) {
|
||||
cpputils::logging::LOG(cpputils::logging::ERROR) << "Wrong config file format";
|
||||
return boost::none;
|
||||
}
|
||||
auto keyConfig = DerivedKeyConfig::load(stream);
|
||||
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;
|
||||
auto data = cpputils::Data::LoadFromStream(stream);
|
||||
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(data.data()), data.size(), key);
|
||||
if (decrypted == boost::none) {
|
||||
cpputils::logging::LOG(cpputils::logging::ERROR) << "Couldn't load config file. Wrong password?";
|
||||
return boost::none;
|
||||
}
|
||||
auto plaintext = _removePadding(*decrypted);
|
||||
if (plaintext == boost::none) {
|
||||
cpputils::logging::LOG(cpputils::logging::ERROR) << "Config file is invalid: Invalid padding.";
|
||||
return boost::none;
|
||||
}
|
||||
return std::make_pair(ConfigEncryptionKey(std::move(keyConfig), std::move(key)), std::move(*plaintext));
|
||||
};
|
||||
|
||||
template<class Cipher>
|
||||
cpputils::Data CryConfigEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext, const ConfigEncryptionKey &key) {
|
||||
std::stringstream stream;
|
||||
stream.write(header.c_str(), header.size()+1);
|
||||
key.config().save(stream);
|
||||
auto paddedPlaintext = _addPadding(plaintext);
|
||||
auto ciphertext = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), key.key());
|
||||
ciphertext.StoreToStream(stream);
|
||||
return cpputils::Data::LoadFromStream(stream);
|
||||
}
|
||||
|
||||
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 >= CONFIG_SIZE) {
|
||||
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
|
@ -1,20 +1,31 @@
|
||||
#include "CryConfigFile.h"
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <sstream>
|
||||
#include "crypto/Scrypt.h"
|
||||
#include <messmer/cpp-utils/logging/logging.h>
|
||||
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
using std::string;
|
||||
using std::istringstream;
|
||||
using std::ostringstream;
|
||||
using std::stringstream;
|
||||
using std::istream;
|
||||
using cpputils::Data;
|
||||
namespace bf = boost::filesystem;
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config) {
|
||||
CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config, const string &password) {
|
||||
if (bf::exists(path)) {
|
||||
throw std::runtime_error("Config file exists already.");
|
||||
}
|
||||
auto result = CryConfigFile(path, std::move(config));
|
||||
auto configEncKey = Encryptor::deriveKey(password);
|
||||
auto result = CryConfigFile(path, std::move(config), std::move(configEncKey));
|
||||
result.save();
|
||||
return result;
|
||||
}
|
||||
@ -23,27 +34,28 @@ 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) {
|
||||
if (!bf::exists(path)) {
|
||||
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;
|
||||
}
|
||||
ifstream file(path.native());
|
||||
CryConfig config;
|
||||
config.load(file);
|
||||
return CryConfigFile(path, std::move(config));
|
||||
auto decrypted = Encryptor::decrypt(*encryptedConfigData, password);
|
||||
if (decrypted == none) {
|
||||
return none;
|
||||
}
|
||||
CryConfig config = CryConfig::load(decrypted->second);
|
||||
return CryConfigFile(path, std::move(config), std::move(decrypted->first));
|
||||
}
|
||||
|
||||
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)) {
|
||||
CryConfigFile::CryConfigFile(const bf::path &path, CryConfig config, ConfigEncryptionKey configEncKey)
|
||||
: _path (path), _config(std::move(config)), _configEncKey(std::move(configEncKey)) {
|
||||
}
|
||||
|
||||
void CryConfigFile::save() const {
|
||||
ofstream file(_path.native(), ofstream::out|ofstream::binary|ofstream::trunc);
|
||||
_config.save(file);
|
||||
Data configData = _config.save();
|
||||
auto encrypted = Encryptor::encrypt(configData, _configEncKey);
|
||||
encrypted.StoreToFile(_path);
|
||||
}
|
||||
|
||||
CryConfig *CryConfigFile::config() {
|
||||
|
@ -5,24 +5,35 @@
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include "CryConfig.h"
|
||||
#include "CryConfigEncryptor.h"
|
||||
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
|
||||
|
||||
namespace cryfs {
|
||||
class CryConfigFile final {
|
||||
public:
|
||||
CryConfigFile(CryConfigFile &&rhs);
|
||||
using ConfigCipher = blockstore::encrypted::AES256_GCM;
|
||||
using ConfigEncryptionKey = DerivedKey<ConfigCipher::EncryptionKey::BINARY_LENGTH>;
|
||||
|
||||
CryConfigFile(CryConfigFile &&rhs) = default;
|
||||
~CryConfigFile();
|
||||
|
||||
static CryConfigFile create(const boost::filesystem::path &path, CryConfig config);
|
||||
static boost::optional<CryConfigFile> load(const boost::filesystem::path &path);
|
||||
static CryConfigFile create(const boost::filesystem::path &path, CryConfig config, const std::string &password);
|
||||
static boost::optional<CryConfigFile> load(const boost::filesystem::path &path, const std::string &password);
|
||||
void save() const;
|
||||
|
||||
CryConfig *config();
|
||||
|
||||
private:
|
||||
CryConfigFile(const boost::filesystem::path &path, CryConfig config);
|
||||
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);
|
||||
|
||||
boost::filesystem::path _path;
|
||||
CryConfig _config;
|
||||
ConfigEncryptionKey _configEncKey;
|
||||
using Encryptor = CryConfigEncryptor<ConfigCipher>;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CryConfigFile);
|
||||
};
|
||||
|
@ -8,22 +8,43 @@ using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using cpputils::Console;
|
||||
using cpputils::IOStreamConsole;
|
||||
using cpputils::Random;
|
||||
using cpputils::RandomGenerator;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::function;
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
CryConfigLoader::CryConfigLoader(unique_ref<Console> console, cpputils::RandomGenerator &keyGenerator)
|
||||
: _creator(std::move(console), keyGenerator) {}
|
||||
CryConfigLoader::CryConfigLoader(unique_ref<Console> console, RandomGenerator &keyGenerator, function<string()> askPassword)
|
||||
: _creator(std::move(console), keyGenerator), _askPassword(askPassword) {
|
||||
}
|
||||
|
||||
CryConfigFile CryConfigLoader::loadOrCreate(const bf::path &filename) {
|
||||
auto config = CryConfigFile::load(filename);
|
||||
if (config != none) {
|
||||
return std::move(*config);
|
||||
if (bf::exists(filename)) {
|
||||
return _loadConfig(filename);
|
||||
} else {
|
||||
return _createConfig(filename);
|
||||
}
|
||||
return CryConfigFile::create(filename, _creator.create());
|
||||
}
|
||||
|
||||
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;
|
||||
abort(); // TODO Use exit() once gtest can handle that
|
||||
}
|
||||
return std::move(*config);
|
||||
}
|
||||
|
||||
CryConfigFile CryConfigLoader::_createConfig(const bf::path &filename) {
|
||||
auto config = _creator.create();
|
||||
//TODO Ask confirmation if using insecure password (<8 characters)
|
||||
string password = _askPassword();
|
||||
return CryConfigFile::create(filename, std::move(config), password);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,12 +12,19 @@ namespace cryfs {
|
||||
|
||||
class CryConfigLoader {
|
||||
public:
|
||||
CryConfigLoader(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator);
|
||||
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);
|
||||
|
||||
private:
|
||||
CryConfigCreator _creator;
|
||||
CryConfigFile _loadConfig(const boost::filesystem::path &filename);
|
||||
CryConfigFile _createConfig(const boost::filesystem::path &filename);
|
||||
|
||||
CryConfigCreator _creator;
|
||||
std::function<std::string()> _askPassword;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CryConfigLoader);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace cryfs {
|
||||
|
||||
class SCrypt {
|
||||
public:
|
||||
//TODO Make user-configurable. For sensitive storage, N=1048576, r=8 is recommended.
|
||||
//TODO Make user-configurable. For sensitive storage, N=1048576, r=8 is recommended. For tests, we should use faster settings.
|
||||
constexpr static size_t SALT_LEN = 32; // Size of the salt
|
||||
constexpr static uint64_t N = 524288; // CPU/Memory cost
|
||||
constexpr static uint32_t r = 1; // Blocksize
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "messmer/blockstore/implementations/encrypted/EncryptedBlockStore.h"
|
||||
#include "parallelaccessfsblobstore/ParallelAccessFsBlobStore.h"
|
||||
#include "cachingfsblobstore/CachingFsBlobStore.h"
|
||||
#include "../config/CryCipher.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
#define MESSMER_CRYFS_FILESYSTEM_CRYDEVICE_H_
|
||||
|
||||
#include <messmer/blockstore/interface/BlockStore.h>
|
||||
#include "../config/CryConfigLoader.h"
|
||||
#include "../config/CryConfigFile.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <messmer/fspp/fs_interface/Device.h>
|
||||
|
44
src/main.cpp
44
src/main.cpp
@ -15,6 +15,14 @@
|
||||
|
||||
#include <gitversion/version.h>
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
//<limits.h> needed for libc to define PASS_MAX
|
||||
#include <limits.h>
|
||||
#ifdef PASS_MAX
|
||||
#error The used libc implementation has a maximal password size for getpass(). We cannot use it to ask for passwords.
|
||||
#endif
|
||||
|
||||
using namespace cryfs;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
@ -26,6 +34,7 @@ using cpputils::make_unique_ref;
|
||||
using cpputils::Random;
|
||||
using cpputils::IOStreamConsole;
|
||||
using std::cout;
|
||||
using std::string;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using boost::none;
|
||||
@ -34,6 +43,7 @@ using boost::none;
|
||||
//TODO Improve parallelity.
|
||||
//TODO Did deadlock in bonnie++ second run (in the create files sequentially) - maybe also in a later run or different step?
|
||||
//TODO Improve error message when root blob wasn't found.
|
||||
//TODO Replace ASSERTs with other error handling when it is not a programming error but an environment influence (e.g. a block is missing)
|
||||
|
||||
void showVersion() {
|
||||
cout << "CryFS Version " << version::VERSION_STRING << endl;
|
||||
@ -52,15 +62,36 @@ void showVersion() {
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
CryConfigFile loadOrCreateConfig(const ProgramOptions &options) {
|
||||
auto console = make_unique_ref<IOStreamConsole>();
|
||||
auto &keyGenerator = Random::OSRandom();
|
||||
return CryConfigLoader(std::move(console), keyGenerator).loadOrCreate(bf::path(options.configFile()));
|
||||
bool checkPassword(const string &password) {
|
||||
if (password == "") {
|
||||
std::cerr << "Empty password not allowed. Please try again." << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string askPassword() {
|
||||
string password = getpass("Password: ");
|
||||
while(!checkPassword(password)) {
|
||||
password = getpass("Password: ");
|
||||
}
|
||||
return password;
|
||||
};
|
||||
|
||||
CryConfigFile loadOrCreateConfig(const bf::path &filename) {
|
||||
try {
|
||||
auto console = make_unique_ref<IOStreamConsole>();
|
||||
auto &keyGenerator = Random::OSRandom();
|
||||
return CryConfigLoader(std::move(console), keyGenerator, &askPassword).loadOrCreate(filename);
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void runFilesystem(const ProgramOptions &options) {
|
||||
auto config = loadOrCreateConfig(options);
|
||||
//TODO This daemonize causes error messages when initializing CryDevice to get lost.
|
||||
auto config = loadOrCreateConfig(options.configFile());
|
||||
//TODO This daemonize causes error messages from CryDevice initialization to get lost.
|
||||
// However, initializing CryDevice might (?) already spawn threads and we have to do daemonization before that
|
||||
// because it doesn't fork threads. What to do?
|
||||
if (!options.foreground()) {
|
||||
@ -76,6 +107,7 @@ void runFilesystem(const ProgramOptions &options) {
|
||||
fspp::fuse::Fuse fuse(&fsimpl);
|
||||
|
||||
vector<char*> fuseOptions = options.fuseOptions();
|
||||
std::cout << "\nFilesystem is running." << std::endl;
|
||||
fuse.run(fuseOptions.size(), fuseOptions.data());
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,23 @@
|
||||
|
||||
#include "../../src/config/CryConfigFile.h"
|
||||
#include <messmer/cpp-utils/tempfile/TempFile.h>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
using namespace cryfs;
|
||||
using cpputils::TempFile;
|
||||
using std::string;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
//gtest/boost::optional workaround for working with optional<CryConfigFile>
|
||||
namespace boost {
|
||||
inline std::ostream &operator<<(std::ostream &out, const CryConfigFile &file) {
|
||||
UNUSED(file);
|
||||
out << "ConfigFile";
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
class CryConfigFileTest: public ::testing::Test {
|
||||
public:
|
||||
@ -12,20 +26,32 @@ public:
|
||||
|
||||
TempFile file;
|
||||
|
||||
CryConfigFile CreateAndLoadEmpty() {
|
||||
Create(CryConfig());
|
||||
return Load();
|
||||
CryConfigFile CreateAndLoadEmpty(const string &password = "mypassword") {
|
||||
Create(CryConfig(), password);
|
||||
return Load().value();
|
||||
}
|
||||
|
||||
void Create(CryConfig cfg) {
|
||||
CryConfigFile::create(file.path(), std::move(cfg));
|
||||
void Create(CryConfig cfg, const string &password = "mypassword") {
|
||||
CryConfigFile::create(file.path(), std::move(cfg), password);
|
||||
}
|
||||
|
||||
CryConfigFile Load() {
|
||||
return CryConfigFile::load(file.path()).value();
|
||||
optional<CryConfigFile> Load(const string &password = "mypassword") {
|
||||
return CryConfigFile::load(file.path(), password);
|
||||
}
|
||||
|
||||
void CreateWithCipher(const string &cipher, const TempFile &tempFile) {
|
||||
CryConfig cfg;
|
||||
cfg.SetCipher(cipher);
|
||||
CryConfigFile::create(tempFile.path(), std::move(cfg), "mypassword");
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CryConfigFileTest, DoesntLoadIfWrongPassword) {
|
||||
Create(CryConfig(), "mypassword");
|
||||
auto loaded = Load("mypassword2");
|
||||
EXPECT_EQ(none, loaded);
|
||||
}
|
||||
|
||||
TEST_F(CryConfigFileTest, RootBlob_Init) {
|
||||
CryConfigFile created = CreateAndLoadEmpty();
|
||||
EXPECT_EQ("", created.config()->RootBlob());
|
||||
@ -35,7 +61,7 @@ TEST_F(CryConfigFileTest, RootBlob_CreateAndLoad) {
|
||||
CryConfig cfg;
|
||||
cfg.SetRootBlob("rootblobid");
|
||||
Create(std::move(cfg));
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("rootblobid", loaded.config()->RootBlob());
|
||||
}
|
||||
|
||||
@ -43,7 +69,7 @@ TEST_F(CryConfigFileTest, RootBlob_SaveAndLoad) {
|
||||
CryConfigFile created = CreateAndLoadEmpty();
|
||||
created.config()->SetRootBlob("rootblobid");
|
||||
created.save();
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("rootblobid", loaded.config()->RootBlob());
|
||||
}
|
||||
|
||||
@ -56,7 +82,7 @@ TEST_F(CryConfigFileTest, EncryptionKey_CreateAndLoad) {
|
||||
CryConfig cfg;
|
||||
cfg.SetEncryptionKey("encryptionkey");
|
||||
Create(std::move(cfg));
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("encryptionkey", loaded.config()->EncryptionKey());
|
||||
}
|
||||
|
||||
@ -64,7 +90,7 @@ TEST_F(CryConfigFileTest, EncryptionKey_SaveAndLoad) {
|
||||
CryConfigFile created = CreateAndLoadEmpty();
|
||||
created.config()->SetEncryptionKey("encryptionkey");
|
||||
created.save();
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("encryptionkey", loaded.config()->EncryptionKey());
|
||||
}
|
||||
|
||||
@ -77,7 +103,7 @@ TEST_F(CryConfigFileTest, Cipher_CreateAndLoad) {
|
||||
CryConfig cfg;
|
||||
cfg.SetCipher("cipher");
|
||||
Create(std::move(cfg));
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("cipher", loaded.config()->Cipher());
|
||||
}
|
||||
|
||||
@ -85,6 +111,15 @@ TEST_F(CryConfigFileTest, Cipher_SaveAndLoad) {
|
||||
CryConfigFile created = CreateAndLoadEmpty();
|
||||
created.config()->SetCipher("cipher");
|
||||
created.save();
|
||||
CryConfigFile loaded = Load();
|
||||
CryConfigFile loaded = Load().value();
|
||||
EXPECT_EQ("cipher", loaded.config()->Cipher());
|
||||
}
|
||||
|
||||
//Test that the encrypted config file has the same size, no matter how big the plaintext config data.
|
||||
TEST_F(CryConfigFileTest, ConfigFileHasFixedSize) {
|
||||
TempFile file1(false);
|
||||
TempFile file2(false);
|
||||
CreateWithCipher("short", file1);
|
||||
CreateWithCipher("long_cipher_name_that_causes_the_plaintext_config_data_to_be_larger", file2);
|
||||
EXPECT_EQ(bf::file_size(file1.path()), bf::file_size(file2.path()));
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using cpputils::TempFile;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
using std::string;
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
@ -16,37 +18,40 @@ using namespace cryfs;
|
||||
|
||||
class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole {
|
||||
public:
|
||||
CryConfigLoaderTest(): loader(mockConsole(), cpputils::Random::PseudoRandom()), file(false) {}
|
||||
CryConfigLoaderTest(): file(false) {}
|
||||
|
||||
CryConfigFile Create() {
|
||||
CryConfigLoader loader(const string &password) {
|
||||
return CryConfigLoader(mockConsole(), cpputils::Random::PseudoRandom(), [password] {return password;});
|
||||
}
|
||||
|
||||
CryConfigFile Create(const string &password = "mypassword") {
|
||||
EXPECT_FALSE(file.exists());
|
||||
return loader.loadOrCreate(file.path());
|
||||
return loader(password).loadOrCreate(file.path());
|
||||
}
|
||||
|
||||
CryConfigFile Load() {
|
||||
CryConfigFile Load(const string &password = "mypassword") {
|
||||
EXPECT_TRUE(file.exists());
|
||||
return loader.loadOrCreate(file.path());
|
||||
return loader(password).loadOrCreate(file.path());
|
||||
}
|
||||
|
||||
void CreateWithRootBlob(const string &rootBlob) {
|
||||
auto cfg = loader.loadOrCreate(file.path());
|
||||
void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
cfg.config()->SetRootBlob(rootBlob);
|
||||
cfg.save();
|
||||
}
|
||||
|
||||
void CreateWithCipher(const string &cipher) {
|
||||
auto cfg = loader.loadOrCreate(file.path());
|
||||
void CreateWithCipher(const string &cipher, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
cfg.config()->SetCipher(cipher);
|
||||
cfg.save();
|
||||
}
|
||||
|
||||
void CreateWithEncryptionKey(const string &encKey) {
|
||||
auto cfg = loader.loadOrCreate(file.path());
|
||||
void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") {
|
||||
auto cfg = loader(password).loadOrCreate(file.path());
|
||||
cfg.config()->SetEncryptionKey(encKey);
|
||||
cfg.save();
|
||||
}
|
||||
|
||||
CryConfigLoader loader;
|
||||
TempFile file;
|
||||
};
|
||||
|
||||
@ -61,6 +66,14 @@ TEST_F(CryConfigLoaderTest, DoesntCrashIfExisting) {
|
||||
Load();
|
||||
}
|
||||
|
||||
TEST_F(CryConfigLoaderTest, DoesntLoadIfWrongPassword) {
|
||||
Create("mypassword");
|
||||
EXPECT_DEATH(
|
||||
Load("mypassword2"),
|
||||
"Wrong password"
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(CryConfigLoaderTest, RootBlob_Load) {
|
||||
CreateWithRootBlob("rootblobid");
|
||||
auto loaded = Load();
|
||||
|
@ -3,17 +3,15 @@
|
||||
#include "../../src/config/CryConfig.h"
|
||||
|
||||
using namespace cryfs;
|
||||
using cpputils::Data;
|
||||
|
||||
class CryConfigTest: public ::testing::Test {
|
||||
public:
|
||||
CryConfig cfg;
|
||||
|
||||
CryConfig SaveAndLoad(CryConfig cfg) {
|
||||
std::stringstream stream;
|
||||
cfg.save(stream);
|
||||
CryConfig loaded;
|
||||
loaded.load(stream);
|
||||
return loaded;
|
||||
Data configData = cfg.save();
|
||||
return CryConfig::load(configData);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "../../src/filesystem/CryFile.h"
|
||||
#include "../../src/filesystem/CryOpenFile.h"
|
||||
#include "../testutils/MockConsole.h"
|
||||
#include "../../src/config/CryConfigLoader.h"
|
||||
|
||||
//TODO (whole project) Make constructors explicit when implicit construction not needed
|
||||
|
||||
@ -20,6 +21,7 @@ using cpputils::dynamic_pointer_move;
|
||||
using cpputils::make_unique_ref;
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::Console;
|
||||
using cpputils::Random;
|
||||
using blockstore::ondisk::OnDiskBlockStore;
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
@ -31,7 +33,7 @@ public:
|
||||
}
|
||||
|
||||
CryConfigFile loadOrCreateConfig() {
|
||||
return CryConfigLoader(mockConsole(), cpputils::Random::PseudoRandom()).loadOrCreate(config.path());
|
||||
return CryConfigLoader(mockConsole(), Random::PseudoRandom(), [] {return "mypassword";}).loadOrCreate(config.path());
|
||||
}
|
||||
|
||||
unique_ref<OnDiskBlockStore> blockStore() {
|
||||
|
@ -3,10 +3,12 @@
|
||||
#include <messmer/cpp-utils/tempfile/TempFile.h>
|
||||
|
||||
#include "../../src/filesystem/CryDevice.h"
|
||||
#include "../../src/config/CryConfigLoader.h"
|
||||
#include "../testutils/MockConsole.h"
|
||||
|
||||
using cpputils::unique_ref;
|
||||
using cpputils::make_unique_ref;
|
||||
using cpputils::Random;
|
||||
|
||||
using fspp::Device;
|
||||
using ::testing::Return;
|
||||
@ -24,7 +26,7 @@ public:
|
||||
|
||||
unique_ref<Device> createDevice() override {
|
||||
auto blockStore = cpputils::make_unique_ref<FakeBlockStore>();
|
||||
auto config = CryConfigLoader(mockConsole(), cpputils::Random::PseudoRandom())
|
||||
auto config = CryConfigLoader(mockConsole(), Random::PseudoRandom(), [] {return "mypassword";})
|
||||
.loadOrCreate(configFile.path());
|
||||
return make_unique_ref<CryDevice>(std::move(config), std::move(blockStore));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user