Refactor folder structure and put classes in own files

This commit is contained in:
Sebastian Messmer 2015-10-26 18:14:27 +01:00
parent fd184b45d2
commit aceeb2644f
21 changed files with 240 additions and 179 deletions

View File

@ -1,5 +0,0 @@
#include "CryConfigEncryptor.h"
namespace cryfs {
const std::string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
}

View File

@ -1,159 +0,0 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGENCRYPTOR_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYCONFIGENCRYPTOR_H
#include <messmer/cpp-utils/data/Serializer.h>
#include <messmer/cpp-utils/data/Deserializer.h>
#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
class CryConfigEncryptor {
public:
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);
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);
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>
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>
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 cpputils::make_unique_ref<ConcreteCryConfigEncryptor<Cipher>>(std::move(key));
}
inline boost::optional<cpputils::unique_ref<CryConfigEncryptor>> CryConfigEncryptor::loadKey(const cpputils::Data &ciphertext, const std::string &password) {
cpputils::Deserializer deserializer(&ciphertext);
try {
_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.
}
}
inline void CryConfigEncryptor::_checkHeader(cpputils::Deserializer *deserializer) {
std::string header = deserializer->readString();
if (header != HEADER) {
throw std::runtime_error("Invalid header");
}
}
template<class Cipher>
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 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>
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.key());
if (decrypted == boost::none) {
throw std::runtime_error("Couldn't decrypt config file. Wrong password?");
}
auto configData = RandomPadding::remove(*decrypted);
if (configData == boost::none) {
throw std::runtime_error("Couldn't decrypt config file because of wrong padding");
}
return std::move(*configData);
}
template<class Cipher>
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 ConcreteCryConfigEncryptor<Cipher>::_serialize(const cpputils::Data &ciphertext) {
try {
cpputils::Serializer serializer(cpputils::Serializer::StringSize(HEADER)
+ _key.config().serializedSize()
+ cpputils::Serializer::DataSize(ciphertext));
serializer.writeString(HEADER);
_key.config().serialize(&serializer);
serializer.writeData(ciphertext);
return serializer.finished();
} catch (const std::exception &e) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing CryConfigEncryptor: " << e.what();
throw; // This is a programming logic error. Pass through exception.
}
}
}
#endif

View File

@ -2,8 +2,8 @@
#include <fstream>
#include <boost/filesystem.hpp>
#include <sstream>
#include "crypto/Scrypt.h"
#include <messmer/cpp-utils/logging/logging.h>
#include "crypto/CryConfigEncryptorFactory.h"
using boost::optional;
using boost::none;
@ -30,7 +30,7 @@ CryConfigFile CryConfigFile::create(const bf::path &path, CryConfig config, cons
if (bf::exists(path)) {
throw std::runtime_error("Config file exists already.");
}
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptor::deriveKey<ConfigCipher>(password));
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptorFactory::deriveKey<ConfigCipher>(password));
result.save();
return result;
}
@ -41,7 +41,7 @@ optional<CryConfigFile> CryConfigFile::load(const bf::path &path, const string &
LOG(ERROR) << "Config file not found";
return none;
}
auto encryptor = CryConfigEncryptor::loadKey(*encryptedConfigData, password);
auto encryptor = CryConfigEncryptorFactory::loadKey(*encryptedConfigData, password);
if (encryptor == none) {
return none;
}

View File

@ -5,7 +5,7 @@
#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
#include "CryConfig.h"
#include "CryConfigEncryptor.h"
#include "crypto/CryConfigEncryptor.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
namespace cryfs {

View File

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

View File

@ -0,0 +1,91 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CONCRETECRYCONFIGENCRYPTOR_H
#include <messmer/cpp-utils/data/Serializer.h>
#include <messmer/cpp-utils/data/Deserializer.h>
#include "RandomPadding.h"
#include "CryConfigEncryptor.h"
namespace cryfs {
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>
ConcreteCryConfigEncryptor<Cipher>::ConcreteCryConfigEncryptor(ConfigEncryptionKey key): _key(std::move(key)) {
}
template<class Cipher>
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.key());
if (decrypted == boost::none) {
throw std::runtime_error("Couldn't decrypt config file. Wrong password?");
}
auto configData = RandomPadding::remove(*decrypted);
if (configData == boost::none) {
throw std::runtime_error("Couldn't decrypt config file because of wrong padding");
}
return std::move(*configData);
}
template<class Cipher>
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 ConcreteCryConfigEncryptor<Cipher>::_serialize(const cpputils::Data &ciphertext) {
try {
cpputils::Serializer serializer(cpputils::Serializer::StringSize(HEADER)
+ _key.config().serializedSize()
+ cpputils::Serializer::DataSize(ciphertext));
writeHeader(&serializer);
_key.config().serialize(&serializer);
serializer.writeData(ciphertext);
return serializer.finished();
} catch (const std::exception &e) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing CryConfigEncryptor: " << e.what();
throw; // This is a programming logic error. Pass through exception.
}
}
}
#endif

View File

@ -0,0 +1,22 @@
#include "CryConfigEncryptor.h"
#include <messmer/cpp-utils/logging/logging.h>
using std::string;
using cpputils::Deserializer;
using cpputils::Serializer;
namespace cryfs {
const string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
void CryConfigEncryptor::checkHeader(Deserializer *deserializer) {
string header = deserializer->readString();
if (header != HEADER) {
throw std::runtime_error("Invalid header");
}
}
void CryConfigEncryptor::writeHeader(Serializer *serializer) {
serializer->writeString(HEADER);
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTOR_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTOR_H
#include <messmer/cpp-utils/data/Data.h>
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include <messmer/cpp-utils/data/Deserializer.h>
#include <messmer/cpp-utils/data/Serializer.h>
#include "kdf/DerivedKey.h"
#include <string>
#include <stdexcept>
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
class CryConfigEncryptor {
public:
virtual cpputils::Data encrypt(const cpputils::Data &plaintext) = 0;
virtual boost::optional <cpputils::Data> decrypt(const cpputils::Data &plaintext) = 0;
static void checkHeader(cpputils::Deserializer *deserializer);
static void writeHeader(cpputils::Serializer *serializer);
private:
template<class Cipher>
static DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> _loadKey(cpputils::Deserializer *deserializer,
const std::string &password);
static const std::string HEADER;
};
}
#endif

View File

@ -0,0 +1,41 @@
#include "CryConfigEncryptorFactory.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
using namespace cpputils::logging;
using boost::optional;
using boost::none;
using cpputils::unique_ref;
using cpputils::make_unique_ref;
using cpputils::Data;
using cpputils::Deserializer;
using std::string;
namespace cryfs {
template<class Cipher>
DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> CryConfigEncryptorFactory::_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 DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH>(std::move(keyConfig), std::move(key));
}
optional <unique_ref<CryConfigEncryptor>> CryConfigEncryptorFactory::loadKey(const Data &ciphertext,
const string &password) {
Deserializer deserializer(&ciphertext);
try {
CryConfigEncryptor::checkHeader(&deserializer);
auto key = _loadKey<blockstore::encrypted::AES256_GCM>(&deserializer, password); //TODO Allow other ciphers
return optional < unique_ref < CryConfigEncryptor >> (make_unique_ref < ConcreteCryConfigEncryptor <
blockstore::encrypted::AES256_GCM >>
(std::move(key))); //TODO Allow other ciphers
} catch (const std::exception &e) {
LOG(ERROR) << "Error loading configuration: " << e.what();
return none; // This can be caused by invalid loaded data and is not necessarily a programming logic error. Don't throw exception.
}
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTORFACTORY_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_CRYCONFIGENCRYPTORFACTORY_H
#include "ConcreteCryConfigEncryptor.h"
#include <messmer/cpp-utils/pointer/unique_ref.h>
#include "kdf/Scrypt.h"
namespace cryfs {
class CryConfigEncryptorFactory {
public:
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);
private:
template<class Cipher>
static DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> _loadKey(cpputils::Deserializer *deserializer,
const std::string &password);
};
template<class Cipher>
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;
return cpputils::make_unique_ref<ConcreteCryConfigEncryptor<Cipher>>(std::move(key));
}
}
#endif

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_PADDING_H
#define MESSMER_CRYFS_SRC_CONFIG_PADDING_H
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_PADDING_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_PADDING_H
#include <messmer/cpp-utils/data/Data.h>
#include <boost/optional.hpp>

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_DERIVEDKEY_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_DERIVEDKEY_H
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_DERIVEDKEY_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_DERIVEDKEY_H
#include <messmer/cpp-utils/data/FixedSizeData.h>
#include "DerivedKeyConfig.h"

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KEYCONFIG_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KEYCONFIG_H
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_KEYCONFIG_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_KEYCONFIG_H
#include <messmer/cpp-utils/data/Data.h>
#include <messmer/cpp-utils/data/Serializer.h>

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_SCRYPT_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_SCRYPT_H
#ifndef MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_SCRYPT_H
#define MESSMER_CRYFS_SRC_CONFIG_CRYPTO_KDF_SCRYPT_H
#include <messmer/cpp-utils/macros.h>
#include <messmer/cpp-utils/random/Random.h>

View File

@ -1,5 +1,5 @@
#include <google/gtest/gtest.h>
#include "../../../src/config/crypto/DerivedKeyConfig.h"
#include "../../../../src/config/crypto/kdf/DerivedKeyConfig.h"
#include <messmer/cpp-utils/data/DataFixture.h>
#include <sstream>

View File

@ -1,5 +1,5 @@
#include <google/gtest/gtest.h>
#include "../../../src/config/crypto/DerivedKey.h"
#include "../../../../src/config/crypto/kdf/DerivedKey.h"
#include <messmer/cpp-utils/data/DataFixture.h>
using namespace cryfs;

View File

@ -1,5 +1,5 @@
#include <google/gtest/gtest.h>
#include "../../../src/config/crypto/Scrypt.h"
#include "../../../../src/config/crypto/kdf/Scrypt.h"
using namespace cryfs;