Config encryption: Prepend inner cipher name to the encrypted data before encrypting it with the outer cipher
This commit is contained in:
parent
d9eaac5f75
commit
08e4ae8a2e
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
);
|
||||
|
@ -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()
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user