268 template<
typename Derived,
typename Cipher>
270 bool decipherParallelizable,
271 unsigned int nbThread):
272 _cipherParallelizable(cipherParallelizable),
273 _decipherParallelizable(decipherParallelizable),
279 if(nbThread == 0 && (cipherParallelizable || decipherParallelizable)) {
280 _nbThread = std::thread::hardware_concurrency();
290 template<
typename Derived,
typename Cipher>
298 template<
typename Derived,
typename Cipher>
301 std::ostream& output,
302 const std::string& key) {
303 if(input && output) {
305 if(!_cipherParallelizable || _nbThread == 1) {
306 cipherSequentially(input, output, key);
309 cipherInParallel(input, output, key);
312 throw std::ios_base::failure(
"Input and/or output streams are closed");
316 template<
typename Derived,
typename Cipher>
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);
327 decipherInParallel(input, output, key, prevData);
330 throw std::ios_base::failure(
"Input and/or output streams are closed");
334 template<
typename Derived,
typename Cipher>
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;
343 while(!input.eof()) {
344 input.read(
reinterpret_cast<char*
>(data.data()),
static_cast<std::streamsize
>(Cipher::getBlockSize()));
345 std::streamsize nbRead = input.gcount();
349 std::size_t nbBlocks = cipherBlock(data, nbRead, out, index, cipher);
350 for(std::size_t i = 0 ; i < nbBlocks ; ++i) {
358 template<
typename Derived,
typename Cipher>
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];
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]));
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();
380 threads.push_back(std::thread(&Derived::deferredCipherBlock,
387 std::ref(nbWrite[i])));
388 if(
static_cast<std::size_t
>(nbRead) != Cipher::getBlockSize()) {
392 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
393 std::thread& th = threads.front();
395 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
396 output << result[i][j];
408 template<
typename Derived,
typename Cipher>
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();
423 std::streamsize read = nbRead;
424 input.read(
reinterpret_cast<char*
>(data.data()),
static_cast<std::streamsize
>(Cipher::getBlockSize()));
426 std::size_t end = decipherBlock(cipherData, prevData, read, input.eof(), out, index, cipher);
427 for(std::size_t i = 0 ; i < end ; ++i) {
431 prevData = cipherData;
432 nbRead = input.gcount();
435 }
while(nbRead != 0);
439 template<
typename Derived,
typename Cipher>
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];
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]));
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());
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();
465 threads.push_back(std::thread(&Derived::deferredDecipherBlock,
474 std::ref(nbWrite[i])));
478 nbRead =
static_cast<std::size_t
>(nextCount);
481 for(uint32_t i = 0 ; !threads.empty() ; ++i) {
482 std::thread& th = threads.front();
484 for(uint32_t j = 0 ; j < nbWrite[i] ; ++j) {
485 output << result[i][j];
492 data[0] = data[_nbThread];
501 template<
typename Derived,
typename Cipher>
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,
508 std::size_t& nbWrite) {
509 nbWrite = cipherBlock(input, nbRead, output, index, cipher);
512 template<
typename Derived,
typename Cipher>
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,
519 std::array<uint8_t, Cipher::getBlockSize()>& output,
521 std::size_t& nbWrite) {
523 nbWrite = decipherBlock(input, prevInput, nbRead, lastBlock, output, index, cipher);
532 template<
typename Derived,
typename Cipher>
535 _nbThread = nbThread;