libcryfs/implementations/encrypted/EncryptedBlock.cpp

79 lines
2.6 KiB
C++
Raw Normal View History

#include "EncryptedBlock.h"
2015-04-09 21:17:28 +02:00
#include <cryptopp/cryptopp/modes.h>
#include "../../utils/BlockStoreUtils.h"
2015-04-09 22:11:40 +02:00
using CryptoPP::CFB_Mode;
2015-04-09 21:17:28 +02:00
using CryptoPP::AES;
using std::make_unique;
2015-04-10 00:57:10 +02:00
//TODO not only encryption, but also hmac
namespace blockstore {
namespace encrypted {
2015-04-09 21:17:28 +02:00
constexpr unsigned int EncryptedBlock::IV_SIZE;
std::unique_ptr<EncryptedBlock> EncryptedBlock::CreateNew(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey) {
auto block = make_unique<EncryptedBlock>(std::move(baseBlock), encKey);
//We have to explicitly fill the block with zeroes, because otherwise the encrypted version is filled with zeroes and not the plaintext version
utils::fillWithZeroes(block.get());
return block;
}
EncryptedBlock::EncryptedBlock(std::unique_ptr<Block> baseBlock, const EncryptionKey &encKey)
2015-04-09 21:17:28 +02:00
:Block(baseBlock->key()),
_baseBlock(std::move(baseBlock)),
_plaintextData(USEABLE_BLOCK_SIZE(_baseBlock->size())),
_encKey(encKey),
_dataChanged(false) {
_decryptFromBaseBlock();
}
EncryptedBlock::~EncryptedBlock() {
flush();
}
const void *EncryptedBlock::data() const {
2015-04-09 21:17:28 +02:00
return _plaintextData.data();
}
void EncryptedBlock::write(const void *source, uint64_t offset, uint64_t size) {
2015-04-09 21:17:28 +02:00
assert(offset <= _plaintextData.size() && offset + size <= _plaintextData.size()); //Also check offset < _data->size() because of possible overflow in the addition
std::memcpy((uint8_t*)_plaintextData.data()+offset, source, size);
_dataChanged = true;
}
void EncryptedBlock::flush() {
2015-04-09 21:17:28 +02:00
_encryptToBaseBlock();
return _baseBlock->flush();
}
size_t EncryptedBlock::size() const {
2015-04-09 21:17:28 +02:00
return _plaintextData.size();
}
void EncryptedBlock::_decryptFromBaseBlock() {
const byte *iv = (byte*)_baseBlock->data();
const byte *data = (byte*)_baseBlock->data() + IV_SIZE;
2015-04-09 22:11:40 +02:00
auto decryption = CFB_Mode<AES>::Decryption((byte*)_encKey.data(), EncryptionKey::BINARY_LENGTH, iv);
decryption.ProcessData((byte*)_plaintextData.data(), data, _plaintextData.size());
2015-04-09 21:17:28 +02:00
}
void EncryptedBlock::_encryptToBaseBlock() {
if (_dataChanged) {
FixedSizeData<IV_SIZE> iv = FixedSizeData<IV_SIZE>::CreateRandom();
2015-04-09 22:11:40 +02:00
auto encryption = CFB_Mode<AES>::Encryption(_encKey.data(), EncryptionKey::BINARY_LENGTH, iv.data());
//TODO More performance when not using "Data encrypted" object, but specialized CryptoPP sink
Data encrypted(_plaintextData.size());
encryption.ProcessData((byte*)encrypted.data(), (byte*)_plaintextData.data(), _plaintextData.size());
2015-04-09 21:17:28 +02:00
_baseBlock->write(iv.data(), 0, IV_SIZE);
2015-04-09 22:11:40 +02:00
_baseBlock->write(encrypted.data(), IV_SIZE, encrypted.size());
2015-04-09 21:17:28 +02:00
_dataChanged = false;
}
}
}
}