Storing block ID is job of VersionCountingBlockStore, not EncryptedBlockStore.
This commit is contained in:
parent
446e6e2654
commit
00d098952b
@ -34,17 +34,21 @@ public:
|
||||
private:
|
||||
|
||||
// This header is prepended to blocks to allow future versions to have compatibility.
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER = 0;
|
||||
static constexpr unsigned int HEADER_LENGTH = Key::BINARY_LENGTH;
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER_OLD = 0;
|
||||
#endif
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER = 1;
|
||||
|
||||
cpputils::Data _encrypt(const Key &key, const cpputils::Data &data) const;
|
||||
cpputils::Data _encrypt(const cpputils::Data &data) const;
|
||||
boost::optional<cpputils::Data> _tryDecrypt(const Key &key, const cpputils::Data &data) const;
|
||||
|
||||
static cpputils::Data _prependKeyHeaderToData(const Key &key, const cpputils::Data &data);
|
||||
static bool _keyHeaderIsCorrect(const Key &key, const cpputils::Data &data);
|
||||
static cpputils::Data _prependFormatHeaderToData(const cpputils::Data &data);
|
||||
static cpputils::Data _removeKeyHeader(const cpputils::Data &data);
|
||||
static cpputils::Data _checkAndRemoveFormatHeader(const cpputils::Data &data);
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
static bool _keyHeaderIsCorrect(const Key &key, const cpputils::Data &data);
|
||||
static cpputils::Data _migrateBlock(const cpputils::Data &data);
|
||||
#endif
|
||||
static void _checkFormatHeader(const cpputils::Data &data);
|
||||
static uint16_t _readFormatHeader(const cpputils::Data &data);
|
||||
|
||||
cpputils::unique_ref<BlockStore2> _baseBlockStore;
|
||||
typename Cipher::EncryptionKey _encKey;
|
||||
@ -52,11 +56,13 @@ private:
|
||||
DISALLOW_COPY_AND_ASSIGN(EncryptedBlockStore2);
|
||||
};
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
template<class Cipher>
|
||||
constexpr uint16_t EncryptedBlockStore2<Cipher>::FORMAT_VERSION_HEADER;
|
||||
constexpr uint16_t EncryptedBlockStore2<Cipher>::FORMAT_VERSION_HEADER_OLD;
|
||||
#endif
|
||||
|
||||
template<class Cipher>
|
||||
constexpr unsigned int EncryptedBlockStore2<Cipher>::HEADER_LENGTH;
|
||||
constexpr uint16_t EncryptedBlockStore2<Cipher>::FORMAT_VERSION_HEADER;
|
||||
|
||||
template<class Cipher>
|
||||
inline EncryptedBlockStore2<Cipher>::EncryptedBlockStore2(cpputils::unique_ref<BlockStore2> baseBlockStore, const typename Cipher::EncryptionKey &encKey)
|
||||
@ -65,7 +71,7 @@ inline EncryptedBlockStore2<Cipher>::EncryptedBlockStore2(cpputils::unique_ref<B
|
||||
|
||||
template<class Cipher>
|
||||
inline bool EncryptedBlockStore2<Cipher>::tryCreate(const Key &key, const cpputils::Data &data) {
|
||||
cpputils::Data encrypted = _encrypt(key, data);
|
||||
cpputils::Data encrypted = _encrypt(data);
|
||||
return _baseBlockStore->tryCreate(key, encrypted);
|
||||
}
|
||||
|
||||
@ -86,7 +92,7 @@ inline boost::optional<cpputils::Data> EncryptedBlockStore2<Cipher>::load(const
|
||||
|
||||
template<class Cipher>
|
||||
inline void EncryptedBlockStore2<Cipher>::store(const Key &key, const cpputils::Data &data) {
|
||||
cpputils::Data encrypted = _encrypt(key, data);
|
||||
cpputils::Data encrypted = _encrypt(data);
|
||||
return _baseBlockStore->store(key, encrypted);
|
||||
}
|
||||
|
||||
@ -103,10 +109,10 @@ inline uint64_t EncryptedBlockStore2<Cipher>::estimateNumFreeBytes() const {
|
||||
template<class Cipher>
|
||||
inline uint64_t EncryptedBlockStore2<Cipher>::blockSizeFromPhysicalBlockSize(uint64_t blockSize) const {
|
||||
uint64_t baseBlockSize = _baseBlockStore->blockSizeFromPhysicalBlockSize(blockSize);
|
||||
if (baseBlockSize <= Cipher::ciphertextSize(HEADER_LENGTH) + sizeof(FORMAT_VERSION_HEADER)) {
|
||||
if (baseBlockSize <= Cipher::ciphertextSize(0) + sizeof(FORMAT_VERSION_HEADER)) {
|
||||
return 0;
|
||||
}
|
||||
return Cipher::plaintextSize(baseBlockSize - sizeof(FORMAT_VERSION_HEADER)) - HEADER_LENGTH;
|
||||
return Cipher::plaintextSize(baseBlockSize - sizeof(FORMAT_VERSION_HEADER));
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
@ -115,39 +121,45 @@ inline void EncryptedBlockStore2<Cipher>::forEachBlock(std::function<void (const
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_encrypt(const Key &key, const cpputils::Data &data) const {
|
||||
cpputils::Data plaintextWithHeader = _prependKeyHeaderToData(key, data);
|
||||
cpputils::Data encrypted = Cipher::encrypt((CryptoPP::byte*)plaintextWithHeader.data(), plaintextWithHeader.size(), _encKey);
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_encrypt(const cpputils::Data &data) const {
|
||||
cpputils::Data encrypted = Cipher::encrypt((CryptoPP::byte*)data.data(), data.size(), _encKey);
|
||||
return _prependFormatHeaderToData(encrypted);
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
inline boost::optional<cpputils::Data> EncryptedBlockStore2<Cipher>::_tryDecrypt(const Key &key, const cpputils::Data &data) const {
|
||||
auto ciphertext = _checkAndRemoveFormatHeader(data);
|
||||
boost::optional<cpputils::Data> decrypted = Cipher::decrypt((CryptoPP::byte*)ciphertext.data(), ciphertext.size(), _encKey);
|
||||
if (boost::none == decrypted) {
|
||||
// TODO Warning
|
||||
_checkFormatHeader(data);
|
||||
boost::optional<cpputils::Data> decrypted = Cipher::decrypt((CryptoPP::byte*)data.dataOffset(sizeof(FORMAT_VERSION_HEADER)), data.size() - sizeof(FORMAT_VERSION_HEADER), _encKey);
|
||||
if (decrypted == boost::none) {
|
||||
// TODO Log warning
|
||||
return boost::none;
|
||||
}
|
||||
if (!_keyHeaderIsCorrect(key, *decrypted)) {
|
||||
// TODO Warning
|
||||
return boost::none;
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
if (FORMAT_VERSION_HEADER_OLD == _readFormatHeader(data)) {
|
||||
if (!_keyHeaderIsCorrect(key, *decrypted)) {
|
||||
return boost::none;
|
||||
}
|
||||
*decrypted = _migrateBlock(*decrypted);
|
||||
// no need to write migrated back to block store because
|
||||
// this migration happens in line with a migration in VersionCountingBlockStore2
|
||||
// which then writes it back
|
||||
}
|
||||
return _removeKeyHeader(*decrypted);
|
||||
#endif
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
template<class Cipher>
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_prependKeyHeaderToData(const Key &key, const cpputils::Data &data) {
|
||||
cpputils::Data result(data.size() + Key::BINARY_LENGTH);
|
||||
std::memcpy(result.data(), key.data(), Key::BINARY_LENGTH);
|
||||
std::memcpy((uint8_t*)result.data() + Key::BINARY_LENGTH, data.data(), data.size());
|
||||
return result;
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_migrateBlock(const cpputils::Data &data) {
|
||||
return data.copyAndRemovePrefix(Key::BINARY_LENGTH);
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
inline bool EncryptedBlockStore2<Cipher>::_keyHeaderIsCorrect(const Key &key, const cpputils::Data &data) {
|
||||
return 0 == std::memcmp(key.data(), data.data(), Key::BINARY_LENGTH);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class Cipher>
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_prependFormatHeaderToData(const cpputils::Data &data) {
|
||||
@ -158,16 +170,21 @@ inline cpputils::Data EncryptedBlockStore2<Cipher>::_prependFormatHeaderToData(c
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_removeKeyHeader(const cpputils::Data &data) {
|
||||
return data.copyAndRemovePrefix(Key::BINARY_LENGTH);
|
||||
inline void EncryptedBlockStore2<Cipher>::_checkFormatHeader(const cpputils::Data &data) {
|
||||
const uint16_t formatVersionHeader = _readFormatHeader(data);
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
const bool formatVersionHeaderValid = formatVersionHeader == FORMAT_VERSION_HEADER || formatVersionHeader == FORMAT_VERSION_HEADER_OLD;
|
||||
#else
|
||||
const bool formatVersionHeaderValid = formatVersionHeader == FORMAT_VERSION_HEADER;
|
||||
#endif
|
||||
if (!formatVersionHeaderValid) {
|
||||
throw std::runtime_error("The encrypted block has the wrong format. Was it created with a newer version of CryFS?");
|
||||
}
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
inline cpputils::Data EncryptedBlockStore2<Cipher>::_checkAndRemoveFormatHeader(const cpputils::Data &data) {
|
||||
if (*reinterpret_cast<decltype(FORMAT_VERSION_HEADER)*>(data.data()) != FORMAT_VERSION_HEADER) {
|
||||
throw std::runtime_error("The encrypted block has the wrong format. Was it created with a newer version of CryFS?");
|
||||
}
|
||||
return data.copyAndRemovePrefix(sizeof(FORMAT_VERSION_HEADER));
|
||||
uint16_t EncryptedBlockStore2<Cipher>::_readFormatHeader(const cpputils::Data &data) {
|
||||
return *reinterpret_cast<decltype(FORMAT_VERSION_HEADER)*>(data.data());
|
||||
}
|
||||
|
||||
template<class Cipher>
|
||||
|
@ -12,16 +12,21 @@ using namespace cpputils::logging;
|
||||
namespace blockstore {
|
||||
namespace versioncounting {
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
constexpr uint16_t VersionCountingBlockStore2::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;
|
||||
|
||||
Data VersionCountingBlockStore2::_prependHeaderToData(uint32_t myClientId, uint64_t version, const Data &data) {
|
||||
static_assert(HEADER_LENGTH == sizeof(FORMAT_VERSION_HEADER) + sizeof(myClientId) + sizeof(version), "Wrong header length");
|
||||
Data VersionCountingBlockStore2::_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));
|
||||
std::memcpy(result.dataOffset(ID_HEADER_OFFSET), key.data(), Key::BINARY_LENGTH);
|
||||
std::memcpy(result.dataOffset(CLIENTID_HEADER_OFFSET), &myClientId, sizeof(myClientId));
|
||||
std::memcpy(result.dataOffset(VERSION_HEADER_OFFSET), &version, sizeof(version));
|
||||
std::memcpy((uint8_t*)result.dataOffset(HEADER_LENGTH), data.data(), data.size());
|
||||
@ -30,11 +35,12 @@ Data VersionCountingBlockStore2::_prependHeaderToData(uint32_t myClientId, uint6
|
||||
|
||||
void VersionCountingBlockStore2::_checkHeader(const Key &key, const Data &data) const {
|
||||
_checkFormatHeader(data);
|
||||
_checkIdHeader(key, data);
|
||||
_checkVersionHeader(key, data);
|
||||
}
|
||||
|
||||
void VersionCountingBlockStore2::_checkFormatHeader(const Data &data) const {
|
||||
if (*reinterpret_cast<decltype(FORMAT_VERSION_HEADER)*>(data.data()) != FORMAT_VERSION_HEADER) {
|
||||
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?");
|
||||
}
|
||||
}
|
||||
@ -48,19 +54,34 @@ void VersionCountingBlockStore2::_checkVersionHeader(const Key &key, const Data
|
||||
}
|
||||
}
|
||||
|
||||
void VersionCountingBlockStore2::_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) {
|
||||
return *reinterpret_cast<decltype(FORMAT_VERSION_HEADER)*>(data.data());
|
||||
}
|
||||
|
||||
uint32_t VersionCountingBlockStore2::_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) {
|
||||
return Key::FromBinary(data.dataOffset(ID_HEADER_OFFSET));
|
||||
}
|
||||
|
||||
uint64_t VersionCountingBlockStore2::_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) const {
|
||||
Data VersionCountingBlockStore2::_removeHeader(const Data &data) {
|
||||
return data.copyAndRemovePrefix(HEADER_LENGTH);
|
||||
}
|
||||
|
||||
@ -86,7 +107,7 @@ VersionCountingBlockStore2::VersionCountingBlockStore2(unique_ref<BlockStore2> b
|
||||
bool VersionCountingBlockStore2::tryCreate(const Key &key, const Data &data) {
|
||||
_checkNoPastIntegrityViolations();
|
||||
uint64_t version = _knownBlockVersions.incrementVersion(key);
|
||||
Data dataWithHeader = _prependHeaderToData(_knownBlockVersions.myClientId(), version, data);
|
||||
Data dataWithHeader = _prependHeaderToData(key, _knownBlockVersions.myClientId(), version, data);
|
||||
return _baseBlockStore->tryCreate(key, dataWithHeader);
|
||||
}
|
||||
|
||||
@ -105,14 +126,34 @@ optional<Data> VersionCountingBlockStore2::load(const Key &key) const {
|
||||
}
|
||||
return optional<Data>(none);
|
||||
}
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
if (FORMAT_VERSION_HEADER_OLD == _readFormatHeader(*loaded)) {
|
||||
Data migrated = _migrateBlock(key, *loaded);
|
||||
_checkHeader(key, migrated);
|
||||
Data content = _removeHeader(migrated);
|
||||
const_cast<VersionCountingBlockStore2*>(this)->store(key, content);
|
||||
return optional<Data>(_removeHeader(migrated));
|
||||
}
|
||||
#endif
|
||||
_checkHeader(key, *loaded);
|
||||
return optional<Data>(_removeHeader(*loaded));
|
||||
}
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
Data VersionCountingBlockStore2::_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);
|
||||
std::memcpy(migrated.dataOffset(ID_HEADER_OFFSET + Key::BINARY_LENGTH), data.dataOffset(sizeof(FORMAT_VERSION_HEADER)), data.size() - sizeof(FORMAT_VERSION_HEADER));
|
||||
ASSERT(migrated.size() == sizeof(FORMAT_VERSION_HEADER) + Key::BINARY_LENGTH + (data.size() - sizeof(FORMAT_VERSION_HEADER)), "Wrong offset computation");
|
||||
return migrated;
|
||||
}
|
||||
#endif
|
||||
|
||||
void VersionCountingBlockStore2::store(const Key &key, const Data &data) {
|
||||
_checkNoPastIntegrityViolations();
|
||||
uint64_t version = _knownBlockVersions.incrementVersion(key);
|
||||
Data dataWithHeader = _prependHeaderToData(_knownBlockVersions.myClientId(), version, data);
|
||||
Data dataWithHeader = _prependHeaderToData(key, _knownBlockVersions.myClientId(), version, data);
|
||||
return _baseBlockStore->store(key, dataWithHeader);
|
||||
}
|
||||
|
||||
@ -170,7 +211,7 @@ void VersionCountingBlockStore2::migrateBlockFromBlockstoreWithoutVersionNumbers
|
||||
return;
|
||||
}
|
||||
cpputils::Data data = std::move(*data_);
|
||||
cpputils::Data dataWithHeader = _prependHeaderToData(knownBlockVersions->myClientId(), version, std::move(data));
|
||||
cpputils::Data dataWithHeader = _prependHeaderToData(key, knownBlockVersions->myClientId(), version, std::move(data));
|
||||
baseBlockStore->store(key, std::move(dataWithHeader));
|
||||
}
|
||||
#endif
|
||||
|
@ -26,14 +26,18 @@ public:
|
||||
void forEachBlock(std::function<void (const Key &)> callback) const override;
|
||||
|
||||
private:
|
||||
// This header is prepended to blocks to allow future versions to have compatibility.
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER = 0;
|
||||
// This format version is prepended to blocks to allow future versions to have compatibility.
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER_OLD = 0;
|
||||
#endif
|
||||
static constexpr uint16_t FORMAT_VERSION_HEADER = 1;
|
||||
|
||||
public:
|
||||
static constexpr uint64_t VERSION_ZERO = 0;
|
||||
static constexpr unsigned int CLIENTID_HEADER_OFFSET = sizeof(FORMAT_VERSION_HEADER);
|
||||
static constexpr unsigned int VERSION_HEADER_OFFSET = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint32_t);
|
||||
static constexpr unsigned int HEADER_LENGTH = sizeof(FORMAT_VERSION_HEADER) + sizeof(uint32_t) + sizeof(VERSION_ZERO);
|
||||
static constexpr unsigned int ID_HEADER_OFFSET = sizeof(FORMAT_VERSION_HEADER);
|
||||
static constexpr unsigned int CLIENTID_HEADER_OFFSET = ID_HEADER_OFFSET + Key::BINARY_LENGTH;
|
||||
static constexpr unsigned int VERSION_HEADER_OFFSET = CLIENTID_HEADER_OFFSET + sizeof(uint32_t);
|
||||
static constexpr unsigned int HEADER_LENGTH = VERSION_HEADER_OFFSET + sizeof(VERSION_ZERO);
|
||||
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
static void migrateFromBlockstoreWithoutVersionNumbers(BlockStore2 *baseBlockStore, const boost::filesystem::path &integrityFilePath, uint32_t myClientId);
|
||||
@ -42,13 +46,19 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static cpputils::Data _prependHeaderToData(uint32_t myClientId, uint64_t version, const cpputils::Data &data);
|
||||
static cpputils::Data _prependHeaderToData(const Key& key, uint32_t myClientId, uint64_t version, const cpputils::Data &data);
|
||||
void _checkHeader(const Key &key, const cpputils::Data &data) const;
|
||||
void _checkFormatHeader(const cpputils::Data &data) const;
|
||||
void _checkIdHeader(const Key &expectedKey, const cpputils::Data &data) const;
|
||||
void _checkVersionHeader(const Key &key, const cpputils::Data &data) const;
|
||||
static uint16_t _readFormatHeader(const cpputils::Data &data);
|
||||
static uint32_t _readClientId(const cpputils::Data &data);
|
||||
static Key _readBlockId(const cpputils::Data &data);
|
||||
static uint64_t _readVersion(const cpputils::Data &data);
|
||||
cpputils::Data _removeHeader(const cpputils::Data &data) const;
|
||||
#ifndef CRYFS_NO_COMPATIBILITY
|
||||
static cpputils::Data _migrateBlock(const Key &key, const cpputils::Data &data);
|
||||
#endif
|
||||
static cpputils::Data _removeHeader(const cpputils::Data &data);
|
||||
void _checkNoPastIntegrityViolations() const;
|
||||
void integrityViolationDetected(const std::string &reason) const;
|
||||
|
||||
|
@ -105,20 +105,6 @@ TEST_F(EncryptedBlockStoreTest, LoadingModifiedBlockFails_WriteSeparately) {
|
||||
EXPECT_EQ(boost::none, loaded);
|
||||
}
|
||||
|
||||
TEST_F(EncryptedBlockStoreTest, LoadingWithDifferentBlockIdFails_WriteOnCreate) {
|
||||
auto key = CreateBlockDirectlyWithFixtureAndReturnKey();
|
||||
auto key2 = CopyBaseBlock(key);
|
||||
auto loaded = blockStore->load(key2);
|
||||
EXPECT_EQ(boost::none, loaded);
|
||||
}
|
||||
|
||||
TEST_F(EncryptedBlockStoreTest, LoadingWithDifferentBlockIdFails_WriteSeparately) {
|
||||
auto key = CreateBlockWriteFixtureToItAndReturnKey();
|
||||
auto key2 = CopyBaseBlock(key);
|
||||
auto loaded = blockStore->load(key2);
|
||||
EXPECT_EQ(boost::none, loaded);
|
||||
}
|
||||
|
||||
TEST_F(EncryptedBlockStoreTest, PhysicalBlockSize_zerophysical) {
|
||||
EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(0));
|
||||
}
|
||||
|
@ -235,6 +235,16 @@ TEST_F(VersionCountingBlockStoreTest, DeletionPrevention_InForEachBlock_DoesntAl
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(VersionCountingBlockStoreTest, LoadingWithDifferentBlockIdFails) {
|
||||
auto key = CreateBlockReturnKey();
|
||||
blockstore::Key key2 = blockstore::Key::FromString("1491BB4932A389EE14BC7090AC772972");
|
||||
baseBlockStore->store(key2, baseBlockStore->load(key).value());
|
||||
EXPECT_THROW(
|
||||
blockStore->load(key2),
|
||||
IntegrityViolationError
|
||||
);
|
||||
}
|
||||
|
||||
// TODO Test more integrity cases:
|
||||
// - RollbackPrevention_DoesntAllowReintroducingDeletedBlocks with different client id (i.e. trying to re-introduce the newest block of a different client)
|
||||
// - RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber with different client id
|
||||
|
@ -25,7 +25,7 @@ namespace cpputils {
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
// This is a fake cipher that uses an indeterministic caesar chiffre and a 4-byte parity for a simple authentication mechanism
|
||||
// This is a fake cipher that uses an indeterministic caesar chiffre and a 4-byte checksum for a simple authentication mechanism
|
||||
class FakeAuthenticatedCipher {
|
||||
public:
|
||||
BOOST_CONCEPT_ASSERT((CipherConcept<FakeAuthenticatedCipher>));
|
||||
@ -58,22 +58,22 @@ namespace cpputils {
|
||||
//Use caesar chiffre on plaintext
|
||||
_caesar((CryptoPP::byte *) result.data() + 1, plaintext, plaintextSize, encKey.value + iv);
|
||||
|
||||
//Add parity information
|
||||
int32_t parity = _parity((CryptoPP::byte *) result.data(), plaintextSize + 1);
|
||||
std::memcpy((CryptoPP::byte *) result.data() + plaintextSize + 1, &parity, 4);
|
||||
//Add checksum information
|
||||
int32_t checksum = _checksum((CryptoPP::byte *) result.data(), encKey, plaintextSize + 1);
|
||||
std::memcpy((CryptoPP::byte *) result.data() + plaintextSize + 1, &checksum, 4);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static boost::optional <Data> decrypt(const CryptoPP::byte *ciphertext, unsigned int ciphertextSize,
|
||||
const EncryptionKey &encKey) {
|
||||
//We need at least 5 bytes (iv + parity)
|
||||
//We need at least 5 bytes (iv + checksum)
|
||||
if (ciphertextSize < 5) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
//Check parity
|
||||
int32_t expectedParity = _parity(ciphertext, plaintextSize(ciphertextSize) + 1);
|
||||
//Check checksum
|
||||
int32_t expectedParity = _checksum(ciphertext, encKey, plaintextSize(ciphertextSize) + 1);
|
||||
int32_t actualParity = *(int32_t * )(ciphertext + plaintextSize(ciphertextSize) + 1);
|
||||
if (expectedParity != actualParity) {
|
||||
return boost::none;
|
||||
@ -89,18 +89,18 @@ namespace cpputils {
|
||||
static constexpr const char *NAME = "FakeAuthenticatedCipher";
|
||||
|
||||
private:
|
||||
static int32_t _parity(const CryptoPP::byte *data, unsigned int size) {
|
||||
int32_t parity = 34343435; // some init value
|
||||
static int32_t _checksum(const CryptoPP::byte *data, FakeKey encKey, unsigned int size) {
|
||||
int32_t checksum = 34343435 * encKey.value; // some init value
|
||||
const int32_t *intData = reinterpret_cast<const int32_t *>(data);
|
||||
unsigned int intSize = size / sizeof(int32_t);
|
||||
for (unsigned int i = 0; i < intSize; ++i) {
|
||||
parity = ((int64_t)parity) + intData[i];
|
||||
checksum = ((int64_t)checksum) + intData[i];
|
||||
}
|
||||
unsigned int remainingBytes = size - 4 * intSize;
|
||||
for (unsigned int i = 0; i < remainingBytes; ++i) {
|
||||
parity = ((int64_t)parity) + (data[4 * intSize + i] << (24 - 8 * i));
|
||||
checksum = ((int64_t)checksum) + (data[4 * intSize + i] << (24 - 8 * i));
|
||||
}
|
||||
return parity;
|
||||
return checksum;
|
||||
}
|
||||
|
||||
static void _caesar(CryptoPP::byte *dst, const CryptoPP::byte *src, unsigned int size, uint8_t key) {
|
||||
|
Loading…
Reference in New Issue
Block a user