Config encryption: Prepend inner cipher name to the encrypted data before encrypting it with the outer cipher

This commit is contained in:
Sebastian Messmer 2015-10-27 18:50:58 +01:00
parent d9eaac5f75
commit 08e4ae8a2e
5 changed files with 54 additions and 13 deletions

View File

@ -38,7 +38,7 @@ namespace cryfs {
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));
auto result = CryConfigFile(path, std::move(config), CryConfigEncryptorFactory::deriveKey<ConfigCipher, SCryptSettings>(password, "aes-256-gcm")); // TODO Take cipher from config instead
result.save();
return result;
}

View File

@ -13,26 +13,33 @@ namespace cryfs {
template<class Cipher>
class ConcreteInnerEncryptor: public InnerEncryptor {
public:
static constexpr size_t CONFIG_SIZE = 1024; // Config data is grown to this size before encryption to hide its actual size
static constexpr size_t CONFIG_SIZE = 512; // Config data is grown to this size before encryption to hide its actual size
ConcreteInnerEncryptor(typename Cipher::EncryptionKey key);
ConcreteInnerEncryptor(typename Cipher::EncryptionKey key, const std::string &cipherName);
cpputils::Data encrypt(const cpputils::Data &plaintext) const override;
boost::optional<cpputils::Data> decrypt(const cpputils::Data &ciphertext) const override;
private:
cpputils::Data _serialize(const cpputils::Data &data) const;
boost::optional<cpputils::Data> _deserialize(const cpputils::Data &data) const;
std::string _cipherName;
typename Cipher::EncryptionKey _key;
};
template<class Cipher>
ConcreteInnerEncryptor<Cipher>::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key): _key(std::move(key)) {
ConcreteInnerEncryptor<Cipher>::ConcreteInnerEncryptor(typename Cipher::EncryptionKey key, const std::string &cipherName)
: _cipherName(cipherName), _key(std::move(key)) {
}
template<class Cipher>
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::decrypt(const cpputils::Data &ciphertext) const {
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(), _key);
auto data = _deserialize(ciphertext);
if (data == boost::none) {
return boost::none;
}
auto decrypted = Cipher::decrypt(static_cast<const uint8_t*>(data->data()), data->size(), _key);
if (decrypted == boost::none) {
return boost::none;
}
@ -43,10 +50,43 @@ namespace cryfs {
return std::move(*configData);
}
template<class Cipher>
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::_deserialize(const cpputils::Data &ciphertext) const {
cpputils::Deserializer deserializer(&ciphertext);
try {
std::string readCipherName = deserializer.readString();
if (readCipherName != _cipherName) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Wrong inner cipher used";
return boost::none;
}
auto result = deserializer.readData();
deserializer.finished();
return result;
} catch (const std::exception &e) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing inner configuration: " << e.what();
return boost::none; // This can be caused by invalid input data and does not have to be a programming error. Don't throw exception.
}
}
template<class Cipher>
cpputils::Data ConcreteInnerEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) const {
auto paddedPlaintext = RandomPadding::add(plaintext, CONFIG_SIZE);
return Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), _key);
auto encrypted = Cipher::encrypt(static_cast<const uint8_t*>(paddedPlaintext.data()), paddedPlaintext.size(), _key);
return _serialize(encrypted);
}
template<class Cipher>
cpputils::Data ConcreteInnerEncryptor<Cipher>::_serialize(const cpputils::Data &ciphertext) const {
try {
cpputils::Serializer serializer(cpputils::Serializer::StringSize(_cipherName)
+ cpputils::Serializer::DataSize(ciphertext));
serializer.writeString(_cipherName);
serializer.writeData(ciphertext);
return serializer.finished();
} catch (const std::exception &e) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Error serializing inner configuration: " << e.what();
throw; // This is a programming logic error, pass through exception.
}
}
}

View File

@ -7,6 +7,7 @@ using cpputils::unique_ref;
using cpputils::Data;
using boost::optional;
using boost::none;
using namespace cpputils::logging;
namespace cryfs {
const string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
@ -56,7 +57,7 @@ namespace cryfs {
deserializer.finished();
return configData;
} catch (const std::exception &e) {
cpputils::logging::LOG(cpputils::logging::ERROR) << "Error loading configuration: " << e.what();
LOG(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.
}
}

View File

@ -24,7 +24,7 @@ namespace cryfs {
auto outerKey = derivedKey.key().take<OuterKeySize>();
auto innerKey = derivedKey.key().drop<OuterKeySize>();
return make_unique_ref<CryConfigEncryptor>(
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey),
make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey, "aes-256-gcm"), // TODO Allow other ciphers
outerKey,
derivedKey.moveOutConfig()
);

View File

@ -12,7 +12,7 @@ namespace cryfs {
class CryConfigEncryptorFactory {
public:
template<class Cipher, class SCryptConfig>
static cpputils::unique_ref<CryConfigEncryptor> deriveKey(const std::string &password);
static cpputils::unique_ref<CryConfigEncryptor> deriveKey(const std::string &password, const std::string &cipherName);
static boost::optional <cpputils::unique_ref<CryConfigEncryptor>> loadKey(const cpputils::Data &ciphertext,
const std::string &password);
@ -31,12 +31,12 @@ namespace cryfs {
}
template<class Cipher, class SCryptConfig>
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptorFactory::deriveKey(const std::string &password) {
cpputils::unique_ref<CryConfigEncryptor> CryConfigEncryptorFactory::deriveKey(const std::string &password, const std::string &cipherName) {
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>>(innerKey),
cpputils::make_unique_ref<ConcreteInnerEncryptor<Cipher>>(innerKey, cipherName),
outerKey,
derivedKey.moveOutConfig()
);