CryFS tells the operating system to not swap the encryption key to the disk (note: this is best-effort and cannot be guaranteed. Hibernation, for example, will still write the encryption key to the disk)
This commit is contained in:
parent
06e8fc15d4
commit
7e56c46bb0
@ -1,14 +1,13 @@
|
||||
Version 0.10.0 (unreleased)
|
||||
---------------
|
||||
New Features:
|
||||
New Features & Improvements:
|
||||
* Integrity checks ensure you notice when someone modifies your file system.
|
||||
* File system nodes (files, directories, symlinks) store a parent pointer to the directory that contains them. This information can be used in later versions to resolve some synchronization conflicts.
|
||||
* Allow mounting using system mount tool and /etc/fstab (e.g. mount -t fuse.cryfs basedir mountdir)
|
||||
|
||||
Improvements:
|
||||
* Performance improvements
|
||||
* Use relatime instead of strictatime (further performance improvement)
|
||||
* Pass fuse options directly to cryfs (i.e. 'cryfs basedir mountdir -o allow_other' instead of 'cryfs basedir mountdir -- -o allow_other')
|
||||
* CryFS tells the operating system to not swap the encryption key to the disk (note: this is best-effort and cannot be guaranteed. Hibernation, for example, will still write the encryption key to the disk)
|
||||
|
||||
Fixed bugs:
|
||||
* `du` shows correct file system size on Mac OS X.
|
||||
|
@ -6,6 +6,7 @@ set(SOURCES
|
||||
crypto/kdf/SCryptParameters.cpp
|
||||
crypto/kdf/PasswordBasedKDF.cpp
|
||||
crypto/RandomPadding.cpp
|
||||
crypto/symmetric/EncryptionKey.cpp
|
||||
process/daemonize.cpp
|
||||
process/subprocess.cpp
|
||||
tempfile/TempFile.cpp
|
||||
@ -37,6 +38,7 @@ set(SOURCES
|
||||
assert/AssertFailed.cpp
|
||||
system/get_total_memory.cpp
|
||||
system/homedir.cpp
|
||||
system/memory.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
|
@ -9,17 +9,14 @@
|
||||
#include <boost/optional.hpp>
|
||||
#include <cryptopp/modes.h>
|
||||
#include "Cipher.h"
|
||||
#include "EncryptionKey.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
template<typename BlockCipher, unsigned int KeySize>
|
||||
class CFB_Cipher {
|
||||
public:
|
||||
using EncryptionKey = FixedSizeData<KeySize>;
|
||||
|
||||
static EncryptionKey CreateKey(RandomGenerator &randomGenerator) {
|
||||
return randomGenerator.getFixedSize<EncryptionKey::BINARY_LENGTH>();
|
||||
}
|
||||
using EncryptionKey = cpputils::EncryptionKey<KeySize>;
|
||||
|
||||
static constexpr unsigned int ciphertextSize(unsigned int plaintextBlockSize) {
|
||||
return plaintextBlockSize + IV_SIZE;
|
||||
@ -39,7 +36,7 @@ private:
|
||||
template<typename BlockCipher, unsigned int KeySize>
|
||||
Data CFB_Cipher<BlockCipher, KeySize>::encrypt(const CryptoPP::byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) {
|
||||
FixedSizeData<IV_SIZE> iv = Random::PseudoRandom().getFixedSize<IV_SIZE>();
|
||||
auto encryption = typename CryptoPP::CFB_Mode<BlockCipher>::Encryption(encKey.data(), encKey.BINARY_LENGTH, iv.data());
|
||||
auto encryption = typename CryptoPP::CFB_Mode<BlockCipher>::Encryption((CryptoPP::byte*)encKey.data(), encKey.BINARY_LENGTH, iv.data());
|
||||
Data ciphertext(ciphertextSize(plaintextSize));
|
||||
std::memcpy(ciphertext.data(), iv.data(), IV_SIZE);
|
||||
encryption.ProcessData((CryptoPP::byte*)ciphertext.data() + IV_SIZE, plaintext, plaintextSize);
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
BOOST_CONCEPT_USAGE(CipherConcept) {
|
||||
same_type(UINT32_C(0), X::ciphertextSize(UINT32_C(5)));
|
||||
same_type(UINT32_C(0), X::plaintextSize(UINT32_C(5)));
|
||||
typename X::EncryptionKey key = X::CreateKey(Random::OSRandom());
|
||||
typename X::EncryptionKey key = X::EncryptionKey::CreateKey(Random::OSRandom());
|
||||
same_type(Data(0), X::encrypt((uint8_t*)nullptr, UINT32_C(0), key));
|
||||
same_type(boost::optional<Data>(Data(0)), X::decrypt((uint8_t*)nullptr, UINT32_C(0), key));
|
||||
string name = X::NAME;
|
||||
|
1
src/cpp-utils/crypto/symmetric/EncryptionKey.cpp
Normal file
1
src/cpp-utils/crypto/symmetric/EncryptionKey.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "EncryptionKey.h"
|
107
src/cpp-utils/crypto/symmetric/EncryptionKey.h
Normal file
107
src/cpp-utils/crypto/symmetric/EncryptionKey.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_CRYPTO_SYMMETRIC_ENCRYPTIONKEY_H_
|
||||
#define MESSMER_CPPUTILS_CRYPTO_SYMMETRIC_ENCRYPTIONKEY_H_
|
||||
|
||||
#include <cpp-utils/data/FixedSizeData.h>
|
||||
#include <memory>
|
||||
#include <cpp-utils/system/memory.h>
|
||||
#include "../cryptopp_byte.h"
|
||||
#include <cpp-utils/random/RandomGenerator.h>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
/**
|
||||
* Use this to store an encryption key and keep it safe in memory.
|
||||
* It will only keep the key in one memory location, even if the EncryptionKey object is copied or moved.
|
||||
* This one memory location will be prevented from swapping to disk.
|
||||
* Note: This is a best-effort, but not a guarantee. System hibernation might still write the encryption key to the disk.
|
||||
* Also, when (de)serializing the config file or calling a crypto library with the encryption key, it isn't guaranteed
|
||||
* that there aren't any copies made to different memory regions. However, these other memory regions should be short-lived
|
||||
* and therefore much less likely to swap.
|
||||
*/
|
||||
template<size_t KeySize>
|
||||
class EncryptionKey final {
|
||||
private:
|
||||
struct EncryptionKeyData final {
|
||||
public:
|
||||
constexpr static size_t BINARY_LENGTH = FixedSizeData<KeySize>::BINARY_LENGTH;
|
||||
constexpr static size_t STRING_LENGTH = FixedSizeData<KeySize>::STRING_LENGTH;
|
||||
|
||||
EncryptionKeyData(const FixedSizeData<KeySize >& keyData);
|
||||
~EncryptionKeyData();
|
||||
|
||||
// Disallow copying and moving
|
||||
EncryptionKeyData(const EncryptionKeyData &rhs) = delete;
|
||||
EncryptionKeyData(EncryptionKeyData &&rhs) = delete;
|
||||
EncryptionKeyData &operator=(const EncryptionKeyData &rhs) = delete;
|
||||
EncryptionKeyData &operator=(EncryptionKeyData &&rhs) = delete;
|
||||
|
||||
FixedSizeData<KeySize> key;
|
||||
DontSwapMemoryRAII memoryProtector; // this makes sure that the key data isn't swapped to disk
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr static size_t BINARY_LENGTH = EncryptionKeyData::BINARY_LENGTH;
|
||||
constexpr static size_t STRING_LENGTH = EncryptionKeyData::STRING_LENGTH;
|
||||
|
||||
EncryptionKey(const FixedSizeData<KeySize>& keyData);
|
||||
|
||||
static EncryptionKey FromBinary(const void *source);
|
||||
static EncryptionKey FromString(const std::string& keyData);
|
||||
std::string ToString() const;
|
||||
|
||||
static EncryptionKey CreateKey(RandomGenerator &randomGenerator) {
|
||||
EncryptionKey result(FixedSizeData<BINARY_LENGTH>::Null());
|
||||
randomGenerator.write(result._key->key.data(), BINARY_LENGTH);
|
||||
return result;
|
||||
}
|
||||
|
||||
const void *data() const {
|
||||
return _key->key.data();
|
||||
}
|
||||
|
||||
void *data() {
|
||||
return const_cast<void*>(const_cast<const EncryptionKey*>(this)->data());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<EncryptionKeyData> _key;
|
||||
};
|
||||
|
||||
template<size_t KeySize>
|
||||
inline EncryptionKey<KeySize>::EncryptionKeyData::EncryptionKeyData(const FixedSizeData<KeySize>& keyData)
|
||||
: key(keyData)
|
||||
, memoryProtector(&key, sizeof(key)) {
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
inline EncryptionKey<KeySize>::EncryptionKeyData::~EncryptionKeyData() {
|
||||
// After destruction, the swap-protection is lifted, but we also don't need the key data anymore.
|
||||
// Overwrite it with zeroes.
|
||||
std::memset(key.data(), 0, KeySize);
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
inline EncryptionKey<KeySize>::EncryptionKey(const FixedSizeData<KeySize>& keyData)
|
||||
: _key(std::make_shared<EncryptionKeyData>(keyData)) {
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
EncryptionKey<KeySize> EncryptionKey<KeySize>::FromBinary(const void *source) {
|
||||
return EncryptionKey(FixedSizeData<KeySize>::FromBinary(source));
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
EncryptionKey<KeySize> EncryptionKey<KeySize>::FromString(const std::string& keyData) {
|
||||
return EncryptionKey(FixedSizeData<KeySize>::FromString(keyData));
|
||||
}
|
||||
|
||||
template<size_t KeySize>
|
||||
std::string EncryptionKey<KeySize>::ToString() const {
|
||||
return _key->key.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -8,17 +8,14 @@
|
||||
#include "../../random/Random.h"
|
||||
#include <cryptopp/gcm.h>
|
||||
#include "Cipher.h"
|
||||
#include "EncryptionKey.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
template<typename BlockCipher, unsigned int KeySize>
|
||||
class GCM_Cipher {
|
||||
public:
|
||||
using EncryptionKey = FixedSizeData<KeySize>;
|
||||
|
||||
static EncryptionKey CreateKey(RandomGenerator &randomGenerator) {
|
||||
return randomGenerator.getFixedSize<EncryptionKey::BINARY_LENGTH>();
|
||||
}
|
||||
using EncryptionKey = cpputils::EncryptionKey<KeySize>;
|
||||
|
||||
static constexpr unsigned int ciphertextSize(unsigned int plaintextBlockSize) {
|
||||
return plaintextBlockSize + IV_SIZE + TAG_SIZE;
|
||||
@ -40,7 +37,7 @@ template<typename BlockCipher, unsigned int KeySize>
|
||||
Data GCM_Cipher<BlockCipher, KeySize>::encrypt(const CryptoPP::byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) {
|
||||
FixedSizeData<IV_SIZE> iv = Random::PseudoRandom().getFixedSize<IV_SIZE>();
|
||||
typename CryptoPP::GCM<BlockCipher, CryptoPP::GCM_64K_Tables>::Encryption encryption;
|
||||
encryption.SetKeyWithIV(encKey.data(), encKey.BINARY_LENGTH, iv.data(), IV_SIZE);
|
||||
encryption.SetKeyWithIV((CryptoPP::byte*)encKey.data(), encKey.BINARY_LENGTH, iv.data(), IV_SIZE);
|
||||
Data ciphertext(ciphertextSize(plaintextSize));
|
||||
|
||||
std::memcpy(ciphertext.data(), iv.data(), IV_SIZE);
|
||||
|
@ -12,6 +12,8 @@ namespace cpputils {
|
||||
template<size_t SIZE> FixedSizeData<SIZE> getFixedSize();
|
||||
Data get(size_t size);
|
||||
|
||||
void write(void *target, size_t size);
|
||||
|
||||
protected:
|
||||
virtual void _get(void *target, size_t bytes) = 0;
|
||||
private:
|
||||
@ -23,6 +25,10 @@ namespace cpputils {
|
||||
inline RandomGenerator::RandomGenerator() {
|
||||
}
|
||||
|
||||
inline void RandomGenerator::write(void *target, size_t size) {
|
||||
_get(target, size);
|
||||
}
|
||||
|
||||
template<size_t SIZE> inline FixedSizeData<SIZE> RandomGenerator::getFixedSize() {
|
||||
FixedSizeData<SIZE> result = FixedSizeData<SIZE>::Null();
|
||||
_get(result.data(), SIZE);
|
||||
|
26
src/cpp-utils/system/memory.cpp
Normal file
26
src/cpp-utils/system/memory.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "memory.h"
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <stdexcept>
|
||||
#include <cpp-utils/logging/logging.h>
|
||||
|
||||
using namespace cpputils::logging;
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
DontSwapMemoryRAII::DontSwapMemoryRAII(const void *addr, size_t len)
|
||||
: addr_(addr), len_(len) {
|
||||
const int result = ::mlock(addr_, len_);
|
||||
if (0 != result) {
|
||||
throw std::runtime_error("Error calling mlock. Errno: " + std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
DontSwapMemoryRAII::~DontSwapMemoryRAII() {
|
||||
const int result = ::munlock(addr_, len_);
|
||||
if (0 != result) {
|
||||
LOG(WARN, "Error calling munlock. Errno: {}", errno);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
23
src/cpp-utils/system/memory.h
Normal file
23
src/cpp-utils/system/memory.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_SYSTEM_MEMORY_H
|
||||
#define MESSMER_CPPUTILS_SYSTEM_MEMORY_H
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
// While this RAII object exists, it locks a given memory address into RAM,
|
||||
// i.e. tells the operating system not to swap it.
|
||||
class DontSwapMemoryRAII final {
|
||||
public:
|
||||
DontSwapMemoryRAII(const void* addr, size_t len);
|
||||
~DontSwapMemoryRAII();
|
||||
|
||||
private:
|
||||
const void* addr_;
|
||||
const size_t len_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -44,7 +44,7 @@ public:
|
||||
}
|
||||
|
||||
string createKey(cpputils::RandomGenerator &randomGenerator) const override {
|
||||
return Cipher::CreateKey(randomGenerator).ToString();
|
||||
return Cipher::EncryptionKey::CreateKey(randomGenerator).ToString();
|
||||
}
|
||||
|
||||
unique_ref<InnerEncryptor> createInnerConfigEncryptor(const FixedSizeData<CryCiphers::MAX_KEY_SIZE> &key) const override {
|
||||
|
@ -58,7 +58,7 @@ set<Key> _getBlockstoreUnaccountedBlocks(const CryConfig &config) {
|
||||
i = 0;
|
||||
cout << "\nRemove blocks that have a parent" << endl;
|
||||
//Remove root block from unaccountedBlocks
|
||||
unaccountedBlocks.erase(Key::FromString(config.RootBlob()));
|
||||
unaccountedBlocks.erase(Key::FrComString(config.RootBlob()));
|
||||
//Remove all blocks that have a parent node from unaccountedBlocks
|
||||
for (auto file = directory_iterator("/home/heinzi/basedir"); file != directory_iterator(); ++file) {
|
||||
cout << "\r" << (++i) << "/" << numBlocks << flush;
|
||||
|
@ -46,6 +46,7 @@ set(SOURCES
|
||||
assert/backtrace_include_test.cpp
|
||||
assert/assert_include_test.cpp
|
||||
assert/assert_debug_test.cpp
|
||||
system/MemoryTest.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
@ -17,6 +17,11 @@ namespace cpputils {
|
||||
|
||||
static constexpr unsigned int BINARY_LENGTH = 1;
|
||||
|
||||
static FakeKey CreateKey(RandomGenerator &randomGenerator) {
|
||||
auto data = randomGenerator.getFixedSize<1>();
|
||||
return FakeKey{*((uint8_t *) data.data())};
|
||||
}
|
||||
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
@ -27,11 +32,6 @@ namespace cpputils {
|
||||
|
||||
using EncryptionKey = FakeKey;
|
||||
|
||||
static EncryptionKey CreateKey(RandomGenerator &randomGenerator) {
|
||||
auto data = randomGenerator.getFixedSize<1>();
|
||||
return FakeKey{*((uint8_t *) data.data())};
|
||||
}
|
||||
|
||||
static EncryptionKey Key1() {
|
||||
return FakeKey{5};
|
||||
}
|
||||
|
25
test/cpp-utils/system/MemoryTest.cpp
Normal file
25
test/cpp-utils/system/MemoryTest.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <cpp-utils/system/memory.h>
|
||||
#include <memory>
|
||||
|
||||
using cpputils::DontSwapMemoryRAII;
|
||||
|
||||
TEST(MemoryTest, LockingSmallStackMemoryDoesntCrash) {
|
||||
bool memory;
|
||||
DontSwapMemoryRAII obj(&memory, sizeof(memory));
|
||||
}
|
||||
|
||||
TEST(MemoryTest, LockingLargeStackMemoryDoesntCrash) {
|
||||
bool memory[10*1024];
|
||||
DontSwapMemoryRAII obj(memory, sizeof(memory));
|
||||
}
|
||||
|
||||
TEST(MemoryTest, LockingSmallHeapMemoryDoesntCrash) {
|
||||
auto memory = std::make_unique<bool>(false);
|
||||
DontSwapMemoryRAII obj(memory.get(), sizeof(*memory));
|
||||
}
|
||||
|
||||
TEST(MemoryTest, LockingLargeHeapMemoryDoesntCrash) {
|
||||
auto memory = std::make_unique<bool[]>(10*1024);
|
||||
DontSwapMemoryRAII obj(memory.get(), 10*1024);
|
||||
}
|
@ -37,7 +37,7 @@ public:
|
||||
void EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE(const string &cipherName) {
|
||||
const auto &actualCipher = CryCiphers::find(cipherName);
|
||||
Data dataFixture = DataFixture::generate(1024);
|
||||
string encKey = ExpectedCipher::CreateKey(Random::PseudoRandom()).ToString();
|
||||
string encKey = ExpectedCipher::EncryptionKey::CreateKey(Random::PseudoRandom()).ToString();
|
||||
_EXPECT_ENCRYPTS_WITH_ACTUAL_BLOCKSTORE_DECRYPTS_CORRECTLY_WITH_EXPECTED_BLOCKSTORE<ExpectedCipher>(actualCipher, encKey, std::move(dataFixture));
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
cryfs::CryConfigFile configFile() {
|
||||
cryfs::CryConfig config;
|
||||
config.SetCipher("aes-256-gcm");
|
||||
config.SetEncryptionKey(cpputils::AES256_GCM::CreateKey(cpputils::Random::PseudoRandom()).ToString());
|
||||
config.SetEncryptionKey(cpputils::AES256_GCM::EncryptionKey::CreateKey(cpputils::Random::PseudoRandom()).ToString());
|
||||
config.SetBlocksizeBytes(10240);
|
||||
return cryfs::CryConfigFile::create(_configFile.path(), std::move(config), "mypassword", cpputils::SCrypt::TestSettings);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user