2015-04-09 19:22:09 +02:00
# 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-09 19:22:09 +02:00
2015-04-10 00:57:10 +02:00
//TODO not only encryption, but also hmac
2015-04-09 19:22:09 +02:00
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 ;
}
2015-04-09 20:14:12 +02:00
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 ( ) ;
2015-04-09 19:22:09 +02:00
}
const void * EncryptedBlock : : data ( ) const {
2015-04-09 21:17:28 +02:00
return _plaintextData . data ( ) ;
2015-04-09 19:22:09 +02:00
}
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 ;
2015-04-09 19:22:09 +02:00
}
void EncryptedBlock : : flush ( ) {
2015-04-09 21:17:28 +02:00
_encryptToBaseBlock ( ) ;
2015-04-09 19:22:09 +02:00
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 ;
}
2015-04-09 19:22:09 +02:00
}
}
}