Make SCrypt config modifiable and speed up test cases by using a special test config

This commit is contained in:
Sebastian Messmer 2015-10-27 13:28:42 +01:00
parent ed390108f4
commit 88262c3ef9
14 changed files with 118 additions and 62 deletions

View File

@ -8,7 +8,7 @@
messmer/cmake: 3
messmer/cpp-utils: 4
messmer/fspp: 1
messmer/gitversion: 5
messmer/gitversion: 6
messmer/parallelaccessstore: 1
messmer/scrypt: 0

View File

@ -3,7 +3,6 @@
#include <boost/filesystem.hpp>
#include <sstream>
#include <messmer/cpp-utils/logging/logging.h>
#include "crypto/CryConfigEncryptorFactory.h"
using boost::optional;
using boost::none;
@ -25,16 +24,6 @@ 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 result = CryConfigFile(path, std::move(config), CryConfigEncryptorFactory::deriveKey<ConfigCipher>(password));
result.save();
return result;
}
optional<CryConfigFile> CryConfigFile::load(const bf::path &path, const string &password) {
auto encryptedConfigData = Data::LoadFromFile(path);
if (encryptedConfigData == none) {

View File

@ -3,10 +3,11 @@
#define MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGFILE_H
#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include "CryConfig.h"
#include "crypto/CryConfigEncryptor.h"
#include "crypto/kdf/Scrypt.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
#include "crypto/CryConfigEncryptorFactory.h"
namespace cryfs {
class CryConfigFile final {
@ -14,6 +15,7 @@ namespace cryfs {
CryConfigFile(CryConfigFile &&rhs) = default;
~CryConfigFile();
template<class SCryptConfig>
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;
@ -29,6 +31,17 @@ namespace cryfs {
DISALLOW_COPY_AND_ASSIGN(CryConfigFile);
};
template<class SCryptSettings>
CryConfigFile CryConfigFile::create(const boost::filesystem::path &path, CryConfig config, const std::string &password) {
using ConfigCipher = blockstore::encrypted::AES256_GCM; // TODO Take cipher from config instead
if (boost::filesystem::exists(path)) {
throw std::runtime_error("Config file exists already.");
}
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptorFactory::deriveKey<ConfigCipher, SCryptSettings>(password));
result.save();
return result;
}
}
#endif

View File

@ -24,14 +24,6 @@ CryConfigLoader::CryConfigLoader(unique_ref<Console> console, RandomGenerator &k
: _creator(std::move(console), keyGenerator), _askPassword(askPassword) {
}
optional<CryConfigFile> CryConfigLoader::loadOrCreate(const bf::path &filename) {
if (bf::exists(filename)) {
return _loadConfig(filename);
} else {
return _createConfig(filename);
}
}
optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
string password = _askPassword();
auto config = CryConfigFile::load(filename, password);
@ -42,11 +34,4 @@ optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
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

@ -3,10 +3,11 @@
#define MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGLOADER_H_
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include "CryConfigFile.h"
#include "CryCipher.h"
#include "CryConfigCreator.h"
#include "crypto/kdf/Scrypt.h"
namespace cryfs {
@ -15,10 +16,12 @@ public:
CryConfigLoader(cpputils::unique_ref<cpputils::Console> console, cpputils::RandomGenerator &keyGenerator, std::function<std::string()> askPassword);
CryConfigLoader(CryConfigLoader &&rhs) = default;
template<class SCryptSettings = SCryptDefaultSettings>
boost::optional<CryConfigFile> loadOrCreate(const boost::filesystem::path &filename);
private:
boost::optional<CryConfigFile> _loadConfig(const boost::filesystem::path &filename);
template<class SCryptSettings>
CryConfigFile _createConfig(const boost::filesystem::path &filename);
CryConfigCreator _creator;
@ -27,6 +30,23 @@ private:
DISALLOW_COPY_AND_ASSIGN(CryConfigLoader);
};
template<class SCryptSettings>
boost::optional<CryConfigFile> CryConfigLoader::loadOrCreate(const boost::filesystem::path &filename) {
if (boost::filesystem::exists(filename)) {
return _loadConfig(filename);
} else {
return _createConfig<SCryptSettings>(filename);
}
}
template<class SCryptSettings>
CryConfigFile CryConfigLoader::_createConfig(const boost::filesystem::path &filename) {
auto config = _creator.create();
//TODO Ask confirmation if using insecure password (<8 characters)
std::string password = _askPassword();
return CryConfigFile::create<SCryptSettings>(filename, std::move(config), password);
}
}
#endif

View File

@ -10,7 +10,7 @@ namespace cryfs {
//TODO Test
class CryConfigEncryptorFactory {
public:
template<class Cipher>
template<class Cipher, class SCryptConfig>
static cpputils::unique_ref <CryConfigEncryptor> deriveKey(const std::string &password);
static boost::optional <cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext,
@ -22,12 +22,9 @@ namespace cryfs {
const std::string &password);
};
template<class Cipher>
template<class Cipher, class SCryptConfig>
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptorFactory::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;
auto key = SCrypt().generateKey<Cipher::EncryptionKey::BINARY_LENGTH, SCryptConfig>(password);
return cpputils::make_unique_ref<ConcreteCryConfigEncryptor<Cipher>>(std::move(key));
}
}

View File

@ -1,8 +1,13 @@
#include "Scrypt.h"
namespace cryfs {
constexpr size_t SCrypt::SALT_LEN;
constexpr uint64_t SCrypt::N;
constexpr uint32_t SCrypt::r;
constexpr uint32_t SCrypt::p;
constexpr size_t SCryptDefaultSettings::SALT_LEN;
constexpr uint64_t SCryptDefaultSettings::N;
constexpr uint32_t SCryptDefaultSettings::r;
constexpr uint32_t SCryptDefaultSettings::p;
constexpr size_t SCryptParanoidSettings::SALT_LEN;
constexpr uint64_t SCryptParanoidSettings::N;
constexpr uint32_t SCryptParanoidSettings::r;
constexpr uint32_t SCryptParanoidSettings::p;
}

View File

@ -12,19 +12,27 @@ extern "C" {
namespace cryfs {
class SCrypt {
public:
//TODO Make user-configurable. For sensitive storage, N=1048576, r=8 is recommended. For tests, we should use faster settings.
struct SCryptParanoidSettings {
constexpr static size_t SALT_LEN = 32; // Size of the salt
constexpr static uint64_t N = 1048576; // CPU/Memory cost
constexpr static uint32_t r = 8; // Blocksize
constexpr static uint32_t p = 16; // Parallelization
};
struct SCryptDefaultSettings {
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
constexpr static uint32_t p = 1; // Parallelization
};
class SCrypt {
public:
SCrypt() {}
template<size_t KEYSIZE> DerivedKey<KEYSIZE> generateKey(const std::string &password) {
auto salt = cpputils::Random::PseudoRandom().get(SALT_LEN);
auto config = DerivedKeyConfig(std::move(salt), N, r, p);
template<size_t KEYSIZE, class Settings = SCryptDefaultSettings> DerivedKey<KEYSIZE> generateKey(const std::string &password) {
auto salt = cpputils::Random::PseudoRandom().get(Settings::SALT_LEN);
auto config = DerivedKeyConfig(std::move(salt), Settings::N, Settings::r, Settings::p);
auto key = generateKeyFromConfig<KEYSIZE>(password, config);
return DerivedKey<KEYSIZE>(std::move(config), key);
}

View File

@ -91,7 +91,9 @@ CryConfigFile loadOrCreateConfig(const ProgramOptions &options) {
auto configFile = determineConfigFile(options);
auto console = make_unique_ref<IOStreamConsole>();
auto &keyGenerator = Random::OSRandom();
std::cout << "Loading config file..." << std::flush;
auto config = CryConfigLoader(std::move(console), keyGenerator, &askPassword).loadOrCreate(configFile);
std::cout << "done" << std::endl;
if (config == none) {
std::cerr << "Could not load config file. Did you enter the correct password?" << std::endl;
exit(1);

View File

@ -3,6 +3,7 @@
#include "../../src/config/CryConfigFile.h"
#include <messmer/cpp-utils/tempfile/TempFile.h>
#include <boost/optional/optional_io.hpp>
#include "testutils/SCryptTestSettings.h"
using namespace cryfs;
using cpputils::TempFile;
@ -32,7 +33,7 @@ public:
}
void Create(CryConfig cfg, const string &password = "mypassword") {
CryConfigFile::create(file.path(), std::move(cfg), password);
CryConfigFile::create<SCryptTestSettings>(file.path(), std::move(cfg), password);
}
optional<CryConfigFile> Load(const string &password = "mypassword") {
@ -42,7 +43,7 @@ public:
void CreateWithCipher(const string &cipher, const TempFile &tempFile) {
CryConfig cfg;
cfg.SetCipher(cipher);
CryConfigFile::create(tempFile.path(), std::move(cfg), "mypassword");
CryConfigFile::create<SCryptTestSettings>(tempFile.path(), std::move(cfg), "mypassword");
}
};

View File

@ -4,6 +4,7 @@
#include <messmer/cpp-utils/tempfile/TempFile.h>
#include <messmer/cpp-utils/random/Random.h>
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
#include "testutils/SCryptTestSettings.h"
using cpputils::unique_ref;
using cpputils::make_unique_ref;
@ -26,28 +27,28 @@ public:
CryConfigFile Create(const string &password = "mypassword") {
EXPECT_FALSE(file.exists());
return loader(password).loadOrCreate(file.path()).value();
return loader(password).loadOrCreate<SCryptTestSettings>(file.path()).value();
}
optional<CryConfigFile> Load(const string &password = "mypassword") {
EXPECT_TRUE(file.exists());
return loader(password).loadOrCreate(file.path());
return loader(password).loadOrCreate<SCryptTestSettings>(file.path());
}
void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") {
auto cfg = loader(password).loadOrCreate(file.path()).value();
auto cfg = loader(password).loadOrCreate<SCryptTestSettings>(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()).value();
auto cfg = loader(password).loadOrCreate<SCryptTestSettings>(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()).value();
auto cfg = loader(password).loadOrCreate<SCryptTestSettings>(file.path()).value();
cfg.config()->SetEncryptionKey(encKey);
cfg.save();
}

View File

@ -1,36 +1,51 @@
#include <google/gtest/gtest.h>
#include "../../../../src/config/crypto/kdf/Scrypt.h"
#include "../../testutils/SCryptTestSettings.h"
using namespace cryfs;
TEST(SCryptTest, GeneratedKeyIsReproductible_448) {
auto created = SCrypt().generateKey<56>("mypassword");
auto created = SCrypt().generateKey<56, SCryptTestSettings>("mypassword");
auto recreated = SCrypt().generateKeyFromConfig<56>("mypassword", created.config());
EXPECT_EQ(created.key(), recreated);
}
TEST(SCryptTest, GeneratedKeyIsReproductible_256) {
auto created = SCrypt().generateKey<32>("mypassword");
auto created = SCrypt().generateKey<32, SCryptTestSettings>("mypassword");
auto recreated = SCrypt().generateKeyFromConfig<32>("mypassword", created.config());
EXPECT_EQ(created.key(), recreated);
}
TEST(SCryptTest, GeneratedKeyIsReproductible_128) {
auto created = SCrypt().generateKey<16, SCryptTestSettings>("mypassword");
auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword", created.config());
EXPECT_EQ(created.key(), recreated);
}
TEST(SCryptTest, GeneratedKeyIsReproductible_DefaultSettings) {
auto created = SCrypt().generateKey<16>("mypassword");
auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword", created.config());
EXPECT_EQ(created.key(), recreated);
}
TEST(SCryptTest, DifferentPasswordResultsInDifferentKey) {
auto created = SCrypt().generateKey<16>("mypassword");
auto created = SCrypt().generateKey<16, SCryptTestSettings>("mypassword");
auto recreated = SCrypt().generateKeyFromConfig<16>("mypassword2", created.config());
EXPECT_NE(created.key(), recreated);
}
TEST(SCryptTest, UsesCorrectDefaultParameters) {
auto created = SCrypt().generateKey<16>("mypassword");
EXPECT_EQ(SCrypt::SALT_LEN, created.config().salt().size());
EXPECT_EQ(SCrypt::N, created.config().N());
EXPECT_EQ(SCrypt::r, created.config().r());
EXPECT_EQ(SCrypt::p, created.config().p());
TEST(SCryptTest, UsesCorrectSettings) {
auto created = SCrypt().generateKey<16, SCryptTestSettings>("mypassword");
EXPECT_EQ(SCryptTestSettings::SALT_LEN, created.config().salt().size());
EXPECT_EQ(SCryptTestSettings::N, created.config().N());
EXPECT_EQ(SCryptTestSettings::r, created.config().r());
EXPECT_EQ(SCryptTestSettings::p, created.config().p());
}
TEST(SCryptTest, UsesCorrectDefaultSettings) {
auto created = SCrypt().generateKey<16>("mypassword");
EXPECT_EQ(SCryptDefaultSettings::SALT_LEN, created.config().salt().size());
EXPECT_EQ(SCryptDefaultSettings::N, created.config().N());
EXPECT_EQ(SCryptDefaultSettings::r, created.config().r());
EXPECT_EQ(SCryptDefaultSettings::p, created.config().p());
}

View File

@ -0,0 +1,6 @@
#include "SCryptTestSettings.h"
constexpr size_t SCryptTestSettings::SALT_LEN;
constexpr uint64_t SCryptTestSettings::N;
constexpr uint32_t SCryptTestSettings::r;
constexpr uint32_t SCryptTestSettings::p;

View File

@ -0,0 +1,14 @@
#ifndef MESSMER_CRYFS_TEST_CONFIG_CRYPTO_TESTUTILS_SCRYPTTESTSETTINGS_H
#define MESSMER_CRYFS_TEST_CONFIG_CRYPTO_TESTUTILS_SCRYPTTESTSETTINGS_H
#include <cstddef>
#include <cstdint>
struct SCryptTestSettings {
constexpr static size_t SALT_LEN = 32; // Size of the salt
constexpr static uint64_t N = 1024; // CPU/Memory cost
constexpr static uint32_t r = 1; // Blocksize
constexpr static uint32_t p = 1; // Parallelization
};
#endif