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 ;
2015-04-18 14:47:12 +02:00
std : : unique_ptr < EncryptedBlock > EncryptedBlock : : TryCreateNew ( BlockStore * baseBlockStore , const Key & key , Data data , const EncryptionKey & encKey ) {
Data encrypted = _encrypt ( data , encKey ) ;
auto baseBlock = baseBlockStore - > tryCreate ( key , std : : move ( encrypted ) ) ;
if ( baseBlock . get ( ) = = nullptr ) {
//TODO Test this code branch
return nullptr ;
}
return make_unique < EncryptedBlock > ( std : : move ( baseBlock ) , encKey ) ;
2015-04-09 21:17:28 +02:00
}
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 ( ) {
2015-04-18 14:47:12 +02:00
_encryptToBaseBlock ( ) ;
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 ) {
2015-04-18 14:47:12 +02:00
Data encrypted = _encrypt ( _plaintextData , _encKey ) ;
_baseBlock - > write ( encrypted . data ( ) , 0 , encrypted . size ( ) ) ;
2015-04-09 21:17:28 +02:00
_dataChanged = false ;
}
2015-04-09 19:22:09 +02:00
}
2015-04-18 14:47:12 +02:00
Data EncryptedBlock : : _encrypt ( const Data & plaintext , const EncryptionKey & encKey ) {
FixedSizeData < IV_SIZE > iv = FixedSizeData < IV_SIZE > : : CreateRandom ( ) ;
auto encryption = CFB_Mode < AES > : : Encryption ( encKey . data ( ) , EncryptionKey : : BINARY_LENGTH , iv . data ( ) ) ;
//TODO More performance when not using "Data encrypted" object, but encrypting directly to a target that was specified via a parameter using a specialized CryptoPP sink
Data encrypted ( IV_SIZE + plaintext . size ( ) ) ;
std : : memcpy ( encrypted . data ( ) , iv . data ( ) , IV_SIZE ) ;
encryption . ProcessData ( ( byte * ) encrypted . data ( ) + IV_SIZE , ( byte * ) plaintext . data ( ) , plaintext . size ( ) ) ;
return encrypted ;
}
2015-04-09 19:22:09 +02:00
}
}