AnCH Framework 0.1
Another C++ Hack Framework
 
Loading...
Searching...
No Matches
bcModOp.hpp
1/*
2 ANCH Framework: ANother C++ Hack is a C++ framework based on C++11 standard
3 Copyright (C) 2012 Vincent Lachenal
4
5 This file is part of ANCH Framework.
6
7 ANCH Framework is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 ANCH Framework is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with ANCH Framework. If not, see <http://www.gnu.org/licenses/>.
19*/
20#pragma once
21
22#include "crypto/cipher/invalidBlockException.hpp"
23
24#include <istream>
25#include <ostream>
26#include <array>
27#include <thread>
28#include <condition_variable>
29#include <cstring>
30#include <map>
31
32#include "threadPool.hpp"
33
34
35namespace anch {
36 namespace crypto {
37
47 template<typename Derived, typename Cipher>
49
50 friend class anch::ThreadPool;
51
52 // Attributes +
53 private:
55 bool _cipherParallelizable;
56
58 bool _decipherParallelizable;
59
61 unsigned int _nbThread;
62
64 std::mutex _streamMutex;
65
67 std::condition_variable _writeBlock;
68
70 std::atomic<uint32_t> _endIdx;
71
73 std::atomic<uint32_t> _writeIdx;
74
76 std::atomic<bool> _error;
77
79 std::ostream* _stream;
80 // Attributes -
81
82
83 // Constructors +
84 protected:
93 BlockCipherModeOfOperation(bool cipherParallelizable,
94 bool decipherParallelizable,
95 unsigned int nbThread = 1);
96 // Constructors -
97
98
99 // Destructor +
104 // Destructor -
105
106
107 // Methods +
108 public:
116 void cipher(std::istream& input, std::ostream& output, const std::string& key);
117
125 void decipher(std::istream& input, std::ostream& output, const std::string& key);
126
127 protected:
140 virtual std::size_t cipherBlock(std::array<uint8_t,Cipher::getBlockSize()>& input,
141 std::streamsize nbRead,
142 std::array<uint8_t,Cipher::getBlockSize()>& output,
143 uint32_t index,
144 Cipher& cipher) = 0;
145
160 virtual std::size_t decipherBlock(std::array<uint8_t,Cipher::getBlockSize()>& input,
161 std::array<uint8_t,Cipher::getBlockSize()>& prevInput,
162 std::streamsize nbRead,
163 bool lastBlock,
164 std::array<uint8_t,Cipher::getBlockSize()>& output,
165 uint32_t index,
166 Cipher& cipher) = 0;
167
173 virtual const std::array<uint8_t,Cipher::getBlockSize()>& reset() = 0;
174
175 private:
183 void cipherSequentially(std::istream& input, std::ostream& output, const std::string& key);
184
192 void cipherInParallel(std::istream& input, std::ostream& output, const std::string& key);
193
202 void decipherSequentially(std::istream& input,
203 std::ostream& output,
204 const std::string& key,
205 std::array<uint8_t,Cipher::getBlockSize()>& prevData);
206
215 void decipherInParallel(std::istream& input,
216 std::ostream& output,
217 const std::string& key,
218 std::array<uint8_t,Cipher::getBlockSize()>& prevData);
219
228 void deferredCipherBlock(uint32_t index,
229 std::array<uint8_t,Cipher::getBlockSize()>& input,
230 std::streamsize nbRead,
231 std::array<uint8_t,Cipher::getBlockSize()>& output,
232 Cipher& cipher,
233 std::size_t& nbWrite);
234
244 virtual void deferredDecipherBlock(uint32_t index,
245 std::array<uint8_t, Cipher::getBlockSize()>& input,
246 std::array<uint8_t, Cipher::getBlockSize()> prevInput,
247 std::streamsize nbRead,
248 bool lastBlock,
249 std::array<uint8_t, Cipher::getBlockSize()>& output,
250 Cipher& cipher,
251 std::size_t& nbWrite);
252 // Methods -
253
254
255 // Accessors +
256 public:
262 void setNbThread(unsigned int nbThread);
263 // Accessors -
264
265 };
266
267 // Constructors +
268 template<typename Derived, typename Cipher>
270 bool decipherParallelizable,
271 unsigned int nbThread):
272 _cipherParallelizable(cipherParallelizable),
273 _decipherParallelizable(decipherParallelizable),
274 _nbThread(nbThread),
275 _writeBlock(),
276 _endIdx(UINT32_MAX),
277 _writeIdx(0),
278 _error(false) {
279 if(nbThread == 0 && (cipherParallelizable || decipherParallelizable)) {
280 _nbThread = std::thread::hardware_concurrency();
281 if(_nbThread == 0) { // Keep at least 1 thread running
282 _nbThread = 1;
283 }
284 }
285 }
286 // Constructors -
287
288
289 // Destructor +
290 template<typename Derived, typename Cipher>
294 // Destructor -
295
296
297 // Methods +
298 template<typename Derived, typename Cipher>
299 void
301 std::ostream& output,
302 const std::string& key) {
303 if(input && output) {
304 reset();
305 if(!_cipherParallelizable || _nbThread == 1) {
306 cipherSequentially(input, output, key);
307
308 } else {
309 cipherInParallel(input, output, key);
310 }
311 } else {
312 throw std::ios_base::failure("Input and/or output streams are closed");
313 }
314 }
315
316 template<typename Derived, typename Cipher>
317 void
319 std::ostream& output,
320 const std::string& key) {
321 if(input && output) {
322 std::array<uint8_t,Cipher::getBlockSize()> prevData = reset();
323 if(!_decipherParallelizable || _nbThread == 1) {
324 decipherSequentially(input, output, key, prevData);
325
326 } else {
327 decipherInParallel(input, output, key, prevData);
328 }
329 } else {
330 throw std::ios_base::failure("Input and/or output streams are closed");
331 }
332 }
333
334 template<typename Derived, typename Cipher>
335 inline void
336 BlockCipherModeOfOperation<Derived,Cipher>::cipherSequentially(std::istream& input,
337 std::ostream& output,
338 const std::string& key) {
339 Cipher cipher(reinterpret_cast<const uint8_t*>(key.data()));
340 std::array<uint8_t, Cipher::getBlockSize()> data;
341 std::array<uint8_t, Cipher::getBlockSize()> out;
342 uint32_t index = 0;
343 while(!input.eof()) {
344 input.read(reinterpret_cast<char*>(data.data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
345 std::streamsize nbRead = input.gcount();
346 if(nbRead == 0) {
347 break;
348 }
349 std::size_t nbBlocks = cipherBlock(data, nbRead, out, index, cipher);
350 for(std::size_t i = 0 ; i < nbBlocks ; ++i) {
351 output << out[i];
352 }
353 index++;
354 }
355 output.flush();
356 }
357
358 template<typename Derived, typename Cipher>
359 inline void
360 BlockCipherModeOfOperation<Derived,Cipher>::cipherInParallel(std::istream& input,
361 std::ostream& output,
362 const std::string& key) {
363 std::array<uint8_t,Cipher::getBlockSize()>* data = new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
364 std::array<uint8_t,Cipher::getBlockSize()>* result = new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
365 std::size_t* nbWrite = new std::size_t[_nbThread];
366 uint32_t index = 0;
367 std::deque<std::thread> threads;
368 std::vector<Cipher> ciph;
369 ciph.push_back(Cipher(reinterpret_cast<const uint8_t*>(key.data())));
370 for(std::size_t i = 1 ; i < _nbThread ; ++i) {
371 ciph.push_back(Cipher(ciph[0]));
372 }
373 while(!input.eof()) {
374 for(std::size_t i = 0 ; i < _nbThread ; ++i) {
375 input.read(reinterpret_cast<char*>(data[i].data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
376 std::streamsize nbRead = input.gcount();
377 if(nbRead == 0) {
378 break;
379 }
380 threads.push_back(std::thread(&Derived::deferredCipherBlock,
381 this,
382 index++,
383 std::ref(data[i]),
384 nbRead,
385 std::ref(result[i]),
386 std::ref(ciph[i]),
387 std::ref(nbWrite[i])));
388 if(static_cast<std::size_t>(nbRead) != Cipher::getBlockSize()) {
389 break;
390 }
391 }
392 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
393 std::thread& th = threads.front();
394 th.join();
395 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
396 output << result[i][j];
397 }
398 threads.pop_front();
399 }
400 }
401
402 output.flush();
403 delete[] data;
404 delete[] result;
405 delete[] nbWrite;
406 }
407
408 template<typename Derived, typename Cipher>
409 void
410 BlockCipherModeOfOperation<Derived,Cipher>::decipherSequentially(std::istream& input,
411 std::ostream& output,
412 const std::string& key,
413 std::array<uint8_t,Cipher::getBlockSize()>& prevData) {
414 Cipher cipher(reinterpret_cast<const uint8_t*>(key.data()));
415 std::array<uint8_t,Cipher::getBlockSize()> out;
416 std::array<uint8_t,Cipher::getBlockSize()> data;
417 std::array<uint8_t,Cipher::getBlockSize()> cipherData;
418 input.read(reinterpret_cast<char*>(data.data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
419 std::streamsize nbRead = input.gcount();
420 uint32_t index = 0;
421 do {
422 cipherData = data;
423 std::streamsize read = nbRead;
424 input.read(reinterpret_cast<char*>(data.data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
425
426 std::size_t end = decipherBlock(cipherData, prevData, read, input.eof(), out, index, cipher);
427 for(std::size_t i = 0 ; i < end ; ++i) {
428 output << out[i];
429 }
430
431 prevData = cipherData;
432 nbRead = input.gcount();
433 index++;
434
435 } while(nbRead != 0);
436 output.flush();
437 }
438
439 template<typename Derived, typename Cipher>
440 inline void
441 BlockCipherModeOfOperation<Derived,Cipher>::decipherInParallel(std::istream& input,
442 std::ostream& output,
443 const std::string& key,
444 std::array<uint8_t,Cipher::getBlockSize()>& prevData) {
445 std::array<uint8_t,Cipher::getBlockSize()>* data = new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread + 1];
446 std::array<uint8_t,Cipher::getBlockSize()>* result = new std::array<uint8_t,Cipher::getBlockSize()>[_nbThread];
447 std::size_t* nbWrite = new std::size_t[_nbThread];
448 uint32_t index = 0;
449 std::deque<std::thread> threads;
450 std::vector<Cipher> ciph;
451 ciph.push_back(Cipher(reinterpret_cast<const uint8_t*>(key.data())));
452 for(std::size_t i = 1 ; i < _nbThread ; ++i) {
453 ciph.push_back(Cipher(ciph[0]));
454 }
455 bool lastBlock = false;
456 input.read(reinterpret_cast<char*>(data[0].data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
457 std::size_t nbRead = static_cast<std::size_t>(input.gcount());
458 do {
459 for(std::size_t i = 0, idx = 1 ; i < _nbThread ; ++i, ++idx) {
460 input.read(reinterpret_cast<char*>(data[idx].data()), static_cast<std::streamsize>(Cipher::getBlockSize()));
461 std::streamsize nextCount = input.gcount();
462 if(nextCount == 0) {
463 lastBlock = true;
464 }
465 threads.push_back(std::thread(&Derived::deferredDecipherBlock,
466 this,
467 index++,
468 std::ref(data[i]),
469 prevData,
470 nbRead,
471 lastBlock,
472 std::ref(result[i]),
473 std::ref(ciph[i]),
474 std::ref(nbWrite[i])));
475 if(lastBlock) {
476 break;
477 }
478 nbRead = static_cast<std::size_t>(nextCount);
479 prevData = data[i];
480 }
481 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
482 std::thread& th = threads.front();
483 th.join();
484 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
485 output << result[i][j];
486 }
487 threads.pop_front();
488 }
489 if(_error) {
490 throw InvalidBlockException("Error while decipher stream");
491 }
492 data[0] = data[_nbThread];
493 } while(!lastBlock);
494
495 output.flush();
496 delete[] data;
497 delete[] result;
498 delete[] nbWrite;
499 }
500
501 template<typename Derived, typename Cipher>
502 void
503 BlockCipherModeOfOperation<Derived,Cipher>::deferredCipherBlock(uint32_t index,
504 std::array<uint8_t,Cipher::getBlockSize()>& input,
505 std::streamsize nbRead,
506 std::array<uint8_t,Cipher::getBlockSize()>& output,
507 Cipher& cipher,
508 std::size_t& nbWrite) {
509 nbWrite = cipherBlock(input, nbRead, output, index, cipher);
510 }
511
512 template<typename Derived, typename Cipher>
513 void
514 BlockCipherModeOfOperation<Derived,Cipher>::deferredDecipherBlock(uint32_t index,
515 std::array<uint8_t, Cipher::getBlockSize()>& input,
516 std::array<uint8_t, Cipher::getBlockSize()> prevInput,
517 std::streamsize nbRead,
518 bool lastBlock,
519 std::array<uint8_t, Cipher::getBlockSize()>& output,
520 Cipher& cipher,
521 std::size_t& nbWrite) {
522 try {
523 nbWrite = decipherBlock(input, prevInput, nbRead, lastBlock, output, index, cipher);
524 } catch(const InvalidBlockException& e) {
525 _error = true;
526 }
527 }
528 // Methods -
529
530
531 // Accessors +
532 template<typename Derived, typename Cipher>
533 inline void
535 _nbThread = nbThread;
536 }
537 // Accessors -
538
539 }
540}
Thread pool utility class.
Definition threadPool.hpp:45
virtual const std::array< uint8_t, Cipher::getBlockSize()> & reset()=0
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
void decipher(std::istream &input, std::ostream &output, const std::string &key)
Definition bcModOp.hpp:318
BlockCipherModeOfOperation(bool cipherParallelizable, bool decipherParallelizable, unsigned int nbThread=1)
Definition bcModOp.hpp:269
void cipher(std::istream &input, std::ostream &output, const std::string &key)
Definition bcModOp.hpp:300
virtual ~BlockCipherModeOfOperation()
Definition bcModOp.hpp:291
void setNbThread(unsigned int nbThread)
Definition bcModOp.hpp:534
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
Exception on receiving an invalid block.
Definition invalidBlockException.hpp:38
Cryptography namespace.
Definition base64.hpp:28
AnCH framework base namespace.
Definition app.hpp:28