20 #ifndef _ANCH_CRYPTO_BC_MODOP_H_ 21 #define _ANCH_CRYPTO_BC_MODOP_H_ 23 #include "crypto/cipher/invalidBlockException.hpp" 29 #include <condition_variable> 33 #include "threadPool.hpp" 48 template<
typename Derived,
typename Cipher>
56 bool _cipherParallelizable;
59 bool _decipherParallelizable;
62 unsigned int _nbThread;
65 std::mutex _streamMutex;
68 std::condition_variable _writeBlock;
71 std::atomic<uint32_t> _endIdx;
74 std::atomic<uint32_t> _writeIdx;
77 std::atomic<bool> _error;
80 std::ostream* _stream;
95 bool decipherParallelizable,
96 unsigned int nbThread = 1):
97 _cipherParallelizable(cipherParallelizable),
98 _decipherParallelizable(decipherParallelizable),
104 if(nbThread == 0 && (cipherParallelizable || decipherParallelizable)) {
105 _nbThread = std::thread::hardware_concurrency();
134 std::ostream& output,
135 const std::string& key) {
136 if(input && output) {
138 if(!_cipherParallelizable || _nbThread == 1) {
139 cipherSequentially(input, output, key);
142 cipherInParallel(input, output, key);
157 std::ostream& output,
158 const std::string& key) {
159 if(input && output) {
160 std::array<uint8_t,Cipher::getBlockSize()> prevData =
reset();
161 if(!_decipherParallelizable || _nbThread == 1) {
162 decipherSequentially(input, output, key, prevData);
165 decipherInParallel(input, output, key, prevData);
185 virtual std::size_t
cipherBlock(std::array<uint8_t,Cipher::getBlockSize()>& input,
186 std::streamsize nbRead,
187 std::array<uint8_t,Cipher::getBlockSize()>& output,
205 virtual std::size_t
decipherBlock(std::array<uint8_t,Cipher::getBlockSize()>& input,
206 std::array<uint8_t,Cipher::getBlockSize()>& prevInput,
207 std::streamsize nbRead,
209 std::array<uint8_t,Cipher::getBlockSize()>& output,
218 virtual const std::array<uint8_t,Cipher::getBlockSize()>&
reset() = 0;
228 inline void cipherSequentially(std::istream& input,
229 std::ostream& output,
230 const std::string& key) {
231 Cipher
cipher(reinterpret_cast<const uint8_t*>(key.data()));
232 std::array<uint8_t, Cipher::getBlockSize()> data;
233 std::array<uint8_t, Cipher::getBlockSize()> out;
235 while(!input.eof()) {
236 input.read(reinterpret_cast<char*>(data.data()), Cipher::getBlockSize());
237 std::streamsize nbRead = input.gcount();
241 std::size_t nbBlocks =
cipherBlock(data, nbRead, out, index, cipher);
242 for(std::size_t i = 0 ; i < nbBlocks ; ++i) {
257 inline void cipherInParallel(std::istream& input,
258 std::ostream& output,
259 const std::string& key) {
260 std::array<uint8_t,Cipher::getBlockSize()>* data =
new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
261 std::array<uint8_t,Cipher::getBlockSize()>* result =
new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
262 std::size_t* nbWrite =
new std::size_t[_nbThread];
264 std::deque<std::thread> threads;
265 std::vector<Cipher> ciph;
266 ciph.push_back(Cipher(reinterpret_cast<const uint8_t*>(key.data())));
267 for(std::size_t i = 1 ; i < _nbThread ; ++i) {
268 ciph.push_back(Cipher(ciph[0]));
270 while(!input.eof()) {
271 for(std::size_t i = 0 ; i < _nbThread ; ++i) {
272 input.read(reinterpret_cast<char*>(data[i].data()), Cipher::getBlockSize());
273 std::streamsize nbRead = input.gcount();
277 threads.push_back(std::thread(&Derived::deferredCipherBlock,
284 std::ref(nbWrite[i])));
285 if(nbRead != Cipher::getBlockSize()) {
289 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
290 std::thread& th = threads.front();
292 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
293 output << result[i][j];
313 void decipherSequentially(std::istream& input,
314 std::ostream& output,
315 const std::string& key,
316 std::array<uint8_t,Cipher::getBlockSize()>& prevData) {
317 Cipher
cipher(reinterpret_cast<const uint8_t*>(key.data()));
318 std::array<uint8_t,Cipher::getBlockSize()> out;
319 std::array<uint8_t,Cipher::getBlockSize()> data;
320 std::array<uint8_t,Cipher::getBlockSize()> cipherData;
321 input.read(reinterpret_cast<char*>(data.data()), Cipher::getBlockSize());
322 std::streamsize nbRead = input.gcount();
326 std::size_t read = nbRead;
327 input.read(reinterpret_cast<char*>(data.data()), Cipher::getBlockSize());
329 std::size_t end =
decipherBlock(cipherData, prevData, read, input.eof(), out, index,
cipher);
330 for(std::size_t i = 0 ; i < end ; ++i) {
334 prevData = cipherData;
335 nbRead = input.gcount();
338 }
while(nbRead != 0);
350 inline void decipherInParallel(std::istream& input,
351 std::ostream& output,
352 const std::string& key,
353 std::array<uint8_t,Cipher::getBlockSize()>& prevData) {
354 std::array<uint8_t,Cipher::getBlockSize()>* data =
new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread + 1];
355 std::array<uint8_t,Cipher::getBlockSize()>* result =
new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
356 std::size_t* nbWrite =
new std::size_t[_nbThread];
358 std::deque<std::thread> threads;
359 std::vector<Cipher> ciph;
360 ciph.push_back(Cipher(reinterpret_cast<const uint8_t*>(key.data())));
361 for(std::size_t i = 1 ; i < _nbThread ; ++i) {
362 ciph.push_back(Cipher(ciph[0]));
364 bool lastBlock =
false;
365 input.read(reinterpret_cast<char*>(data[0].data()), Cipher::getBlockSize());
366 std::size_t nbRead = input.gcount();
368 for(std::size_t i = 0, idx = 1 ; i < _nbThread ; ++i, ++idx) {
369 input.read(reinterpret_cast<char*>(data[idx].data()), Cipher::getBlockSize());
370 std::streamsize nextCount = input.gcount();
374 threads.push_back(std::thread(&Derived::deferredDecipherBlock,
383 std::ref(nbWrite[i])));
390 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
391 std::thread& th = threads.front();
393 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
394 output << result[i][j];
401 data[0] = data[_nbThread];
402 }
while(!input.eof() && !lastBlock);
418 void deferredCipherBlock(uint32_t index,
419 std::array<uint8_t,Cipher::getBlockSize()>& input,
420 std::streamsize nbRead,
421 std::array<uint8_t,Cipher::getBlockSize()>& output,
423 std::size_t& nbWrite) {
424 nbWrite =
cipherBlock(input, nbRead, output, index, cipher);
436 virtual void deferredDecipherBlock(uint32_t index,
437 std::array<uint8_t, Cipher::getBlockSize()>& input,
438 std::array<uint8_t, Cipher::getBlockSize()> prevInput,
439 std::streamsize nbRead,
441 std::array<uint8_t, Cipher::getBlockSize()>& output,
443 std::size_t& nbWrite) {
445 nbWrite =
decipherBlock(input, prevInput, nbRead, lastBlock, output, index, cipher);
461 _nbThread = nbThread;
470 #endif // _ANCH_CRYPTO_BC_MODOP_H_ void setNbThread(unsigned int nbThread)
Definition: bcModOp.hpp:460
virtual std::size_t cipherBlock(std::array< uint8_t, Cipher::getBlockSize()> &input, std::streamsize nbRead, std::array< uint8_t, Cipher::getBlockSize()> &output, uint32_t index, Cipher &cipher)=0
BlockCipherModeOfOperation(bool cipherParallelizable, bool decipherParallelizable, unsigned int nbThread=1)
Definition: bcModOp.hpp:94
Exception on receiving an invalid block.
Definition: invalidBlockException.hpp:39
virtual std::size_t decipherBlock(std::array< uint8_t, Cipher::getBlockSize()> &input, std::array< uint8_t, Cipher::getBlockSize()> &prevInput, std::streamsize nbRead, bool lastBlock, std::array< uint8_t, Cipher::getBlockSize()> &output, uint32_t index, Cipher &cipher)=0
Thread pool utility class.
Definition: threadPool.hpp:45
AnCH framework base namespace.
Definition: base64.hpp:28
void cipher(std::istream &input, std::ostream &output, const std::string &key)
Definition: bcModOp.hpp:133
Block cipher mode of operation interface.
Definition: bcModOp.hpp:49
void decipher(std::istream &input, std::ostream &output, const std::string &key)
Definition: bcModOp.hpp:156
virtual const std::array< uint8_t, Cipher::getBlockSize()> & reset()=0
virtual ~BlockCipherModeOfOperation()
Definition: bcModOp.hpp:118