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)) { if (boost::filesystem::exists(path)) {
throw std::runtime_error("Config file exists already."); 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(); result.save();
return result; return result;
} }

View File

@ -13,26 +13,33 @@ namespace cryfs {
template<class Cipher> template<class Cipher>
class ConcreteInnerEncryptor: public InnerEncryptor { class ConcreteInnerEncryptor: public InnerEncryptor {
public: 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; cpputils::Data encrypt(const cpputils::Data &plaintext) const override;
boost::optional<cpputils::Data> decrypt(const cpputils::Data &ciphertext) const override; boost::optional<cpputils::Data> decrypt(const cpputils::Data &ciphertext) const override;
private: 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; typename Cipher::EncryptionKey _key;
}; };
template<class Cipher> 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> template<class Cipher>
boost::optional<cpputils::Data> ConcreteInnerEncryptor<Cipher>::decrypt(const cpputils::Data &ciphertext) const { 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) { if (decrypted == boost::none) {
return boost::none; return boost::none;
} }
@ -43,10 +50,43 @@ namespace cryfs {
return std::move(*configData); 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> template<class Cipher>
cpputils::Data ConcreteInnerEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) const { cpputils::Data ConcreteInnerEncryptor<Cipher>::encrypt(const cpputils::Data &plaintext) const {
auto paddedPlaintext = RandomPadding::add(plaintext, CONFIG_SIZE); 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 cpputils::Data;
using boost::optional; using boost::optional;
using boost::none; using boost::none;
using namespace cpputils::logging;
namespace cryfs { namespace cryfs {
const string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt"; const string CryConfigEncryptor::HEADER = "cryfs.config;0.8.1;scrypt";
@ -56,7 +57,7 @@ namespace cryfs {
deserializer.finished(); deserializer.finished();
return configData; return configData;
} catch (const std::exception &e) { } 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. 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 outerKey = derivedKey.key().take<OuterKeySize>();
auto innerKey = derivedKey.key().drop<OuterKeySize>(); auto innerKey = derivedKey.key().drop<OuterKeySize>();
return make_unique_ref<CryConfigEncryptor>( 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, outerKey,
derivedKey.moveOutConfig() derivedKey.moveOutConfig()
); );

View File

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