PictureCrypt  1.4.1
An image-steganography project
modelpc.cpp
Go to the documentation of this file.
1 #include "modelpc.h"
2 #include <QDebug>
3 #include <QtMath>
10 {
11  // Version control
12  versionString = "1.4.1";
13 
14  auto ver = versionString.split(".");
15  version = ver[0].toInt() * qPow(2, 16) + ver[1].toInt() * qPow(2, 8) + ver[2].toInt();
16 
17  ver_byte = bytes(ver[0].toInt()) +
18  bytes(ver[1].toInt()) +
19  bytes(ver[2].toInt());
20  // Random seed
21  qsrand(randSeed());
22 }
23 
24 QImage *ModelPC::Encrypt(QByteArray data, QImage *image, int _mode, QString key, int _bitsUsed, QString *_error)
25 {
26  return ModelPC().encrypt(data, image, _mode, key, _bitsUsed, _error);
27 }
28 
29 QImage *ModelPC::Inject(QByteArray encr_data, QImage *image, int _mode, int _bitsUsed, QString *_error)
30 {
31  return ModelPC().inject(encr_data, image, _mode, _bitsUsed, _error);
32 }
33 
34 QByteArray ModelPC::Decrypt(QImage *image, QString key, int _mode, QString *_error)
35 {
36  return ModelPC().decrypt(image, key, _mode, _error);
37 }
51 QImage * ModelPC::encrypt(QByteArray data, QImage * image, int _mode, QString key, int _bitsUsed, QString *_error)
52 {
53  success = true;
54  CryptMode mode = CryptMode(_mode);
55  // Error management
56  if(_error == nullptr)
57  _error = new QString();
58  *_error = "ok";
59  error = _error;
60 
61  if(data == nullptr || data.isEmpty()) {
62  fail("nodata");
63  return nullptr;
64  }
65  if(data.size() > pow(2, 24)) {
66  fail("muchdata");
67  return nullptr;
68  }
69  if(image == nullptr || image->isNull()) {
70  fail("nullimage");
71  return nullptr;
72  }
73  if(image->width() * image->height() > pow(10, 9)) {
74  fail("bigimage");
75  return nullptr;
76  }
77  if(_bitsUsed < 1 || _bitsUsed > 8) {
78  fail("bitsWrong");
79  return nullptr;
80  }
81  if(key == nullptr || key.isEmpty()) {
82  fail("no_key");
83  return nullptr;
84  }
85  else if(key.size() > 255) {
86  fail("bigkey");
87  return nullptr;
88  }
89  if(mode == CryptMode::NotDefined) {
90  fail("undefined_mode");
91  return nullptr;
92  }
93  long long usedBytes = data.size() + 14 + key.size();
94  long long size = image->width() * image->height();
95  if(usedBytes * 100 / (size * 3) * 8 / _bitsUsed > 70) {
96  fail("bigdata");
97  return nullptr;
98  }
99 
100  switch(mode)
101  {
102  case v1_3:
103  {
104  QByteArray zipped_data = zip(data, key.toUtf8());
105  QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
106  QByteArray encr_data = hash + zipped_data;
107  if(*error == "ok")
108  return inject(encr_data, image, _mode, _bitsUsed, error);
109  else
110  return nullptr;
111  break;
112  }
113  case v1_4:
114  bitsUsed = _bitsUsed;
115  encryptv1_4(image, data, key);
116  emit saveImage(image);
117  return image;
118  break;
119  case jphs_mode:
120  // TODO add jphs
121  return nullptr;
122  break;
123  default:
124  fail("wrongmode");
125  return nullptr;
126  }
127 }
128 
139 QImage * ModelPC::inject(QByteArray encr_data, QImage * image, int _mode, int _bitsUsed, QString *_error)
140 {
141  success = true;
142  CryptMode mode = CryptMode(_mode);
143  // Error management
144  if(_error == nullptr)
145  _error = new QString();
146  *_error = "ok";
147  error = _error;
148 
149  bitsUsed = _bitsUsed;
150 
151  if(encr_data == nullptr || encr_data.isEmpty()) {
152  fail("nodata");
153  return nullptr;
154  }
155  if(encr_data.size() > pow(2, 24)) {
156  fail("muchdata");
157  return nullptr;
158  }
159  if(image == nullptr || image->isNull()) {
160  fail("nullimage");
161  return nullptr;
162  }
163  if(image->width() * image->height() > pow(10, 9)) {
164  fail("bigimage");
165  return nullptr;
166  }
167  if(_bitsUsed < 1 || _bitsUsed > 8) {
168  fail("bitsWrong");
169  return nullptr;
170  }
171  if(mode == CryptMode::NotDefined) {
172  fail("undefined_mode");
173  return nullptr;
174  }
175 
176  encr_data = ver_byte + encr_data;
177  long long int countBytes = encr_data.size();
178  switch(mode)
179  {
180  case v1_3:
181  circuit(image, &encr_data, countBytes);
182  break;
183  case jphs_mode:
184  jphs(image, &encr_data);
185  break;
186  case v1_4:
187  fail("inject-v1.4");
188  return nullptr;
189  break;
190  default:
191  fail("wrongmode");
192  return nullptr;
193  }
194 
195  // Saving
196  if(success) {
197  emit saveImage(image);
198  return image;
199  }
200  else
201  return nullptr;
202 }
212 QByteArray ModelPC::decrypt(QImage * image, QString key, int _mode, QString *_error)
213 {
214  success = true;
215  CryptMode mode = CryptMode(_mode);
216  // Error management
217  if(_error == nullptr)
218  _error = new QString();
219  *_error = "ok";
220  error = _error;
221  if(image == nullptr || image->isNull()) {
222  fail("nullimage");
223  return nullptr;
224  }
225  if(image->width() * image->height() > pow(10, 9)) {
226  fail("bigimage");
227  return nullptr;
228  }
229  if(key == nullptr || key.isEmpty()) {
230  fail("no_key");
231  return nullptr;
232  }
233  QByteArray result;
234 
235  switch (mode) {
236  case v1_3:
237  result = decryptv1_3(image, key);
238  break;
239  case v1_4:
240  result = decryptv1_4(image, key);
241  break;
242  case jphs_mode:
243  // TODO add jphs support
244  break;
245  case NotDefined:
246  isTry = true;
247 
248  // v1_3
249  result = decryptv1_3(new QImage(*image), key);
250  if(success) {
251  isTry = false;
252  break;
253  }
254  success = true;
255 
256  // v1_4
257  result = decryptv1_4(image, key);
258  if(success) {
259  isTry = false;
260  break;
261  }
262  success = true;
263 
264  // TODO add jphs support
265 
266  isTry = false;
267  fail("all_modes_fail");
268  return nullptr;
269  break;
270  default:
271  // For invalid modes
272  fail("wrongmode");
273  return nullptr;
274  }
275  if(*error == "ok")
276  emit saveData(result);
277  return result;
278 }
283 void ModelPC::fail(QString message)
284 {
285  success = false;
286  if(!isTry) {
287  *error = message;
288  alert(message, true);
289  emit setProgress(101);
290  qDebug() << "[Debug] !!! fail() - " << message;
291  }
292 }
298 void ModelPC::jphs(QImage *image, QByteArray *data)
299 {
300  // Under Development
301  return;
302 
303  // Dead code
304 
305  success = true;
306  bool isEncrypt = !data->isEmpty();
307  QString targetEXE = defaultJPHSDir + (isEncrypt ? "/jphide.exe" : "/jpseek.exe");
308  if(!fileExists(targetEXE))
309  {
310  fail("nojphs");
311  return;
312  }
313 
314  QString randomFileName = defaultJPHSDir + "/";
315  qsrand(randSeed());
316  for(int i = 0; i < 10; i++)
317  randomFileName.append(97 + qrand() % 25);
318  image->save(randomFileName + ".jpg");
319  if(isEncrypt) {
320  QFile file(randomFileName + ".pc");
321  if(!file.open(QFile::WriteOnly)) {
322  fail("save_file_fail");
323  return;
324  }
325  file.write(*data);
326  file.close();
327 
328  QStringList args;
329  args << (randomFileName + ".jpg") << (randomFileName + "_out.jpg") << (randomFileName + ".pc");
330  QProcess prog(this);
331  prog.start(targetEXE, args);
332  prog.waitForStarted();
333  prog.write("test\n");
334  prog.waitForBytesWritten();
335  prog.write("test\n");
336  prog.waitForBytesWritten();
337  prog.waitForReadyRead();
338  QByteArray bytes = prog.readAll();
339  prog.waitForFinished();
340  //QByteArray readData = prog.readAll();
341  prog.close();
342  // Cleaning - Deleting temp files
343 
344  }
345  else {
346 
347  }
348 
349 }
350 
359 void ModelPC::circuit(QImage *image, QByteArray *data, long long countBytes)
360 {
361  // Some flags and creation of the ProgressDialog
362  success = true;
363  emit setProgress(-1);
364  bool isEncrypt = !data->isEmpty();
365 
366  // Image setup
367  int w = image->width();
368  int h = image->height();
369 
370  // Visited pixels array
371  QVector <QPoint> were;
372  were.push_back(QPoint(0, 0));
373  were.push_back(QPoint(0, h - 1));
374  were.push_back(QPoint(w - 1, 0));
375  were.push_back(QPoint(w - 1, h - 1));
376 
377  long long int offset = 0;
378 
379  // Pre-start Cleaning
380  circuitData = data;
381  circuitImage = image;
382  circuitCountBytes = countBytes;
383  cur = 0;
384  bitsBuffer.clear();
385 
386  // Writing Top-Left to Bottom-Left
387  for(int i = 1; i < h - 1 && mustGoOn(isEncrypt); i++) {
388  QPoint pos(0, i);
389  processPixel(pos, &were, isEncrypt);
390  }
391  // Writing Bottom-Right to Top-Right
392  if(mustGoOn(isEncrypt))
393  {
394  for(int i = h - 2; i >= 1 && mustGoOn(isEncrypt); i--){
395  QPoint pos(w - 1, i);
396  processPixel(pos, &were, isEncrypt);
397  }
398  }
399  // Main cycle
400  // Strong is considered as actual corner pixel and weak as pixel near it like (1, 0) or (0, 1)
401  while(mustGoOn(isEncrypt))
402  {
403  // Strong Top-Right to Strong Bottom-Right
404  for(int i = offset; i < h - offset && mustGoOn(isEncrypt); i++){
405  QPoint pos(w - offset - 2, i);
406  processPixel(pos, &were, isEncrypt);
407  }
408  // Strong Top-Left to Weak Top-Right
409  for(int i = offset + 1; i < w - offset - 2 && mustGoOn(isEncrypt); i++){
410  QPoint pos(i, offset);
411  processPixel(pos, &were, isEncrypt);
412  }
413  // Weak Bottom-Right to Weak Bottom-Left
414  for(int i = w - 3 - offset; i >= offset + 2 && mustGoOn(isEncrypt); i--){
415  QPoint pos(i, h - offset - 1);
416  processPixel(pos, &were, isEncrypt);
417  }
418  // Weak Top-Left to Strong Bottom-Left
419  for(int i = offset + 1; i < h - offset && mustGoOn(isEncrypt); i++){
420  QPoint pos(offset + 1, i);
421  processPixel(pos, &were, isEncrypt);
422  }
423  offset++;
424  }
425  // Extra writing
426  if(!success)
427  return;
428  if(isEncrypt)
429  {
430  // Getting past colors
431  QColor colUL = image->pixelColor(0, 0).toRgb();
432  QColor colUR = image->pixelColor(w - 1, 0).toRgb();
433  QColor colDL = image->pixelColor(0, h - 1).toRgb();
434  QColor colDR = image->pixelColor(w - 1, h - 1).toRgb();
435  int red = 0;
436  int green = 0;
437  int blue = 0;
438 
439  // Writing Upper Left
440  red = (colUL.red() & 224) + (countBytes >> 19);
441  green = (colUL.green() & 224) + (countBytes >> 14) % 32;
442  blue = (colUL.blue() & 224) + (countBytes >> 9) % 32;
443  image->setPixelColor(0, 0, QColor(red, green, blue));
444 
445  // Writing Upper Right
446  red = (colUR.red() & 224) + (countBytes >> 4) % 32;
447  green = (colUR.green() & 224) + ((countBytes % 16) << 1) + 1;
448  blue = (colUR.blue() & 224) + 9;
449  image->setPixelColor(w - 1, 0, QColor(red, green, blue));
450 
451  // Getting extra bytes if left
452  while(cur < countBytes)
453  push(mod(circuitData->at(cur++)), 8);
454  if(bitsBuffer.size() > 20) {
455  fail("bitsBufferFail");
456  return;
457  }
458  // Getting extra data as long.
459  long extraData = pop(-2);
460 
461  // Writing Down Left
462  red = (colDL.red() & 224) + (extraData >> 15);
463  green = (colDL.green() & 224) + (extraData >> 10) % 32;
464  blue = (colDL.blue() & 224) + (extraData >> 5) % 32;
465  image->setPixelColor(0, h - 1, QColor(red, green, blue));
466 
467  // Writing Down Right
468  red = (colDR.red() & 224) + extraData % 32;
469  green = (colDR.green() & 224);
470  blue = (colDR.blue() & 224) + ((bitsUsed - 1) << 2) + 2;
471  image->setPixelColor(w - 1, h - 1, QColor(red, green, blue));
472  }
473  else
474  {
475  // Read the past pixels
476  QColor colDL = image->pixelColor(0, h - 1).toRgb();
477  QColor colDR = image->pixelColor(w - 1, h - 1).toRgb();
478 
479  // Read extra data
480  long extraData = ((colDL.red() % 32) << 15) + ((colDL.green() % 32) << 10);
481  extraData += ((colDL.blue() % 32) << 5) + colDR.red() % 32;
482 
483  // Add extra data to the bitsBuffer
484  push(extraData, (countBytes - cur) * 8 - bitsBuffer.size());
485 
486  // Move bits from bitsBuffer to the QByteArray
487  while(!bitsBuffer.isEmpty())
488  data->append(pop(8));
489  }
490  emit setProgress(101);
491 }
492 
500 void ModelPC::processPixel(QPoint pos, QVector<QPoint> *were, bool isEncrypt)
501 {
502  if(!success)
503  return;
504  // Check if point was already visited
505  if(were->contains(pos)){
506  fail("point_visited_twice");
507  return;
508  }
509  else
510  were->push_back(pos);
511  if(isEncrypt)
512  {
513  // Make sure that there are enough bits in bitsBuffer to write
514  while(bitsBuffer.size() < 3 * bitsUsed)
515  push(mod(circuitData->at(cur++)), 8);
516  // Read past contains
517  QColor pixelColor = circuitImage->pixelColor(pos);
518  int red = pixelColor.red();
519  int green = pixelColor.green();
520  int blue = pixelColor.blue();
521 
522  // Write new data in last bitsUsed pixels
523  red += pop() - red % (int) qPow(2, bitsUsed);
524  green += pop() - green % (int) qPow(2, bitsUsed);
525  blue += pop() - blue % (int) qPow(2, bitsUsed);
526 
527  circuitImage->setPixelColor(pos, QColor(red, green, blue));
528  }
529  else
530  {
531  QColor read_color = circuitImage->pixelColor(pos).toRgb();
532  // Reading the pixel
533  int red = read_color.red();
534  int green = read_color.green();
535  int blue = read_color.blue();
536 
537  // Reading the last bitsUsed pixels
538  red %= (int) qPow(2, bitsUsed);
539  green %= (int) qPow(2, bitsUsed);
540  blue %= (int) qPow(2, bitsUsed);
541 
542  // Getting the data in the bitsBuffer.
543  push(red);
544  push(green);
545  push(blue);
546 
547  // Getting data to QByteArray
548  while(bitsBuffer.size() >= 8) {
549  circuitData->append(pop(8));
550  cur++;
551  }
552  }
553  emit setProgress(100 * cur / circuitCountBytes);
554 }
561 void ModelPC::encryptv1_4(QImage *image, QByteArray data, QString key)
562 {
563  if(data.size() + 98 > image->height() * image->width() * 3) {
564  fail("bigdata");
565  return;
566  }
567  QTime st = QTime::currentTime();
568  QByteArray rand_master = GetRandomBytes(32);
569  QByteArray pass = QCryptographicHash::hash(key.toUtf8() + rand_master + QByteArray("hi"), QCryptographicHash::Sha3_384);
570  QByteArray noise = GetRandomBytes(data.size() / 10 + 32);
571  QByteArray bytes_key = GetRandomBytes(32);
572  QByteArray pass_rand = QCryptographicHash::hash(pass + bytes_key, QCryptographicHash::Sha3_512);
573  QByteArray zipped = zip(data, pass_rand);
574  QByteArray heavy_data = zipped + noise;
575 
576  QByteArray verification = QCryptographicHash::hash(pass + bytes_key, QCryptographicHash::Sha3_256);
577  QByteArray given_key = bytes_key.left(30);
578  QByteArray heavy_data_size;
579  // heavy_data_size is always 4 bytes as max for heavy_data is: 2^24 * 11/10 + 32 ~ 1.8 * 10^7 < 2^32
580  long long raw_size = zipped.size();
581  for(int i = 0; i < 4; i++) {
582  int ch = raw_size % 256;
583  raw_size >>= 8;
584  heavy_data_size.push_front(ch);
585  }
586  QByteArray mid_data = verification + given_key + rand_master + heavy_data_size;
587  // mid_data.size() = 32 + 30 + 32 + 4 = 98
588  QVector <QPair<QPoint, QPair<int, int>>> *were = new QVector <QPair<QPoint, QPair<int, int>>>();
589  emit setProgress(-1);
590  proccessPixelsv1_4(image, &mid_data, key.toUtf8(), true, were);
591  proccessPixelsv1_4(image, &heavy_data, pass_rand, true, were);
592  emit setProgress(101);
593  QTime final = QTime::currentTime();
594  qDebug() << "[Debug] Finished encrypting in " << st.msecsTo(final) << " msecs.";
595 }
596 
603 QByteArray ModelPC::decryptv1_4(QImage *image, QString key)
604 {
605  QTime st = QTime::currentTime();
606  QByteArray mid_data, heavy_data;
607  QVector <QPair<QPoint, QPair<int, int>>> *were = new QVector <QPair<QPoint, QPair<int, int>>>();
608  emit setProgress(-1);
609  proccessPixelsv1_4(image, &mid_data, key.toUtf8(), false, were, 98);
610  QByteArray verification = mid_data.left(32);
611  QByteArray given_key = mid_data.mid(32, 30);
612  QByteArray rand_master = mid_data.mid(62, 32);
613  QByteArray heavy_data_size = mid_data.right(4);
614 
615  QByteArray pass = QCryptographicHash::hash(key.toUtf8() + rand_master + QByteArray("hi"), QCryptographicHash::Sha3_384);
616 
617  // Guessing
618  emit setProgress(0);
619  QByteArray bytes_key;
620  for(long long i = 0; i < pow(2, 16); i++) {
621  QByteArray guess_part;
622  long long g = i;
623  for(int q = 0; q < 2; q++) {
624  int ch = g % 256;
625  g >>= 8;
626  guess_part.push_front(ch);
627  }
628  emit setProgress(100 * i / pow(2, 16));
629  QByteArray guess = given_key + guess_part;
630  QByteArray check = QCryptographicHash::hash(pass + guess, QCryptographicHash::Sha3_256);
631  if(check == verification) {
632  bytes_key = guess;
633  break;
634  }
635  }
636  if(bytes_key.isEmpty()) {
637  fail("veriffail");
638  return nullptr;
639  }
640 
641  QByteArray pass_rand = QCryptographicHash::hash(pass + bytes_key, QCryptographicHash::Sha3_512);
642 
643  long long raw_size = mod(heavy_data_size[3]) +
644  mod(heavy_data_size[2]) * pow(2, 8) +
645  mod(heavy_data_size[1]) * pow(2, 16) +
646  mod(heavy_data_size[0]) * pow(2, 24);
647  emit setProgress(0);
648  proccessPixelsv1_4(image, &heavy_data, pass_rand, false, were, raw_size);
649  QByteArray unzipped = unzip(heavy_data, pass_rand);
650  emit setProgress(101);
651  QTime final = QTime::currentTime();
652  qDebug() << "[Debug] Finished decrypting in " << st.msecsTo(final) << " msecs.";
653  return unzipped;
654 }
664 void ModelPC::proccessPixelsv1_4(QImage *image, QByteArray* data, QByteArray key, bool isEncrypt, QVector <QPair<QPoint, QPair<int, int>>> *were, long long size)
665 {
666  long w = image->width();
667  long h = image->height();
668  auto seed_hex = QCryptographicHash::hash(key, QCryptographicHash::Sha3_256).toHex().left(8).toUpper();
669  auto seed = seed_hex.toLongLong(nullptr, 16);
670  QRandomGenerator foo(seed);
671 
672  bitsBuffer.clear();
673  long long left = (size == -1 ? data->size() : size) * 8;
674  long long all = left;
675  long cur = 0;
676  if(isEncrypt) {
677  while(left > 0 && success)
678  {
679  if(bitsBuffer.empty())
680  push(mod(data->at(cur++)), 8);
681  quint64 g = foo.generate64() % (w * h);
682  long x = g % w;
683  long y = g / w;
684  int c = foo.generate64() % 3;
685  int b = foo.generate64() % 24;
686  int bit = -1;
687  if(b < 16)
688  bit = 7;
689  else if(bit < 20)
690  bit = 6;
691  else if(bit < 22)
692  bit = 5;
693  else if(bit < 23)
694  bit = 4;
695  else if(bit < 24)
696  bit = 3;
697  auto piece = qMakePair(QPoint(x, y), qMakePair(c, bit));
698  if(were->contains(piece))
699  continue;
700  were->append(piece);
701  left--;
702  emit setProgress(100 * (all - left) / all);
703  int wr = pop(1);
704  QColor pixel = image->pixelColor(piece.first);
705  int red = pixel.red();
706  int green = pixel.green();
707  int blue = pixel.blue();
708  int dif;
709  if(c == 0)
710  dif = red;
711  else if (c == 1)
712  dif = green;
713  else
714  dif = blue;
715  dif |= 1 << (7 - bit);
716  dif ^= (wr ^ 1) << (7 - bit);
717  if(c == 0)
718  red = dif;
719  else if(c == 1)
720  green = dif;
721  else
722  blue = dif;
723  image->setPixelColor(piece.first, QColor(red, green, blue));
724  }
725  } else {
726  while(left > 0)
727  {
728  while (bitsBuffer.size() >= 8)
729  data->push_back(pop(8));
730  quint64 g = foo.generate64() % (w * h);
731  long x = g % w;
732  long y = g / w;
733  int c = foo.generate64() % 3;
734  int b = foo.generate64() % 24;
735  int bit = -1;
736  if(b < 16)
737  bit = 7;
738  else if(bit < 20)
739  bit = 6;
740  else if(bit < 22)
741  bit = 5;
742  else if(bit < 23)
743  bit = 4;
744  else if(bit < 24)
745  bit = 3;
746  auto piece = qMakePair(QPoint(x, y), qMakePair(c, bit));
747  if(were->contains(piece))
748  continue;
749  were->append(piece);
750  left--;
751  emit setProgress(100 * (all - left) / all);
752  QColor pixel = image->pixelColor(piece.first);
753  int red = pixel.red();
754  int green = pixel.green();
755  int blue = pixel.blue();
756  int dif;
757  if(c == 0)
758  dif = red;
759  else if (c == 1)
760  dif = green;
761  else
762  dif = blue;
763  dif &= 1 << (7 - bit);
764  int wr = dif != 0;
765  push(wr, 1);
766  }
767  while (bitsBuffer.size() >= 8)
768  data->push_back(pop(8));
769  }
770 }
771 
778 QByteArray ModelPC::decryptv1_3(QImage *image, QString key)
779 {
780  // Image opening
781  int w = image->width();
782  int h = image->height();
783 
784  // Getting corner pixels
785  QColor colUL = image->pixelColor(0, 0).toRgb();
786  QColor colUR = image->pixelColor(w - 1, 0).toRgb();
787  QColor colDR = image->pixelColor(w - 1, h - 1).toRgb();
788 
789 
790  // Getting verification code
791  int verifCode = (((colUR.green() % 2) << 5) + colUR.blue() % 32) << 2;
792  verifCode += colDR.blue() % 4;
793  if(verifCode != 166){
794  fail("veriffail");
795  return nullptr;
796  }
797  // Getting number of bytes
798  long long int countBytes = (colUL.blue() % 32 + ((colUL.green() % 32) << 5) + ((colUL.red() % 32) << 10)) << 9;
799  countBytes += ((colUR.red() % 32) << 4) + (colUR.green() >> 1) % 16;
800 
801  bitsUsed = (colDR.blue() >> 2) % 8 + 1;
802  // curMode = colDR.green() % 32;
803 
804  // Start of the circuit
805  QByteArray data;
806  circuit(image, &data, countBytes);
807 
808  // Check if circuit was successful
809  if(!success)
810  return nullptr;
811  if(data.isEmpty())
812  {
813  fail("noreaddata");
814  return nullptr;
815 
816  }
817  // Version check
818  long long int _ver = mod(data.at(0)) * qPow(2, 16);
819  _ver += mod(data.at(1)) * qPow(2, 8);
820  _ver += mod(data.at(2));
821  data.remove(0, 3);
822  if(_ver > version) {
823  fail("new_version");
824  return nullptr;
825  }
826  else if(_ver < version) {
827  fail("old_version");
828  return nullptr;
829  }
830  // Get the hash
831  QByteArray hash = data.left(32);
832  data.remove(0, 32);
833 
834  // Unzip
835  QByteArray unzipped_data = unzip(data, key.toUtf8());
836  QByteArray our_hash = QCryptographicHash::hash(unzipped_data, QCryptographicHash::Sha256);
837  if(our_hash != hash) {
838  fail("veriffail");
839  return QByteArray("");
840  }
841  return unzipped_data;
842 }
843 long ModelPC::pop(int bits)
844 {
845  // Hard to say
846  long res = 0;
847  int poppedBits = bits == -1 ? bitsUsed : bits;
848  if(bits == -2)
849  poppedBits = bitsBuffer.size();
850  for(int i = 0; i < poppedBits; i++)
851  res += bitsBuffer[i] * qPow(2, poppedBits - i - 1);
852  bitsBuffer.remove(0, poppedBits);
853  return res;
854 }
855 
856 void ModelPC::push(int data, int bits)
857 {
858  // That's easier, but also hard
859  int buf_size = bitsBuffer.size();
860  int extraSize = bits == -1 ? bitsUsed : bits;
861  bitsBuffer.resize(buf_size + extraSize);
862  for(int i = bitsBuffer.size() - 1; i >= buf_size; i--, data >>= 1)
863  bitsBuffer[i] = data % 2;
864 }
865 
866 bool ModelPC::mustGoOn(bool isEncrypt)
867 {
868  return success && (isEncrypt ? (circuitCountBytes - cur) * 8 + bitsBuffer.size() >= bitsUsed * 3 :
869  circuitData->size() * 8 + bitsBuffer.size() <
870  circuitCountBytes * 8 - (circuitCountBytes * 8)% (bitsUsed * 3));
871 }
880 QByteArray ModelPC::unzip(QByteArray data, QByteArray key)
881 {
882  // Decryption
883  QByteArray hashKey = QCryptographicHash::hash(key, QCryptographicHash::Sha256);
885  QByteArray new_data = encryption.decode(data, hashKey);
886  // Decompressing
887  return qUncompress(new_data);
888 }
897 QByteArray ModelPC::zip(QByteArray data, QByteArray key)
898 {
899  // Zip
900  QByteArray c_data = qCompress(data, 9);
901  // Encryption
902  QByteArray hashKey = QCryptographicHash::hash(key, QCryptographicHash::Sha256);
904 }
905 
906 bool ModelPC::fileExists(QString path)
907 {
908  QFileInfo check_file(path);
909  return check_file.exists() && check_file.isFile();
910 }
911 
918 QByteArray ModelPC::bytes(long long n)
919 {
920  return QByteArray::fromHex(QByteArray::number(n, 16));
921 }
928 unsigned int ModelPC::mod(int input)
929 {
930  if(input < 0)
931  return (unsigned int) (256 + input);
932  else
933  return (unsigned int) input;
934 }
941 void ModelPC::alert(QString message, bool isWarning)
942 {
943  emit alertView(message, isWarning);
944 }
950 QColor ModelPC::RGBbytes(long long byte)
951 {
952  int blue = byte % 256;
953  int green = (byte / 256) % 256;
954  int red = byte / qPow(2, 16);
955  return QColor(red, green, blue);
956 }
957 
958 QString ModelPC::generateVersionString(long ver)
959 {
960  return QString::number((int)( ver / qPow(2, 16))) + "." + QString::number(((int) (ver / 256)) % 256) + "." + QString::number(ver % 256);
961 }
962 
963 uint ModelPC::randSeed()
964 {
965  QTime time = QTime::currentTime();
966  uint randSeed = time.msecsSinceStartOfDay() % 55363 + time.minute() * 21 + time.second() * 2 + 239;
967  qsrand(randSeed);
968  uint randSeed_2 = qrand() % 72341 + qrand() % 3 + qrand() % 2 + 566;
969  return randSeed_2;
970 }
971 QByteArray ModelPC::GetRandomBytes(long long count)
972 {
973  QByteArray res;
974  for(int i = 0; i < count; i++)
975  res.append(qrand() % 256);
976  return res;
977 }
static QByteArray Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText, const QByteArray &key, const QByteArray &iv=NULL, QAESEncryption::Padding padding=QAESEncryption::ISO)
Crypt Static encode function.
QByteArray decryptv1_4(QImage *image, QString key)
ModelPC::decryptv1_4 Decrypts data from image in v1.4+.
Definition: modelpc.cpp:603
QByteArray zip(QByteArray data, QByteArray key)
ModelPC::zip Zip function, copy of EncryptDialog::zip Used for ModelPC in custom projects, other than PictureCrypt.
Definition: modelpc.cpp:897
QString versionString
versionString Version as string
Definition: modelpc.h:88
The QAESEncryption class Small and portable AES encryption class for Qt. Supports all key sizes - 128...
QByteArray decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv=NULL)
decode Decodes data with AES
long version
version Version of the class
Definition: modelpc.h:84
ModelPC()
ModelPC::ModelPC Constructor Unit tests are run here.
Definition: modelpc.cpp:9
void alertView(QString messageCode, bool isWarning)
alertView Signal to be called to create MessageBox.
void proccessPixelsv1_4(QImage *image, QByteArray *data, QByteArray key, bool isEncrypt, QVector< QPair< QPoint, QPair< int, int > > > *were, long long size=-1)
ModelPC::proccessPixelsv1_4 Hides (or retrieves) data to/from pixels.
Definition: modelpc.cpp:664
QString defaultJPHSDir
defaultJPHSDir Default JPHS directory
Definition: modelpc.h:92
QImage * encrypt(QByteArray data, QImage *image, int _mode, QString key="", int _bitsUsed=8, QString *_error=nullptr)
ModelPC::encrypt Slot to zip and inject data and provide it with some extra stuff After completion st...
Definition: modelpc.cpp:51
void saveData(QByteArray data)
saveData Signal to be called to save data from ModelPC::decrypt.
static QImage * Inject(QByteArray encr_data, QImage *image, int _mode, int _bitsUsed=8, QString *_error=nullptr)
Definition: modelpc.cpp:29
void jphs(QImage *image, QByteArray *data)
ModelPC::jphs JPHS function to use jphide and jpseek (currently under development) ...
Definition: modelpc.cpp:298
void circuit(QImage *image, QByteArray *data, long long int countBytes)
ModelPC::circuit The brain of the app. Via special circuit stores data in image.
Definition: modelpc.cpp:359
QString * error
error Current error
Definition: modelpc.h:108
void encryptv1_4(QImage *image, QByteArray data, QString key)
ModelPC::encryptv1_4 Encrypts and injects data to image used in v1.4+.
Definition: modelpc.cpp:561
QImage * inject(QByteArray encr_data, QImage *image, int _mode, int _bitsUsed=8, QString *_error=nullptr)
ModelPC::inject Slot to be called when encrypt mode in ViewPC is selected and started.
Definition: modelpc.cpp:139
void alert(QString message, bool isWarning=false)
ModelPC::alert Function emits signal ModelPC::alertView and calls ViewPC::alert.
Definition: modelpc.cpp:941
void setProgress(int val)
setProgress Signal to be called to set progress of ProgressDialog.
QByteArray decryptv1_3(QImage *image, QString key)
ModelPC::decryptv1_3 Decrytps data from image in v1.3.
Definition: modelpc.cpp:778
void fail(QString message)
ModelPC::fail Slot to stop execution of cryption.
Definition: modelpc.cpp:283
QByteArray decrypt(QImage *image, QString key, int _mode=0, QString *_error=nullptr)
ModelPC::decrypt Slot to be called when decrypt mode in ViewPC is selected and started.
Definition: modelpc.cpp:212
bool success
success Flag that true by default, but in case of error or cancelling of ProgressDialog it turns to f...
Definition: modelpc.h:80
QByteArray unzip(QByteArray data, QByteArray key)
ModelPC::unzip Unzip data from ModelPC::decrypt. Just mirrored EncryptDialog::zip.
Definition: modelpc.cpp:880
CryptMode
Definition: modelpc.h:38
static QByteArray Decrypt(QImage *image, QString key, int _mode=0, QString *_error=nullptr)
Definition: modelpc.cpp:34
void saveImage(QImage *image)
saveImage Signal to be called to save image from ModelPC::encrypt.
static QImage * Encrypt(QByteArray data, QImage *image, int _mode, QString key="", int _bitsUsed=8, QString *_error=nullptr)
Definition: modelpc.cpp:24
void processPixel(QPoint pos, QVector< QPoint > *were, bool isEncrypt)
ModelPC::processPixel Processes every pixel. Reads its contains or writes data.
Definition: modelpc.cpp:500