2015-04-09 19:22:09 +02:00
# pragma once
2015-10-15 13:09:21 +02:00
# ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_ENCRYPTEDBLOCK_H_
# define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_ENCRYPTEDBLOCK_H_
2015-04-09 19:22:09 +02:00
# include "../../interface/Block.h"
2015-04-25 02:48:41 +02:00
# include <messmer/cpp-utils/data/Data.h>
2015-04-18 14:47:12 +02:00
# include "../../interface/BlockStore.h"
2015-04-09 19:22:09 +02:00
# include "messmer/cpp-utils/macros.h"
# include <memory>
2015-04-26 22:20:04 +02:00
# include <iostream>
2015-04-24 21:08:36 +02:00
# include <boost/optional.hpp>
2015-10-27 23:27:40 +01:00
# include <messmer/cpp-utils/crypto/symmetric/Cipher.h>
2015-07-22 13:42:07 +02:00
# include <messmer/cpp-utils/assert/assert.h>
2015-10-05 18:54:16 +02:00
# include <mutex>
2015-10-17 17:50:30 +02:00
# include <messmer/cpp-utils/logging/logging.h>
2015-04-09 19:22:09 +02:00
namespace blockstore {
namespace encrypted {
2015-04-24 18:14:25 +02:00
template < class Cipher > class EncryptedBlockStore ;
2015-04-09 19:22:09 +02:00
2015-05-06 16:16:18 +02:00
//TODO Test EncryptedBlock
2015-04-24 18:14:25 +02:00
template < class Cipher >
2015-11-27 14:06:40 +01:00
class EncryptedBlock final : public Block {
2015-04-09 19:22:09 +02:00
public :
2015-10-27 23:27:40 +01:00
BOOST_CONCEPT_ASSERT ( ( cpputils : : CipherConcept < Cipher > ) ) ;
2015-07-20 18:57:48 +02:00
static boost : : optional < cpputils : : unique_ref < EncryptedBlock > > TryCreateNew ( BlockStore * baseBlockStore , const Key & key , cpputils : : Data data , const typename Cipher : : EncryptionKey & encKey ) ;
2015-07-21 14:50:52 +02:00
static boost : : optional < cpputils : : unique_ref < EncryptedBlock > > TryDecrypt ( cpputils : : unique_ref < Block > baseBlock , const typename Cipher : : EncryptionKey & key ) ;
2015-04-24 18:14:25 +02:00
2015-04-09 19:22:09 +02:00
//TODO Storing key twice (in parent class and in object pointed to). Once would be enough.
2015-07-21 14:50:52 +02:00
EncryptedBlock ( cpputils : : unique_ref < Block > baseBlock , const typename Cipher : : EncryptionKey & key , cpputils : : Data plaintextWithHeader ) ;
2015-11-27 14:06:40 +01:00
~ EncryptedBlock ( ) ;
2015-04-09 21:17:28 +02:00
2015-04-09 19:22:09 +02:00
const void * data ( ) const override ;
2015-04-26 16:36:48 +02:00
void write ( const void * source , uint64_t offset , uint64_t count ) override ;
2015-04-09 19:22:09 +02:00
void flush ( ) override ;
size_t size ( ) const override ;
2015-07-21 14:50:52 +02:00
cpputils : : unique_ref < Block > releaseBlock ( ) ;
2015-04-09 21:17:28 +02:00
2015-04-09 19:22:09 +02:00
private :
2015-07-21 14:50:52 +02:00
cpputils : : unique_ref < Block > _baseBlock ;
2015-04-26 16:36:48 +02:00
cpputils : : Data _plaintextWithHeader ;
2015-04-24 18:14:25 +02:00
typename Cipher : : EncryptionKey _encKey ;
2015-04-09 21:17:28 +02:00
bool _dataChanged ;
2015-04-26 16:36:48 +02:00
static constexpr unsigned int HEADER_LENGTH = Key : : BINARY_LENGTH ;
2015-04-09 21:17:28 +02:00
void _encryptToBaseBlock ( ) ;
2015-04-26 16:36:48 +02:00
static cpputils : : Data _prependKeyHeaderToData ( const Key & key , cpputils : : Data data ) ;
static bool _keyHeaderIsCorrect ( const Key & key , const cpputils : : Data & data ) ;
2015-04-09 19:22:09 +02:00
2015-10-05 18:54:16 +02:00
std : : mutex _mutex ;
2015-04-09 19:22:09 +02:00
DISALLOW_COPY_AND_ASSIGN ( EncryptedBlock ) ;
} ;
2015-04-26 16:36:48 +02:00
template < class Cipher >
constexpr unsigned int EncryptedBlock < Cipher > : : HEADER_LENGTH ;
2015-04-24 18:14:25 +02:00
template < class Cipher >
2015-07-20 18:57:48 +02:00
boost : : optional < cpputils : : unique_ref < EncryptedBlock < Cipher > > > EncryptedBlock < Cipher > : : TryCreateNew ( BlockStore * baseBlockStore , const Key & key , cpputils : : Data data , const typename Cipher : : EncryptionKey & encKey ) {
2015-04-26 16:36:48 +02:00
cpputils : : Data plaintextWithHeader = _prependKeyHeaderToData ( key , std : : move ( data ) ) ;
cpputils : : Data encrypted = Cipher : : encrypt ( ( byte * ) plaintextWithHeader . data ( ) , plaintextWithHeader . size ( ) , encKey ) ;
2015-04-24 18:14:25 +02:00
auto baseBlock = baseBlockStore - > tryCreate ( key , std : : move ( encrypted ) ) ;
2015-07-20 18:57:48 +02:00
if ( baseBlock = = boost : : none ) {
2015-04-24 18:14:25 +02:00
//TODO Test this code branch
2015-07-20 18:57:48 +02:00
return boost : : none ;
2015-04-24 18:14:25 +02:00
}
2015-07-21 14:50:52 +02:00
return cpputils : : make_unique_ref < EncryptedBlock > ( std : : move ( * baseBlock ) , encKey , std : : move ( plaintextWithHeader ) ) ;
2015-04-24 18:14:25 +02:00
}
template < class Cipher >
2015-07-21 14:50:52 +02:00
boost : : optional < cpputils : : unique_ref < EncryptedBlock < Cipher > > > EncryptedBlock < Cipher > : : TryDecrypt ( cpputils : : unique_ref < Block > baseBlock , const typename Cipher : : EncryptionKey & encKey ) {
2015-04-24 21:08:36 +02:00
//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
2015-04-26 16:36:48 +02:00
boost : : optional < cpputils : : Data > plaintextWithHeader = Cipher : : decrypt ( ( byte * ) baseBlock - > data ( ) , baseBlock - > size ( ) , encKey ) ;
2015-07-21 14:50:52 +02:00
if ( plaintextWithHeader = = boost : : none ) {
2015-04-26 16:36:48 +02:00
//Decryption failed (e.g. an authenticated cipher detected modifications to the ciphertext)
2015-10-17 17:50:30 +02:00
cpputils : : logging : : LOG ( cpputils : : logging : : WARN ) < < " Decrypting block " < < baseBlock - > key ( ) . ToString ( ) < < " failed. Was the block modified by an attacker? " ;
2015-07-21 14:50:52 +02:00
return boost : : none ;
2015-04-24 21:08:36 +02:00
}
2015-04-26 16:36:48 +02:00
if ( ! _keyHeaderIsCorrect ( baseBlock - > key ( ) , * plaintextWithHeader ) ) {
//The stored key in the block data is incorrect - an attacker might have exchanged the contents with the encrypted data from a different block
2015-10-17 17:50:30 +02:00
cpputils : : logging : : LOG ( cpputils : : logging : : WARN ) < < " Decrypting block " < < baseBlock - > key ( ) . ToString ( ) < < " failed due to invalid block key. Was the block modified by an attacker? " ;
2015-07-21 14:50:52 +02:00
return boost : : none ;
2015-04-26 16:36:48 +02:00
}
2015-07-21 14:50:52 +02:00
return cpputils : : make_unique_ref < EncryptedBlock < Cipher > > ( std : : move ( baseBlock ) , encKey , std : : move ( * plaintextWithHeader ) ) ;
2015-04-26 16:36:48 +02:00
}
template < class Cipher >
cpputils : : Data EncryptedBlock < Cipher > : : _prependKeyHeaderToData ( const Key & key , cpputils : : Data data ) {
static_assert ( HEADER_LENGTH > = Key : : BINARY_LENGTH , " Key doesn't fit into the header " ) ;
cpputils : : Data result ( data . size ( ) + HEADER_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 ;
}
template < class Cipher >
bool EncryptedBlock < Cipher > : : _keyHeaderIsCorrect ( const Key & key , const cpputils : : Data & data ) {
return 0 = = std : : memcmp ( key . data ( ) , data . data ( ) , Key : : BINARY_LENGTH ) ;
2015-04-24 18:14:25 +02:00
}
template < class Cipher >
2015-07-21 14:50:52 +02:00
EncryptedBlock < Cipher > : : EncryptedBlock ( cpputils : : unique_ref < Block > baseBlock , const typename Cipher : : EncryptionKey & encKey , cpputils : : Data plaintextWithHeader )
2015-04-24 18:14:25 +02:00
: Block ( baseBlock - > key ( ) ) ,
_baseBlock ( std : : move ( baseBlock ) ) ,
2015-04-26 16:36:48 +02:00
_plaintextWithHeader ( std : : move ( plaintextWithHeader ) ) ,
2015-04-24 18:14:25 +02:00
_encKey ( encKey ) ,
2015-10-17 21:10:26 +02:00
_dataChanged ( false ) ,
_mutex ( ) {
2015-04-24 18:14:25 +02:00
}
template < class Cipher >
EncryptedBlock < Cipher > : : ~ EncryptedBlock ( ) {
2015-10-05 18:54:16 +02:00
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
2015-04-24 18:14:25 +02:00
_encryptToBaseBlock ( ) ;
}
template < class Cipher >
const void * EncryptedBlock < Cipher > : : data ( ) const {
2015-04-26 16:36:48 +02:00
return ( uint8_t * ) _plaintextWithHeader . data ( ) + HEADER_LENGTH ;
2015-04-24 18:14:25 +02:00
}
template < class Cipher >
2015-04-26 16:36:48 +02:00
void EncryptedBlock < Cipher > : : write ( const void * source , uint64_t offset , uint64_t count ) {
2015-07-22 13:42:07 +02:00
ASSERT ( offset < = size ( ) & & offset + count < = size ( ) , " Write outside of valid area " ) ; //Also check offset < size() because of possible overflow in the addition
2015-04-26 16:36:48 +02:00
std : : memcpy ( ( uint8_t * ) _plaintextWithHeader . data ( ) + HEADER_LENGTH + offset , source , count ) ;
2015-04-24 18:14:25 +02:00
_dataChanged = true ;
}
template < class Cipher >
void EncryptedBlock < Cipher > : : flush ( ) {
2015-10-05 18:54:16 +02:00
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
2015-04-24 18:14:25 +02:00
_encryptToBaseBlock ( ) ;
return _baseBlock - > flush ( ) ;
}
template < class Cipher >
size_t EncryptedBlock < Cipher > : : size ( ) const {
2015-04-26 16:36:48 +02:00
return _plaintextWithHeader . size ( ) - HEADER_LENGTH ;
2015-04-24 18:14:25 +02:00
}
template < class Cipher >
void EncryptedBlock < Cipher > : : _encryptToBaseBlock ( ) {
if ( _dataChanged ) {
2015-04-26 16:36:48 +02:00
cpputils : : Data encrypted = Cipher : : encrypt ( ( byte * ) _plaintextWithHeader . data ( ) , _plaintextWithHeader . size ( ) , _encKey ) ;
2015-04-24 18:14:25 +02:00
_baseBlock - > write ( encrypted . data ( ) , 0 , encrypted . size ( ) ) ;
_dataChanged = false ;
}
}
template < class Cipher >
2015-07-21 14:50:52 +02:00
cpputils : : unique_ref < Block > EncryptedBlock < Cipher > : : releaseBlock ( ) {
2015-10-05 18:54:16 +02:00
std : : unique_lock < std : : mutex > lock ( _mutex ) ;
2015-09-29 18:51:59 +02:00
_encryptToBaseBlock ( ) ;
2015-04-24 18:14:25 +02:00
return std : : move ( _baseBlock ) ;
}
2015-04-09 19:22:09 +02:00
}
}
# endif