Allow decryption interface to fail (needed for authenticated ciphers later)
This commit is contained in:
parent
79283b868b
commit
5adcf4aca1
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "messmer/cpp-utils/macros.h"
|
#include "messmer/cpp-utils/macros.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
namespace encrypted {
|
namespace encrypted {
|
||||||
@ -19,9 +20,9 @@ template<class Cipher>
|
|||||||
class EncryptedBlock: public Block {
|
class EncryptedBlock: public Block {
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<EncryptedBlock> TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const typename Cipher::EncryptionKey &encKey);
|
static std::unique_ptr<EncryptedBlock> TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const typename Cipher::EncryptionKey &encKey);
|
||||||
|
static std::unique_ptr<EncryptedBlock> TryDecrypt(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &key);
|
||||||
|
|
||||||
//TODO Storing key twice (in parent class and in object pointed to). Once would be enough.
|
//TODO Storing key twice (in parent class and in object pointed to). Once would be enough.
|
||||||
EncryptedBlock(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &key);
|
|
||||||
EncryptedBlock(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &key, Data plaintextData);
|
EncryptedBlock(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &key, Data plaintextData);
|
||||||
virtual ~EncryptedBlock();
|
virtual ~EncryptedBlock();
|
||||||
|
|
||||||
@ -40,7 +41,6 @@ private:
|
|||||||
bool _dataChanged;
|
bool _dataChanged;
|
||||||
|
|
||||||
void _encryptToBaseBlock();
|
void _encryptToBaseBlock();
|
||||||
void _decryptFromBaseBlock();
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(EncryptedBlock);
|
DISALLOW_COPY_AND_ASSIGN(EncryptedBlock);
|
||||||
};
|
};
|
||||||
@ -49,8 +49,7 @@ private:
|
|||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
std::unique_ptr<EncryptedBlock<Cipher>> EncryptedBlock<Cipher>::TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const typename Cipher::EncryptionKey &encKey) {
|
std::unique_ptr<EncryptedBlock<Cipher>> EncryptedBlock<Cipher>::TryCreateNew(BlockStore *baseBlockStore, const Key &key, Data data, const typename Cipher::EncryptionKey &encKey) {
|
||||||
Data encrypted(Cipher::ciphertextSize(data.size()));
|
Data encrypted = Cipher::encrypt((byte*)data.data(), data.size(), encKey);
|
||||||
Cipher::encrypt((byte*)data.data(), data.size(), (byte*)encrypted.data(), encKey);
|
|
||||||
auto baseBlock = baseBlockStore->tryCreate(key, std::move(encrypted));
|
auto baseBlock = baseBlockStore->tryCreate(key, std::move(encrypted));
|
||||||
if (baseBlock.get() == nullptr) {
|
if (baseBlock.get() == nullptr) {
|
||||||
//TODO Test this code branch
|
//TODO Test this code branch
|
||||||
@ -61,9 +60,13 @@ std::unique_ptr<EncryptedBlock<Cipher>> EncryptedBlock<Cipher>::TryCreateNew(Blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
EncryptedBlock<Cipher>::EncryptedBlock(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &encKey)
|
std::unique_ptr<EncryptedBlock<Cipher>> EncryptedBlock<Cipher>::TryDecrypt(std::unique_ptr<Block> baseBlock, const typename Cipher::EncryptionKey &encKey) {
|
||||||
:EncryptedBlock(std::move(baseBlock), encKey, Data(Cipher::plaintextSize(baseBlock->size()))) {
|
//TODO Change BlockStore so we can read their "class Data" objects instead of "void *data()", and then we can change the Cipher interface to take Data objects instead of "byte *" + size
|
||||||
_decryptFromBaseBlock();
|
boost::optional<Data> plaintext = Cipher::decrypt((byte*)baseBlock->data(), baseBlock->size(), encKey);
|
||||||
|
if(!plaintext) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::make_unique<EncryptedBlock<Cipher>>(std::move(baseBlock), encKey, std::move(*plaintext));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
@ -103,17 +106,10 @@ size_t EncryptedBlock<Cipher>::size() const {
|
|||||||
return _plaintextData.size();
|
return _plaintextData.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Cipher>
|
|
||||||
void EncryptedBlock<Cipher>::_decryptFromBaseBlock() {
|
|
||||||
//TODO Change BlockStore so we can read their "class Data" objects instead of "void *data()", and then we can change the Cipher interface to take Data objects instead of "byte *" + size
|
|
||||||
Cipher::decrypt((byte*)_baseBlock->data(), (byte*)_plaintextData.data(), _plaintextData.size(), _encKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
void EncryptedBlock<Cipher>::_encryptToBaseBlock() {
|
void EncryptedBlock<Cipher>::_encryptToBaseBlock() {
|
||||||
if (_dataChanged) {
|
if (_dataChanged) {
|
||||||
Data encrypted(Cipher::ciphertextSize(_plaintextData.size()));
|
Data encrypted = Cipher::encrypt((byte*)_plaintextData.data(), _plaintextData.size(), _encKey);
|
||||||
Cipher::encrypt((byte*)_plaintextData.data(), _plaintextData.size(), (byte*)encrypted.data(), _encKey);
|
|
||||||
_baseBlock->write(encrypted.data(), 0, encrypted.size());
|
_baseBlock->write(encrypted.data(), 0, encrypted.size());
|
||||||
_dataChanged = false;
|
_dataChanged = false;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <messmer/cpp-utils/macros.h>
|
#include <messmer/cpp-utils/macros.h>
|
||||||
#include <messmer/cpp-utils/pointer.h>
|
#include <messmer/cpp-utils/pointer.h>
|
||||||
#include "EncryptedBlock.h"
|
#include "EncryptedBlock.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
namespace encrypted {
|
namespace encrypted {
|
||||||
@ -51,7 +52,12 @@ std::unique_ptr<Block> EncryptedBlockStore<Cipher>::load(const Key &key) {
|
|||||||
if (block.get() == nullptr) {
|
if (block.get() == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_unique<EncryptedBlock<Cipher>>(std::move(block), _encKey);
|
auto encBlock = EncryptedBlock<Cipher>::TryDecrypt(std::move(block), _encKey);
|
||||||
|
if (encBlock.get() == nullptr) {
|
||||||
|
//TODO Think about how to do logging
|
||||||
|
|
||||||
|
}
|
||||||
|
return std::move(encBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Cipher>
|
template<class Cipher>
|
||||||
|
@ -9,18 +9,22 @@ namespace encrypted {
|
|||||||
|
|
||||||
constexpr unsigned int AES256_CFB::IV_SIZE;
|
constexpr unsigned int AES256_CFB::IV_SIZE;
|
||||||
|
|
||||||
void AES256_CFB::encrypt(const byte *plaintext, unsigned int plaintextSize, byte *ciphertext, const EncryptionKey &encKey) {
|
Data AES256_CFB::encrypt(const byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) {
|
||||||
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
|
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
|
||||||
auto encryption = CFB_Mode<AES>::Encryption(encKey.data(), encKey.BINARY_LENGTH, iv.data());
|
auto encryption = CFB_Mode<AES>::Encryption(encKey.data(), encKey.BINARY_LENGTH, iv.data());
|
||||||
std::memcpy(ciphertext, iv.data(), IV_SIZE);
|
Data ciphertext(ciphertextSize(plaintextSize));
|
||||||
encryption.ProcessData(ciphertext + IV_SIZE, plaintext, plaintextSize);
|
std::memcpy(ciphertext.data(), iv.data(), IV_SIZE);
|
||||||
|
encryption.ProcessData((byte*)ciphertext.data() + IV_SIZE, plaintext, plaintextSize);
|
||||||
|
return ciphertext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AES256_CFB::decrypt(const byte *ciphertext, byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) {
|
boost::optional<Data> AES256_CFB::decrypt(const byte *ciphertext, unsigned int ciphertextSize, const EncryptionKey &encKey) {
|
||||||
const byte *iv = ciphertext;
|
const byte *ciphertextIV = ciphertext;
|
||||||
const byte *data = ciphertext + IV_SIZE;
|
const byte *ciphertextData = ciphertext + IV_SIZE;
|
||||||
auto decryption = CFB_Mode<AES>::Decryption((byte*)encKey.data(), encKey.BINARY_LENGTH, iv);
|
auto decryption = CFB_Mode<AES>::Decryption((byte*)encKey.data(), encKey.BINARY_LENGTH, ciphertextIV);
|
||||||
decryption.ProcessData(plaintext, data, plaintextSize);
|
Data plaintext(plaintextSize(ciphertextSize));
|
||||||
|
decryption.ProcessData((byte*)plaintext.data(), ciphertextData, plaintext.size());
|
||||||
|
return std::move(plaintext);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_CIPHERS_AES256_CFB_H_
|
#define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_CIPHERS_AES256_CFB_H_
|
||||||
|
|
||||||
#include "../../../utils/FixedSizeData.h"
|
#include "../../../utils/FixedSizeData.h"
|
||||||
|
#include "../../../utils/Data.h"
|
||||||
#include <cryptopp/cryptopp/aes.h>
|
#include <cryptopp/cryptopp/aes.h>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
namespace blockstore {
|
namespace blockstore {
|
||||||
namespace encrypted {
|
namespace encrypted {
|
||||||
@ -24,8 +26,8 @@ public:
|
|||||||
return ciphertextBlockSize - IV_SIZE;
|
return ciphertextBlockSize - IV_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void encrypt(const byte *plaintext, unsigned int plaintextSize, byte *ciphertext, const EncryptionKey &key);
|
static Data encrypt(const byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey);
|
||||||
static void decrypt(const byte *ciphertext, byte *plaintext, unsigned int plaintextSize, const EncryptionKey &key);
|
static boost::optional<Data> decrypt(const byte *ciphertext, unsigned int ciphertextSize, const EncryptionKey &encKey);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr unsigned int IV_SIZE = CryptoPP::AES::BLOCKSIZE;
|
static constexpr unsigned int IV_SIZE = CryptoPP::AES::BLOCKSIZE;
|
||||||
|
@ -30,16 +30,17 @@ public:
|
|||||||
EXPECT_NE(0, std::memcmp(ciphertext.data(), ciphertext2.data(), ciphertext.size()));
|
EXPECT_NE(0, std::memcmp(ciphertext.data(), ciphertext2.data(), ciphertext.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckEncryptedSize(const Data &plaintext) {
|
||||||
|
Data ciphertext = Encrypt(plaintext);
|
||||||
|
EXPECT_EQ(Cipher::ciphertextSize(plaintext.size()), ciphertext.size());
|
||||||
|
}
|
||||||
|
|
||||||
Data Encrypt(const Data &plaintext) {
|
Data Encrypt(const Data &plaintext) {
|
||||||
Data ciphertext(Cipher::ciphertextSize(plaintext.size()));
|
return Cipher::encrypt((byte*)plaintext.data(), plaintext.size(), this->encKey);
|
||||||
Cipher::encrypt((byte*)plaintext.data(), plaintext.size(), (byte*)ciphertext.data(), this->encKey);
|
|
||||||
return ciphertext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data Decrypt(const Data &ciphertext) {
|
Data Decrypt(const Data &ciphertext) {
|
||||||
Data decrypted(Cipher::plaintextSize(ciphertext.size()));
|
return Cipher::decrypt((byte*)ciphertext.data(), ciphertext.size(), this->encKey).value();
|
||||||
Cipher::decrypt((byte*)ciphertext.data(), (byte*) decrypted.data(), decrypted.size(), this->encKey);
|
|
||||||
return decrypted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data CreateZeroes(unsigned int size) {
|
Data CreateZeroes(unsigned int size) {
|
||||||
@ -111,6 +112,13 @@ TYPED_TEST_P(CipherTest, EncryptIsIndeterministic_Data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TYPED_TEST_P(CipherTest, EncryptedSize) {
|
||||||
|
for (auto size: SIZES) {
|
||||||
|
Data plaintext = this->CreateData(size);
|
||||||
|
this->CheckEncryptedSize(plaintext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_TYPED_TEST_CASE_P(CipherTest,
|
REGISTER_TYPED_TEST_CASE_P(CipherTest,
|
||||||
Size_0,
|
Size_0,
|
||||||
Size_1,
|
Size_1,
|
||||||
@ -120,7 +128,8 @@ REGISTER_TYPED_TEST_CASE_P(CipherTest,
|
|||||||
EncryptThenDecrypt_Zeroes,
|
EncryptThenDecrypt_Zeroes,
|
||||||
EncryptThenDecrypt_Data,
|
EncryptThenDecrypt_Data,
|
||||||
EncryptIsIndeterministic_Zeroes,
|
EncryptIsIndeterministic_Zeroes,
|
||||||
EncryptIsIndeterministic_Data
|
EncryptIsIndeterministic_Data,
|
||||||
|
EncryptedSize
|
||||||
);
|
);
|
||||||
|
|
||||||
//TODO For authenticated ciphers, we need test cases checking that authentication fails on manipulations
|
//TODO For authenticated ciphers, we need test cases checking that authentication fails on manipulations
|
||||||
|
Loading…
Reference in New Issue
Block a user