Config file is AES256_GCM encrypted, the config file key is generated with scrypt

This commit is contained in:
Sebastian Messmer 2015-10-24 19:35:37 +02:00
parent 7988cc406d
commit 371303ae6a
18 changed files with 335 additions and 80 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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:

View File

@ -0,0 +1 @@
#include "CryConfigEncryptor.h"

View 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

View File

@ -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() {

View File

@ -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);
};

View File

@ -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);
}
}

View File

@ -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);
};
}

View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -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());
}

View File

@ -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()));
}

View File

@ -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();

View File

@ -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);
}
};

View File

@ -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() {

View File

@ -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));
}