Rename VersionCountingBlockStore -> IntegrityBlockStore

This commit is contained in:
Sebastian Messmer 2017-09-16 00:18:58 +01:00
parent 00d098952b
commit f6b6875bb2
19 changed files with 196 additions and 195 deletions

View File

@ -24,10 +24,10 @@ set(SOURCES
implementations/caching/cache/QueueMap.cpp
implementations/low2highlevel/LowToHighLevelBlock.cpp
implementations/low2highlevel/LowToHighLevelBlockStore.cpp
implementations/versioncounting/VersionCountingBlockStore2.cpp
implementations/versioncounting/KnownBlockVersions.cpp
implementations/versioncounting/ClientIdAndBlockKey.cpp
implementations/versioncounting/IntegrityViolationError.cpp
implementations/integrity/IntegrityBlockStore2.cpp
implementations/integrity/KnownBlockVersions.cpp
implementations/integrity/ClientIdAndBlockKey.cpp
implementations/integrity/IntegrityViolationError.cpp
implementations/mock/MockBlockStore.cpp
implementations/mock/MockBlock.cpp
)

View File

@ -142,7 +142,7 @@ inline boost::optional<cpputils::Data> EncryptedBlockStore2<Cipher>::_tryDecrypt
}
*decrypted = _migrateBlock(*decrypted);
// no need to write migrated back to block store because
// this migration happens in line with a migration in VersionCountingBlockStore2
// this migration happens in line with a migration in IntegrityBlockStore2
// which then writes it back
}
#endif

View File

@ -0,0 +1,34 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_CLIENTIDANDBLOCKKEY_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_CLIENTIDANDBLOCKKEY_H_
#include <utility>
#include "../../utils/Key.h"
namespace blockstore {
namespace integrity {
struct ClientIdAndBlockKey {
uint32_t clientId;
Key blockKey;
};
}
}
// Allow using it in std::unordered_set / std::unordered_map
namespace std {
template<> struct hash<blockstore::integrity::ClientIdAndBlockKey> {
size_t operator()(const blockstore::integrity::ClientIdAndBlockKey &ref) const {
return std::hash<uint32_t>()(ref.clientId) ^ std::hash<blockstore::Key>()(ref.blockKey);
}
};
template<> struct equal_to<blockstore::integrity::ClientIdAndBlockKey> {
size_t operator()(const blockstore::integrity::ClientIdAndBlockKey &lhs, const blockstore::integrity::ClientIdAndBlockKey &rhs) const {
return lhs.clientId == rhs.clientId && lhs.blockKey == rhs.blockKey;
}
};
}
#endif

View File

@ -1,5 +1,5 @@
#include <blockstore/interface/BlockStore2.h>
#include "VersionCountingBlockStore2.h"
#include "IntegrityBlockStore2.h"
#include "KnownBlockVersions.h"
using cpputils::Data;
@ -10,19 +10,19 @@ using boost::none;
using namespace cpputils::logging;
namespace blockstore {
namespace versioncounting {
namespace integrity {
#ifndef CRYFS_NO_COMPATIBILITY
constexpr uint16_t VersionCountingBlockStore2::FORMAT_VERSION_HEADER_OLD;
constexpr uint16_t IntegrityBlockStore2::FORMAT_VERSION_HEADER_OLD;
#endif
constexpr uint16_t VersionCountingBlockStore2::FORMAT_VERSION_HEADER;
constexpr uint64_t VersionCountingBlockStore2::VERSION_ZERO;
constexpr unsigned int VersionCountingBlockStore2::ID_HEADER_OFFSET;
constexpr unsigned int VersionCountingBlockStore2::CLIENTID_HEADER_OFFSET;
constexpr unsigned int VersionCountingBlockStore2::VERSION_HEADER_OFFSET;
constexpr unsigned int VersionCountingBlockStore2::HEADER_LENGTH;
constexpr uint16_t IntegrityBlockStore2::FORMAT_VERSION_HEADER;
constexpr uint64_t IntegrityBlockStore2::VERSION_ZERO;
constexpr unsigned int IntegrityBlockStore2::ID_HEADER_OFFSET;
constexpr unsigned int IntegrityBlockStore2::CLIENTID_HEADER_OFFSET;
constexpr unsigned int IntegrityBlockStore2::VERSION_HEADER_OFFSET;
constexpr unsigned int IntegrityBlockStore2::HEADER_LENGTH;
Data VersionCountingBlockStore2::_prependHeaderToData(const Key& key, uint32_t myClientId, uint64_t version, const Data &data) {
Data IntegrityBlockStore2::_prependHeaderToData(const Key& key, uint32_t myClientId, uint64_t version, const Data &data) {
static_assert(HEADER_LENGTH == sizeof(FORMAT_VERSION_HEADER) + Key::BINARY_LENGTH + sizeof(myClientId) + sizeof(version), "Wrong header length");
Data result(data.size() + HEADER_LENGTH);
std::memcpy(result.dataOffset(0), &FORMAT_VERSION_HEADER, sizeof(FORMAT_VERSION_HEADER));
@ -33,19 +33,19 @@ Data VersionCountingBlockStore2::_prependHeaderToData(const Key& key, uint32_t m
return result;
}
void VersionCountingBlockStore2::_checkHeader(const Key &key, const Data &data) const {
void IntegrityBlockStore2::_checkHeader(const Key &key, const Data &data) const {
_checkFormatHeader(data);
_checkIdHeader(key, data);
_checkVersionHeader(key, data);
}
void VersionCountingBlockStore2::_checkFormatHeader(const Data &data) const {
void IntegrityBlockStore2::_checkFormatHeader(const Data &data) const {
if (FORMAT_VERSION_HEADER != _readFormatHeader(data)) {
throw std::runtime_error("The versioned block has the wrong format. Was it created with a newer version of CryFS?");
}
}
void VersionCountingBlockStore2::_checkVersionHeader(const Key &key, const Data &data) const {
void IntegrityBlockStore2::_checkVersionHeader(const Key &key, const Data &data) const {
uint32_t clientId = _readClientId(data);
uint64_t version = _readVersion(data);
@ -54,38 +54,38 @@ void VersionCountingBlockStore2::_checkVersionHeader(const Key &key, const Data
}
}
void VersionCountingBlockStore2::_checkIdHeader(const Key &expectedKey, const Data &data) const {
void IntegrityBlockStore2::_checkIdHeader(const Key &expectedKey, const Data &data) const {
Key actualKey = _readBlockId(data);
if (expectedKey != actualKey) {
integrityViolationDetected("The block key is wrong. Did an attacker try to rename some blocks?");
}
}
uint16_t VersionCountingBlockStore2::_readFormatHeader(const Data &data) {
uint16_t IntegrityBlockStore2::_readFormatHeader(const Data &data) {
return *reinterpret_cast<decltype(FORMAT_VERSION_HEADER)*>(data.data());
}
uint32_t VersionCountingBlockStore2::_readClientId(const Data &data) {
uint32_t IntegrityBlockStore2::_readClientId(const Data &data) {
uint32_t clientId;
std::memcpy(&clientId, data.dataOffset(CLIENTID_HEADER_OFFSET), sizeof(clientId));
return clientId;
}
Key VersionCountingBlockStore2::_readBlockId(const Data &data) {
Key IntegrityBlockStore2::_readBlockId(const Data &data) {
return Key::FromBinary(data.dataOffset(ID_HEADER_OFFSET));
}
uint64_t VersionCountingBlockStore2::_readVersion(const Data &data) {
uint64_t IntegrityBlockStore2::_readVersion(const Data &data) {
uint64_t version;
std::memcpy(&version, data.dataOffset(VERSION_HEADER_OFFSET), sizeof(version));
return version;
}
Data VersionCountingBlockStore2::_removeHeader(const Data &data) {
Data IntegrityBlockStore2::_removeHeader(const Data &data) {
return data.copyAndRemovePrefix(HEADER_LENGTH);
}
void VersionCountingBlockStore2::_checkNoPastIntegrityViolations() const {
void IntegrityBlockStore2::_checkNoPastIntegrityViolations() const {
if (_integrityViolationDetected) {
throw std::runtime_error(string() +
"There was an integrity violation detected. Preventing any further access to the file system. " +
@ -95,29 +95,29 @@ void VersionCountingBlockStore2::_checkNoPastIntegrityViolations() const {
}
}
void VersionCountingBlockStore2::integrityViolationDetected(const string &reason) const {
void IntegrityBlockStore2::integrityViolationDetected(const string &reason) const {
_integrityViolationDetected = true;
throw IntegrityViolationError(reason);
}
VersionCountingBlockStore2::VersionCountingBlockStore2(unique_ref<BlockStore2> baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId, bool missingBlockIsIntegrityViolation)
IntegrityBlockStore2::IntegrityBlockStore2(unique_ref<BlockStore2> baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId, bool missingBlockIsIntegrityViolation)
: _baseBlockStore(std::move(baseBlockStore)), _knownBlockVersions(integrityFilePath, myClientId), _missingBlockIsIntegrityViolation(missingBlockIsIntegrityViolation), _integrityViolationDetected(false) {
}
bool VersionCountingBlockStore2::tryCreate(const Key &key, const Data &data) {
bool IntegrityBlockStore2::tryCreate(const Key &key, const Data &data) {
_checkNoPastIntegrityViolations();
uint64_t version = _knownBlockVersions.incrementVersion(key);
Data dataWithHeader = _prependHeaderToData(key, _knownBlockVersions.myClientId(), version, data);
return _baseBlockStore->tryCreate(key, dataWithHeader);
}
bool VersionCountingBlockStore2::remove(const Key &key) {
bool IntegrityBlockStore2::remove(const Key &key) {
_checkNoPastIntegrityViolations();
_knownBlockVersions.markBlockAsDeleted(key);
return _baseBlockStore->remove(key);
}
optional<Data> VersionCountingBlockStore2::load(const Key &key) const {
optional<Data> IntegrityBlockStore2::load(const Key &key) const {
_checkNoPastIntegrityViolations();
auto loaded = _baseBlockStore->load(key);
if (none == loaded) {
@ -131,7 +131,7 @@ optional<Data> VersionCountingBlockStore2::load(const Key &key) const {
Data migrated = _migrateBlock(key, *loaded);
_checkHeader(key, migrated);
Data content = _removeHeader(migrated);
const_cast<VersionCountingBlockStore2*>(this)->store(key, content);
const_cast<IntegrityBlockStore2*>(this)->store(key, content);
return optional<Data>(_removeHeader(migrated));
}
#endif
@ -140,7 +140,7 @@ optional<Data> VersionCountingBlockStore2::load(const Key &key) const {
}
#ifndef CRYFS_NO_COMPATIBILITY
Data VersionCountingBlockStore2::_migrateBlock(const Key &key, const Data &data) {
Data IntegrityBlockStore2::_migrateBlock(const Key &key, const Data &data) {
Data migrated(data.size() + Key::BINARY_LENGTH);
std::memcpy(migrated.dataOffset(0), &FORMAT_VERSION_HEADER, sizeof(FORMAT_VERSION_HEADER));
std::memcpy(migrated.dataOffset(ID_HEADER_OFFSET), key.data(), Key::BINARY_LENGTH);
@ -150,22 +150,22 @@ Data VersionCountingBlockStore2::_migrateBlock(const Key &key, const Data &data)
}
#endif
void VersionCountingBlockStore2::store(const Key &key, const Data &data) {
void IntegrityBlockStore2::store(const Key &key, const Data &data) {
_checkNoPastIntegrityViolations();
uint64_t version = _knownBlockVersions.incrementVersion(key);
Data dataWithHeader = _prependHeaderToData(key, _knownBlockVersions.myClientId(), version, data);
return _baseBlockStore->store(key, dataWithHeader);
}
uint64_t VersionCountingBlockStore2::numBlocks() const {
uint64_t IntegrityBlockStore2::numBlocks() const {
return _baseBlockStore->numBlocks();
}
uint64_t VersionCountingBlockStore2::estimateNumFreeBytes() const {
uint64_t IntegrityBlockStore2::estimateNumFreeBytes() const {
return _baseBlockStore->estimateNumFreeBytes();
}
uint64_t VersionCountingBlockStore2::blockSizeFromPhysicalBlockSize(uint64_t blockSize) const {
uint64_t IntegrityBlockStore2::blockSizeFromPhysicalBlockSize(uint64_t blockSize) const {
uint64_t baseBlockSize = _baseBlockStore->blockSizeFromPhysicalBlockSize(blockSize);
if (baseBlockSize <= HEADER_LENGTH) {
return 0;
@ -173,7 +173,7 @@ uint64_t VersionCountingBlockStore2::blockSizeFromPhysicalBlockSize(uint64_t blo
return baseBlockSize - HEADER_LENGTH;
}
void VersionCountingBlockStore2::forEachBlock(std::function<void (const Key &)> callback) const {
void IntegrityBlockStore2::forEachBlock(std::function<void (const Key &)> callback) const {
if (!_missingBlockIsIntegrityViolation) {
return _baseBlockStore->forEachBlock(std::move(callback));
}
@ -193,7 +193,7 @@ void VersionCountingBlockStore2::forEachBlock(std::function<void (const Key &)>
}
#ifndef CRYFS_NO_COMPATIBILITY
void VersionCountingBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(BlockStore2 *baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId) {
void IntegrityBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(BlockStore2 *baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId) {
std::cout << "Migrating file system for integrity features. Please don't interrupt this process. This can take a while..." << std::flush;
KnownBlockVersions knownBlockVersions(integrityFilePath, myClientId);
baseBlockStore->forEachBlock([&baseBlockStore, &knownBlockVersions] (const Key &key) {
@ -202,7 +202,7 @@ void VersionCountingBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(Bloc
std::cout << "done" << std::endl;
}
void VersionCountingBlockStore2::migrateBlockFromBlockstoreWithoutVersionNumbers(blockstore::BlockStore2* baseBlockStore, const blockstore::Key& key, KnownBlockVersions *knownBlockVersions) {
void IntegrityBlockStore2::migrateBlockFromBlockstoreWithoutVersionNumbers(blockstore::BlockStore2* baseBlockStore, const blockstore::Key& key, KnownBlockVersions *knownBlockVersions) {
uint64_t version = knownBlockVersions->incrementVersion(key);
auto data_ = baseBlockStore->load(key);

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_VERSIONCOUNTINGBLOCKSTORE2_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_VERSIONCOUNTINGBLOCKSTORE2_H_
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_INTEGRITYBLOCKSTORE2_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_INTEGRITYBLOCKSTORE2_H_
#include "../../interface/BlockStore2.h"
#include <cpp-utils/macros.h>
@ -8,13 +8,15 @@
#include "IntegrityViolationError.h"
namespace blockstore {
namespace versioncounting {
namespace integrity {
//TODO Format version headers
class VersionCountingBlockStore2 final: public BlockStore2 {
// This blockstore implements integrity measures.
// It depends on being used on top of an encrypted block store that protects integrity of the block contents (i.e. uses an authenticated cipher).
class IntegrityBlockStore2 final: public BlockStore2 {
public:
VersionCountingBlockStore2(cpputils::unique_ref<BlockStore2> baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId, bool missingBlockIsIntegrityViolation);
IntegrityBlockStore2(cpputils::unique_ref<BlockStore2> baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId, bool missingBlockIsIntegrityViolation);
bool tryCreate(const Key &key, const cpputils::Data &data) override;
bool remove(const Key &key) override;
@ -67,7 +69,7 @@ private:
const bool _missingBlockIsIntegrityViolation;
mutable bool _integrityViolationDetected;
DISALLOW_COPY_AND_ASSIGN(VersionCountingBlockStore2);
DISALLOW_COPY_AND_ASSIGN(IntegrityBlockStore2);
};
}

View File

@ -1,12 +1,12 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_INTEGRITYVIOLATIONERROR_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_INTEGRITYVIOLATIONERROR_H_
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_INTEGRITYVIOLATIONERROR_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_INTEGRITYVIOLATIONERROR_H_
#include <cpp-utils/macros.h>
#include <string>
namespace blockstore {
namespace versioncounting {
namespace integrity {
class IntegrityViolationError final : public std::exception {
public:
@ -16,14 +16,13 @@ namespace blockstore {
}
private:
// Constructor is private to make sure that only VersionCountingBlockStore can throw this exception.
// This is because VersionCountingBlockStore wants to know about integrity violations and
// Constructor is private to make sure that only IntegrityBlockStore can throw this exception.
// This is because IntegrityBlockStore wants to know about integrity violations and
// block all further file system access if it happens.
IntegrityViolationError(const std::string &reason)
: _reason("Integrity violation: " + reason) {
}
friend class VersionCountingBlockStore;
friend class VersionCountingBlockStore2;
friend class IntegrityBlockStore2;
std::string _reason;
};

View File

@ -17,7 +17,7 @@ using cpputils::Serializer;
using cpputils::Deserializer;
namespace blockstore {
namespace versioncounting {
namespace integrity {
const string KnownBlockVersions::HEADER = "cryfs.integritydata.knownblockversions;0";
constexpr uint32_t KnownBlockVersions::CLIENT_ID_FOR_DELETED_BLOCK;

View File

@ -1,6 +1,6 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_KNOWNBLOCKVERSIONS_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_KNOWNBLOCKVERSIONS_H_
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_KNOWNBLOCKVERSIONS_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_INTEGRITY_KNOWNBLOCKVERSIONS_H_
#include <cpp-utils/macros.h>
#include <blockstore/utils/Key.h>
@ -13,7 +13,7 @@
#include <unordered_set>
namespace blockstore {
namespace versioncounting {
namespace integrity {
class KnownBlockVersions final {
public:

View File

@ -1,34 +0,0 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_CLIENTIDANDBLOCKKEY_H_
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_VERSIONCOUNTING_CLIENTIDANDBLOCKKEY_H_
#include <utility>
#include "../../utils/Key.h"
namespace blockstore {
namespace versioncounting {
struct ClientIdAndBlockKey {
uint32_t clientId;
Key blockKey;
};
}
}
// Allow using it in std::unordered_set / std::unordered_map
namespace std {
template<> struct hash<blockstore::versioncounting::ClientIdAndBlockKey> {
size_t operator()(const blockstore::versioncounting::ClientIdAndBlockKey &ref) const {
return std::hash<uint32_t>()(ref.clientId) ^ std::hash<blockstore::Key>()(ref.blockKey);
}
};
template<> struct equal_to<blockstore::versioncounting::ClientIdAndBlockKey> {
size_t operator()(const blockstore::versioncounting::ClientIdAndBlockKey &lhs, const blockstore::versioncounting::ClientIdAndBlockKey &rhs) const {
return lhs.clientId == rhs.clientId && lhs.blockKey == rhs.blockKey;
}
};
}
#endif

View File

@ -12,7 +12,7 @@
#include <blobstore/implementations/onblocks/BlobOnBlocks.h>
#include <blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h>
#include <blockstore/implementations/encrypted/EncryptedBlockStore2.h>
#include <blockstore/implementations/versioncounting/VersionCountingBlockStore2.h>
#include <blockstore/implementations/integrity/IntegrityBlockStore2.h>
#include "parallelaccessfsblobstore/ParallelAccessFsBlobStore.h"
#include "cachingfsblobstore/CachingFsBlobStore.h"
#include "../config/CryCipher.h"
@ -37,7 +37,7 @@ using blockstore::lowtohighlevel::LowToHighLevelBlockStore;
using blobstore::onblocks::BlobStoreOnBlocks;
using blobstore::onblocks::BlobOnBlocks;
using blockstore::caching::CachingBlockStore2;
using blockstore::versioncounting::VersionCountingBlockStore2;
using blockstore::integrity::IntegrityBlockStore2;
using gitversion::VersionCompare;
using cpputils::unique_ref;
using cpputils::make_unique_ref;
@ -90,33 +90,33 @@ unique_ref<fsblobstore::FsBlobStore> CryDevice::MigrateOrCreateFsBlobStore(uniqu
#endif
unique_ref<blobstore::BlobStore> CryDevice::CreateBlobStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
auto versionCountingEncryptedBlockStore = CreateVersionCountingEncryptedBlockStore(std::move(blockStore), configFile, myClientId);
// Create versionCountingEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes
auto integrityEncryptedBlockStore = CreateIntegrityEncryptedBlockStore(std::move(blockStore), configFile, myClientId);
// Create integrityEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes
// in the configFile and therefore has to be run before the second parameter to the BlobStoreOnBlocks parameter is evaluated.
return make_unique_ref<BlobStoreOnBlocks>(
make_unique_ref<LowToHighLevelBlockStore>(
make_unique_ref<CachingBlockStore2>(
std::move(versionCountingEncryptedBlockStore)
std::move(integrityEncryptedBlockStore)
)
),
configFile->config()->BlocksizeBytes());
}
unique_ref<BlockStore2> CryDevice::CreateVersionCountingEncryptedBlockStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
unique_ref<BlockStore2> CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref<BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId) {
auto encryptedBlockStore = CreateEncryptedBlockStore(*configFile->config(), std::move(blockStore));
auto statePath = LocalStateDir::forFilesystemId(configFile->config()->FilesystemId());
auto integrityFilePath = statePath / "integritydata";
#ifndef CRYFS_NO_COMPATIBILITY
if (!configFile->config()->HasVersionNumbers()) {
VersionCountingBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(encryptedBlockStore.get(), integrityFilePath, myClientId);
configFile->config()->SetBlocksizeBytes(configFile->config()->BlocksizeBytes() + VersionCountingBlockStore2::HEADER_LENGTH);
IntegrityBlockStore2::migrateFromBlockstoreWithoutVersionNumbers(encryptedBlockStore.get(), integrityFilePath, myClientId);
configFile->config()->SetBlocksizeBytes(configFile->config()->BlocksizeBytes() + IntegrityBlockStore2::HEADER_LENGTH);
configFile->config()->SetHasVersionNumbers(true);
configFile->save();
}
#endif
return make_unique_ref<VersionCountingBlockStore2>(std::move(encryptedBlockStore), integrityFilePath, myClientId, false);
return make_unique_ref<IntegrityBlockStore2>(std::move(encryptedBlockStore), integrityFilePath, myClientId, false);
}
Key CryDevice::CreateRootBlobAndReturnKey() {

View File

@ -58,7 +58,7 @@ private:
static cpputils::unique_ref<fsblobstore::FsBlobStore> MigrateOrCreateFsBlobStore(cpputils::unique_ref<blobstore::BlobStore> blobStore, CryConfigFile *configFile);
#endif
static cpputils::unique_ref<blobstore::BlobStore> CreateBlobStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blockstore::BlockStore2> CreateVersionCountingEncryptedBlockStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blockstore::BlockStore2> CreateIntegrityEncryptedBlockStore(cpputils::unique_ref<blockstore::BlockStore2> blockStore, CryConfigFile *configFile, uint32_t myClientId);
static cpputils::unique_ref<blockstore::BlockStore2> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore2> baseBlockStore);
struct BlobWithParent {

View File

@ -1,14 +1,14 @@
#include "MyClientId.h"
#include <fstream>
#include <cpp-utils/random/Random.h>
#include <blockstore/implementations/versioncounting/KnownBlockVersions.h>
#include <blockstore/implementations/integrity/KnownBlockVersions.h>
using boost::optional;
using boost::none;
using std::ifstream;
using std::ofstream;
using cpputils::Random;
using blockstore::versioncounting::KnownBlockVersions;
using blockstore::integrity::KnownBlockVersions;
namespace bf = boost::filesystem;
namespace cryfs {

View File

@ -35,9 +35,9 @@ set(SOURCES
implementations/caching/cache/CacheTest_RaceCondition.cpp
implementations/caching/cache/PeriodicTaskTest.cpp
implementations/caching/cache/QueueMapTest_Peek.cpp
implementations/versioncounting/KnownBlockVersionsTest.cpp
implementations/versioncounting/VersionCountingBlockStoreTest_Generic.cpp
implementations/versioncounting/VersionCountingBlockStoreTest_Specific.cpp
implementations/integrity/KnownBlockVersionsTest.cpp
implementations/integrity/IntegrityBlockStoreTest_Generic.cpp
implementations/integrity/IntegrityBlockStoreTest_Specific.cpp
implementations/low2highlevel/LowToHighLevelBlockStoreTest.cpp
)

View File

@ -0,0 +1,54 @@
#include "blockstore/implementations/integrity/IntegrityBlockStore2.h"
#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h"
#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h"
#include "../../testutils/BlockStoreTest.h"
#include "../../testutils/BlockStore2Test.h"
#include <gtest/gtest.h>
#include <cpp-utils/tempfile/TempFile.h>
using ::testing::Test;
using blockstore::BlockStore;
using blockstore::BlockStore2;
using blockstore::integrity::IntegrityBlockStore2;
using blockstore::integrity::KnownBlockVersions;
using blockstore::lowtohighlevel::LowToHighLevelBlockStore;
using blockstore::inmemory::InMemoryBlockStore2;
using cpputils::Data;
using cpputils::DataFixture;
using cpputils::make_unique_ref;
using cpputils::unique_ref;
using cpputils::TempFile;
template<bool MissingBlockIsIntegrityViolation>
class IntegrityBlockStoreTestFixture: public BlockStoreTestFixture {
public:
IntegrityBlockStoreTestFixture() :stateFile(false) {}
TempFile stateFile;
unique_ref<BlockStore> createBlockStore() override {
return make_unique_ref<LowToHighLevelBlockStore>(
make_unique_ref<IntegrityBlockStore2>(make_unique_ref<InMemoryBlockStore2>(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation)
);
}
};
// TODO Why is here no IntegrityBlockStoreWithRandomKeysTest?
INSTANTIATE_TYPED_TEST_CASE_P(Integrity_multiclient, BlockStoreTest, IntegrityBlockStoreTestFixture<false>);
INSTANTIATE_TYPED_TEST_CASE_P(Integrity_singleclient, BlockStoreTest, IntegrityBlockStoreTestFixture<true>);
template<bool MissingBlockIsIntegrityViolation>
class IntegrityBlockStore2TestFixture: public BlockStore2TestFixture {
public:
IntegrityBlockStore2TestFixture() :stateFile(false) {}
TempFile stateFile;
unique_ref<BlockStore2> createBlockStore() override {
return make_unique_ref<IntegrityBlockStore2>(make_unique_ref<InMemoryBlockStore2>(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation);
}
};
INSTANTIATE_TYPED_TEST_CASE_P(Integrity_multiclient, BlockStore2Test, IntegrityBlockStore2TestFixture<false>);
INSTANTIATE_TYPED_TEST_CASE_P(Integrity_singleclient, BlockStore2Test, IntegrityBlockStore2TestFixture<true>);

View File

@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "blockstore/implementations/versioncounting/VersionCountingBlockStore2.h"
#include "blockstore/implementations/integrity/IntegrityBlockStore2.h"
#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h"
#include "blockstore/utils/BlockStoreUtils.h"
#include <cpp-utils/data/DataFixture.h>
@ -19,32 +19,32 @@ using std::unique_ptr;
using blockstore::inmemory::InMemoryBlockStore2;
using namespace blockstore::versioncounting;
using namespace blockstore::integrity;
class VersionCountingBlockStoreTest: public Test {
class IntegrityBlockStoreTest: public Test {
public:
static constexpr unsigned int BLOCKSIZE = 1024;
VersionCountingBlockStoreTest():
IntegrityBlockStoreTest():
stateFile(false),
baseBlockStore(new InMemoryBlockStore2),
blockStore(make_unique_ref<VersionCountingBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, false)),
blockStore(make_unique_ref<IntegrityBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, false)),
data(DataFixture::generate(BLOCKSIZE)) {
}
static constexpr uint32_t myClientId = 0x12345678;
TempFile stateFile;
InMemoryBlockStore2 *baseBlockStore;
unique_ref<VersionCountingBlockStore2> blockStore;
unique_ref<IntegrityBlockStore2> blockStore;
Data data;
std::pair<InMemoryBlockStore2 *, unique_ptr<VersionCountingBlockStore2>> makeBlockStoreWithDeletionPrevention() {
std::pair<InMemoryBlockStore2 *, unique_ptr<IntegrityBlockStore2>> makeBlockStoreWithDeletionPrevention() {
InMemoryBlockStore2 *baseBlockStore = new InMemoryBlockStore2;
auto blockStore = make_unique<VersionCountingBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, true);
auto blockStore = make_unique<IntegrityBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, true);
return std::make_pair(baseBlockStore, std::move(blockStore));
}
std::pair<InMemoryBlockStore2 *, unique_ptr<VersionCountingBlockStore2>> makeBlockStoreWithoutDeletionPrevention() {
std::pair<InMemoryBlockStore2 *, unique_ptr<IntegrityBlockStore2>> makeBlockStoreWithoutDeletionPrevention() {
InMemoryBlockStore2 *baseBlockStore = new InMemoryBlockStore2;
auto blockStore = make_unique<VersionCountingBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, false);
auto blockStore = make_unique<IntegrityBlockStore2>(std::move(cpputils::nullcheck(std::unique_ptr<InMemoryBlockStore2>(baseBlockStore)).value()), stateFile.path(), myClientId, false);
return std::make_pair(baseBlockStore, std::move(blockStore));
}
@ -77,7 +77,7 @@ public:
void decreaseVersionNumber(const blockstore::Key &key) {
auto baseBlock = baseBlockStore->load(key).value();
uint64_t* version = (uint64_t*)((uint8_t*)baseBlock.data()+VersionCountingBlockStore2::VERSION_HEADER_OFFSET);
uint64_t* version = (uint64_t*)((uint8_t*)baseBlock.data()+IntegrityBlockStore2::VERSION_HEADER_OFFSET);
ASSERT(*version > 1, "Can't decrease the lowest allowed version number");
*version -= 1;
baseBlockStore->store(key, baseBlock);
@ -85,14 +85,14 @@ public:
void increaseVersionNumber(const blockstore::Key &key) {
auto baseBlock = baseBlockStore->load(key).value();
uint64_t* version = (uint64_t*)((uint8_t*)baseBlock.data()+VersionCountingBlockStore2::VERSION_HEADER_OFFSET);
uint64_t* version = (uint64_t*)((uint8_t*)baseBlock.data()+IntegrityBlockStore2::VERSION_HEADER_OFFSET);
*version += 1;
baseBlockStore->store(key, baseBlock);
}
void changeClientId(const blockstore::Key &key) {
auto baseBlock = baseBlockStore->load(key).value();
uint32_t* clientId = (uint32_t*)((uint8_t*)baseBlock.data()+VersionCountingBlockStore2::CLIENTID_HEADER_OFFSET);
uint32_t* clientId = (uint32_t*)((uint8_t*)baseBlock.data()+IntegrityBlockStore2::CLIENTID_HEADER_OFFSET);
*clientId += 1;
baseBlockStore->store(key, baseBlock);
}
@ -106,13 +106,13 @@ public:
}
private:
DISALLOW_COPY_AND_ASSIGN(VersionCountingBlockStoreTest);
DISALLOW_COPY_AND_ASSIGN(IntegrityBlockStoreTest);
};
constexpr uint32_t VersionCountingBlockStoreTest::myClientId;
constexpr uint32_t IntegrityBlockStoreTest::myClientId;
// Test that a decreasing version number is not allowed
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_1) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_1) {
auto key = CreateBlockReturnKey();
Data oldBaseBlock = loadBaseBlock(key);
modifyBlock(key);
@ -123,7 +123,7 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVe
);
}
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_2) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_2) {
auto key = CreateBlockReturnKey();
// Increase the version number
modifyBlock(key);
@ -136,7 +136,7 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowDecreasingVe
}
// Test that a different client doesn't need to have a higher version number (i.e. version numbers are per client).
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesAllowDecreasingVersionNumberForDifferentClient) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_DoesAllowDecreasingVersionNumberForDifferentClient) {
auto key = CreateBlockReturnKey();
// Increase the version number
modifyBlock(key);
@ -147,7 +147,7 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesAllowDecreasingVers
}
// Test that it doesn't allow a rollback to the "newest" block of a client, when this block was superseded by a version of a different client
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowSameVersionNumberForOldClient) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_DoesntAllowSameVersionNumberForOldClient) {
auto key = CreateBlockReturnKey();
// Increase the version number
modifyBlock(key);
@ -164,7 +164,7 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowSameVersionN
}
// Test that deleted blocks cannot be re-introduced
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowReintroducingDeletedBlocks) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_DoesntAllowReintroducingDeletedBlocks) {
auto key = CreateBlockReturnKey();
Data oldBaseBlock = loadBaseBlock(key);
deleteBlock(key);
@ -176,7 +176,7 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_DoesntAllowReintroducin
}
// This can happen if a client synchronization is delayed. Another client might have won the conflict and pushed a new version for the deleted block.
TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber) {
TEST_F(IntegrityBlockStoreTest, RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber) {
auto key = CreateBlockReturnKey();
Data oldBaseBlock = loadBaseBlock(key);
deleteBlock(key);
@ -186,9 +186,9 @@ TEST_F(VersionCountingBlockStoreTest, RollbackPrevention_AllowsReintroducingDele
}
// Check that in a multi-client scenario, missing blocks are not integrity errors, because another client might have deleted them.
TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_AllowsDeletingBlocksWhenDeactivated) {
TEST_F(IntegrityBlockStoreTest, DeletionPrevention_AllowsDeletingBlocksWhenDeactivated) {
InMemoryBlockStore2 *baseBlockStore;
unique_ptr<VersionCountingBlockStore2> blockStore;
unique_ptr<IntegrityBlockStore2> blockStore;
std::tie(baseBlockStore, blockStore) = makeBlockStoreWithoutDeletionPrevention();
auto key = blockStore->create(Data(0));
baseBlockStore->remove(key);
@ -196,9 +196,9 @@ TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_AllowsDeletingBlocksWhe
}
// Check that in a single-client scenario, missing blocks are integrity errors.
TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_DoesntAllowDeletingBlocksWhenActivated) {
TEST_F(IntegrityBlockStoreTest, DeletionPrevention_DoesntAllowDeletingBlocksWhenActivated) {
InMemoryBlockStore2 *baseBlockStore;
unique_ptr<VersionCountingBlockStore2> blockStore;
unique_ptr<IntegrityBlockStore2> blockStore;
std::tie(baseBlockStore, blockStore) = makeBlockStoreWithDeletionPrevention();
auto key = blockStore->create(Data(0));
baseBlockStore->remove(key);
@ -209,9 +209,9 @@ TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_DoesntAllowDeletingBloc
}
// Check that in a multi-client scenario, missing blocks are not integrity errors, because another client might have deleted them.
TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_InForEachBlock_AllowsDeletingBlocksWhenDeactivated) {
TEST_F(IntegrityBlockStoreTest, DeletionPrevention_InForEachBlock_AllowsDeletingBlocksWhenDeactivated) {
InMemoryBlockStore2 *baseBlockStore;
unique_ptr<VersionCountingBlockStore2> blockStore;
unique_ptr<IntegrityBlockStore2> blockStore;
std::tie(baseBlockStore, blockStore) = makeBlockStoreWithoutDeletionPrevention();
auto key = blockStore->create(Data(0));
baseBlockStore->remove(key);
@ -223,9 +223,9 @@ TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_InForEachBlock_AllowsDe
}
// Check that in a single-client scenario, missing blocks are integrity errors.
TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_InForEachBlock_DoesntAllowDeletingBlocksWhenActivated) {
TEST_F(IntegrityBlockStoreTest, DeletionPrevention_InForEachBlock_DoesntAllowDeletingBlocksWhenActivated) {
InMemoryBlockStore2 *baseBlockStore;
unique_ptr<VersionCountingBlockStore2> blockStore;
unique_ptr<IntegrityBlockStore2> blockStore;
std::tie(baseBlockStore, blockStore) = makeBlockStoreWithDeletionPrevention();
auto key = blockStore->create(Data(0));
baseBlockStore->remove(key);
@ -235,7 +235,7 @@ TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_InForEachBlock_DoesntAl
);
}
TEST_F(VersionCountingBlockStoreTest, LoadingWithDifferentBlockIdFails) {
TEST_F(IntegrityBlockStoreTest, LoadingWithDifferentBlockIdFails) {
auto key = CreateBlockReturnKey();
blockstore::Key key2 = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972");
baseBlockStore->store(key2, baseBlockStore->load(key).value());
@ -250,17 +250,17 @@ TEST_F(VersionCountingBlockStoreTest, LoadingWithDifferentBlockIdFails) {
// - RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber with different client id
// - Think about more...
TEST_F(VersionCountingBlockStoreTest, PhysicalBlockSize_zerophysical) {
TEST_F(IntegrityBlockStoreTest, PhysicalBlockSize_zerophysical) {
EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(0));
}
TEST_F(VersionCountingBlockStoreTest, PhysicalBlockSize_zerovirtual) {
TEST_F(IntegrityBlockStoreTest, PhysicalBlockSize_zerovirtual) {
auto key = CreateBlockReturnKey(Data(0));
auto base = baseBlockStore->load(key).value();
EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(base.size()));
}
TEST_F(VersionCountingBlockStoreTest, PhysicalBlockSize_negativeboundaries) {
TEST_F(IntegrityBlockStoreTest, PhysicalBlockSize_negativeboundaries) {
// This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the
// correct boundary set. We test the highest value that is negative and the smallest value that is positive.
auto physicalSizeForVirtualSizeZero = baseBlockStore->load(CreateBlockReturnKey(Data(0))).value().size();
@ -271,7 +271,7 @@ TEST_F(VersionCountingBlockStoreTest, PhysicalBlockSize_negativeboundaries) {
EXPECT_EQ(1u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1));
}
TEST_F(VersionCountingBlockStoreTest, PhysicalBlockSize_positive) {
TEST_F(IntegrityBlockStoreTest, PhysicalBlockSize_positive) {
auto key = CreateBlockReturnKey(Data(10*1024));
auto base = baseBlockStore->load(key).value();
EXPECT_EQ(10*1024u, blockStore->blockSizeFromPhysicalBlockSize(base.size()));

View File

@ -1,8 +1,8 @@
#include <gtest/gtest.h>
#include <blockstore/implementations/versioncounting/KnownBlockVersions.h>
#include <blockstore/implementations/integrity/KnownBlockVersions.h>
#include <cpp-utils/tempfile/TempFile.h>
using blockstore::versioncounting::KnownBlockVersions;
using blockstore::integrity::KnownBlockVersions;
using blockstore::Key;
using cpputils::TempFile;
using std::unordered_set;

View File

@ -1,54 +0,0 @@
#include "blockstore/implementations/versioncounting/VersionCountingBlockStore2.h"
#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h"
#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h"
#include "../../testutils/BlockStoreTest.h"
#include "../../testutils/BlockStore2Test.h"
#include <gtest/gtest.h>
#include <cpp-utils/tempfile/TempFile.h>
using ::testing::Test;
using blockstore::BlockStore;
using blockstore::BlockStore2;
using blockstore::versioncounting::VersionCountingBlockStore2;
using blockstore::versioncounting::KnownBlockVersions;
using blockstore::lowtohighlevel::LowToHighLevelBlockStore;
using blockstore::inmemory::InMemoryBlockStore2;
using cpputils::Data;
using cpputils::DataFixture;
using cpputils::make_unique_ref;
using cpputils::unique_ref;
using cpputils::TempFile;
template<bool MissingBlockIsIntegrityViolation>
class VersionCountingBlockStoreTestFixture: public BlockStoreTestFixture {
public:
VersionCountingBlockStoreTestFixture() :stateFile(false) {}
TempFile stateFile;
unique_ref<BlockStore> createBlockStore() override {
return make_unique_ref<LowToHighLevelBlockStore>(
make_unique_ref<VersionCountingBlockStore2>(make_unique_ref<InMemoryBlockStore2>(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation)
);
}
};
// TODO Why is here no VersionCountingBlockStoreWithRandomKeysTest?
INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_multiclient, BlockStoreTest, VersionCountingBlockStoreTestFixture<false>);
INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_singleclient, BlockStoreTest, VersionCountingBlockStoreTestFixture<true>);
template<bool MissingBlockIsIntegrityViolation>
class VersionCountingBlockStore2TestFixture: public BlockStore2TestFixture {
public:
VersionCountingBlockStore2TestFixture() :stateFile(false) {}
TempFile stateFile;
unique_ref<BlockStore2> createBlockStore() override {
return make_unique_ref<VersionCountingBlockStore2>(make_unique_ref<InMemoryBlockStore2>(), stateFile.path(), 0x12345678, MissingBlockIsIntegrityViolation);
}
};
INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_multiclient, BlockStore2Test, VersionCountingBlockStore2TestFixture<false>);
INSTANTIATE_TYPED_TEST_CASE_P(VersionCounting_singleclient, BlockStore2Test, VersionCountingBlockStore2TestFixture<true>);