Encrypt config file twice - with an inner and an outer key

This commit is contained in:
Sebastian Messmer 2015-10-27 17:33:31 +01:00
parent 635349d636
commit d9eaac5f75
4 changed files with 48 additions and 23 deletions

View File

@ -11,8 +11,8 @@ using boost::none;
namespace cryfs {
const string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
CryConfigEncryptor::CryConfigEncryptor(unique_ref<InnerEncryptor> innerEncryptor, DerivedKeyConfig keyConfig)
: _innerEncryptor(std::move(innerEncryptor)), _keyConfig(std::move(keyConfig)) {
CryConfigEncryptor::CryConfigEncryptor(unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, DerivedKeyConfig keyConfig)
: _innerEncryptor(std::move(innerEncryptor)), _outerKey(std::move(outerKey)), _keyConfig(std::move(keyConfig)) {
}
void CryConfigEncryptor::checkHeader(Deserializer *deserializer) {
@ -27,7 +27,8 @@ namespace cryfs {
}
Data CryConfigEncryptor::encrypt(const Data &plaintext) {
auto ciphertext = _innerEncryptor->encrypt(plaintext);
auto inner = _innerEncryptor->encrypt(plaintext);
auto ciphertext = OuterCipher::encrypt(static_cast<const uint8_t*>(inner.data()), inner.size(), _outerKey);
return _serialize(ciphertext);
}
@ -66,6 +67,10 @@ namespace cryfs {
optional<Data> CryConfigEncryptor::_loadAndDecryptConfigData(Deserializer *deserializer) {
auto ciphertext = deserializer->readData();
return _innerEncryptor->decrypt(ciphertext);
auto inner = OuterCipher::decrypt(static_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(), _outerKey);
if(inner == none) {
return none;
}
return _innerEncryptor->decrypt(*inner);
}
}

View File

@ -7,6 +7,7 @@
#include <messmer/cpp-utils/data/Serializer.h>
#include "InnerEncryptor.h"
#include "kdf/DerivedKeyConfig.h"
#include <messmer/blockstore/implementations/encrypted/ciphers/ciphers.h>
namespace cryfs {
//TODO Test
@ -15,7 +16,9 @@ namespace cryfs {
//TODO Use own exception for cpputils::Serializer/cpputils::Deserializer errors and only catch them
class CryConfigEncryptor {
public:
CryConfigEncryptor(cpputils::unique_ref<InnerEncryptor> innerEncryptor, DerivedKeyConfig keyConfig);
using OuterCipher = blockstore::encrypted::AES256_GCM;
CryConfigEncryptor(cpputils::unique_ref<InnerEncryptor> innerEncryptor, OuterCipher::EncryptionKey outerKey, DerivedKeyConfig keyConfig);
cpputils::Data encrypt(const cpputils::Data &plaintext);
boost::optional <cpputils::Data> decrypt(const cpputils::Data &plaintext);
@ -29,6 +32,7 @@ namespace cryfs {
cpputils::Data _serialize(const cpputils::Data &ciphertext);
cpputils::unique_ref<InnerEncryptor> _innerEncryptor;
OuterCipher::EncryptionKey _outerKey;
DerivedKeyConfig _keyConfig;
static const std::string HEADER;

View File

@ -12,26 +12,21 @@ 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));
}
constexpr size_t CryConfigEncryptorFactory::OuterKeySize;
optional<unique_ref<CryConfigEncryptor>> CryConfigEncryptorFactory::loadKey(const Data &ciphertext,
const string &password) {
using Cipher = blockstore::encrypted::AES256_GCM; //TODO Allow other ciphers
Deserializer deserializer(&ciphertext);
try {
CryConfigEncryptor::checkHeader(&deserializer);
auto key = _loadKey<blockstore::encrypted::AES256_GCM>(&deserializer, password); //TODO Allow other ciphers
auto derivedKey = _loadKey<Cipher>(&deserializer, password);
auto outerKey = derivedKey.key().take<OuterKeySize>();
auto innerKey = derivedKey.key().drop<OuterKeySize>();
return make_unique_ref<CryConfigEncryptor>(
make_unique_ref<ConcreteInnerEncryptor<blockstore::encrypted::AES256_GCM>>(key.moveOutKey()), //TODO Allow other ciphers
key.moveOutConfig()
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
outerKey,
derivedKey.moveOutConfig()
);
} catch (const std::exception &e) {
LOG(ERROR) << "Error loading configuration: " << e.what();

View File

@ -18,19 +18,40 @@ namespace cryfs {
const std::string &password);
private:
static constexpr size_t OuterKeySize = CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH;
template<class Cipher> static constexpr size_t TotalKeySize();
template<class Cipher>
static DerivedKey<Cipher::EncryptionKey::BINARY_LENGTH> _loadKey(cpputils::Deserializer *deserializer,
const std::string &password);
static DerivedKey<CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH + Cipher::EncryptionKey::BINARY_LENGTH>
_loadKey(cpputils::Deserializer *deserializer, const std::string &password);
};
template<class Cipher> constexpr size_t CryConfigEncryptorFactory::TotalKeySize() {
return OuterKeySize + Cipher::EncryptionKey::BINARY_LENGTH;
}
template<class Cipher, class SCryptConfig>
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptorFactory::deriveKey(const std::string &password) {
auto key = SCrypt().generateKey<Cipher::EncryptionKey::BINARY_LENGTH, SCryptConfig>(password);
auto derivedKey = SCrypt().generateKey<TotalKeySize<Cipher>(), SCryptConfig>(password);
auto outerKey = derivedKey.key().template take<OuterKeySize>();
auto innerKey = derivedKey.key().template drop<OuterKeySize>();
return cpputils::make_unique_ref<CryConfigEncryptor>(
cpputils::make_unique_ref<ConcreteInnerEncryptor<Cipher>>(key.moveOutKey()),
key.moveOutConfig()
cpputils::make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
outerKey,
derivedKey.moveOutConfig()
);
}
template<class Cipher>
DerivedKey<CryConfigEncryptor::OuterCipher::EncryptionKey::BINARY_LENGTH + 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<TotalKeySize<Cipher>()>(password, keyConfig);
std::cout << "done" << std::endl;
return DerivedKey<TotalKeySize<Cipher>()>(std::move(keyConfig), std::move(key));
}
}
#endif