├── .gitattributes ├── README.md ├── image-sound ├── cryptoAmpli │ ├── cat.jpg │ ├── cryptoAmpli.pde │ ├── jazz.wav │ ├── loadPixels_.png │ └── rick.jpg ├── cryptoProSound │ ├── cryptoProSound.pde │ ├── gyver.wav │ ├── jazz.wav │ ├── loadPixels_.png │ ├── rick.jpg │ ├── качество нужно менять ПЕРЕД загрузкой аудио!.txt │ └── расшифровка качественных аудио может занимать пару минут.txt ├── cryptoSpectrum │ ├── cat.jpg │ ├── cryptoSpectrum.pde │ ├── fft.pde │ ├── loadPixels_.png │ ├── logo500.jpg │ ├── test1.wav │ └── test2.wav └── kek.bmp ├── image-text ├── colorTest │ └── colorTest.pde ├── crypto │ ├── appls.png │ ├── bin │ │ ├── application.windows32 │ │ │ ├── crypto.exe │ │ │ └── lib │ │ │ │ ├── controlP5.jar │ │ │ │ ├── core.jar │ │ │ │ ├── crypto.jar │ │ │ │ ├── gluegen-rt-natives-windows-i586.jar │ │ │ │ ├── gluegen-rt.jar │ │ │ │ ├── jogl-all-natives-windows-i586.jar │ │ │ │ └── jogl-all.jar │ │ └── application.windows64 │ │ │ ├── crypto.exe │ │ │ └── lib │ │ │ ├── controlP5.jar │ │ │ ├── core.jar │ │ │ ├── crypto.jar │ │ │ ├── gluegen-rt-natives-windows-amd64.jar │ │ │ ├── gluegen-rt.jar │ │ │ ├── jogl-all-natives-windows-amd64.jar │ │ │ └── jogl-all.jar │ ├── black.jpg │ ├── blackwhite.jpg │ ├── crypto.pde │ ├── old.pde │ ├── text.txt │ └── white.jpg └── cryptoText │ ├── apples.png │ ├── bin │ ├── application.windows32 │ │ ├── cryptoText.exe │ │ └── lib │ │ │ ├── controlP5.jar │ │ │ ├── core.jar │ │ │ ├── cryptoText.jar │ │ │ ├── gluegen-rt-natives-windows-i586.jar │ │ │ ├── gluegen-rt.jar │ │ │ ├── jogl-all-natives-windows-i586.jar │ │ │ └── jogl-all.jar │ └── application.windows64 │ │ ├── cryptoText.exe │ │ └── lib │ │ ├── controlP5.jar │ │ ├── core.jar │ │ ├── cryptoText.jar │ │ ├── gluegen-rt-natives-windows-amd64.jar │ │ ├── gluegen-rt.jar │ │ ├── jogl-all-natives-windows-amd64.jar │ │ └── jogl-all.jar │ ├── cat.jpg │ ├── cryptoText.pde │ ├── logo150.jpg │ ├── rick.jpg │ ├── text.txt │ └── шифровки от Гувера =) Пароль в видео │ ├── crypted_1.bmp │ ├── crypted_2.bmp │ ├── crypted_3.bmp │ └── crypted_4.bmp └── logo.bmp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crypto 2 | Программы для кодирования одних данных в другие 3 | ![logo](/logo.bmp) 4 | + Если не умеешь качать с гитхаба - [нажми вот сюда](https://github.com/AlexGyver/crypto/archive/main.zip), чтобы скачать весь архив полностью 5 | + Для запуска исходников нужно [скачать Processing](https://processing.org/download/) 6 | + Установить пакет [Java](https://java.com/ru/download/) 7 | + В самой программе Processing установить библиотеку **ControlP5**: зайти "Набросок / Импортировать библиотеку... / Добавить библиотеку...", в поиске найти и установить библиотеку ControlP5. Требуется подключение к интернету! 8 | + Для примеров со звуком установить библиотеку **Sound** 9 | + В папках с исходниками есть папка **bin**, там лежит скомпилированная прогамма для win32 и win64 10 | + Для запуска исходника открываем файл *.pde* при помощи Processing 11 | 12 | ## Папка image-text 13 | ### Кодирование текста в изображение 14 | + [Видос](https://youtu.be/RmHGSq6rbKA) 15 | + **crypto** - вариант с двумя картинками (старый). Во вкладке *old* лежит несколько алгоритмов 16 | + **cryptoText** - вариант с ключом шифрования и случайным распределением пикселей 17 | + **colorTest** - программа для тестирования смеси цветов из видео 18 | 19 | ## Папка image-sound 20 | ### Кодирование звука изображение и наоборот 21 | + [Видос](https://youtu.be/RuNU5gbt3_w) 22 | + **cryptoAmpli** - пакует изображение в звук 23 | + **cryptoProSound** - пакует звук в изображение 24 | + **cryptoSpectrum** - зашивает картинку в спектр звука 25 | -------------------------------------------------------------------------------- /image-sound/cryptoAmpli/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoAmpli/cat.jpg -------------------------------------------------------------------------------- /image-sound/cryptoAmpli/cryptoAmpli.pde: -------------------------------------------------------------------------------- 1 | // упаковщик-распаковщик изображения в звук 2 | // AlexGyver, 2020, https://alexgyver.ru/ 3 | 4 | /* 5 | В Processing зайти "Набросок / Импортировать библиотеку... / Добавить библиотеку..." 6 | В поиске найти и установить библиотеку ControlP5 7 | В поиске найти и установить библиотеку Sound 8 | */ 9 | import controlP5.*; 10 | ControlP5 cp5; 11 | Textarea debugArea; 12 | String cryptPath="", refPath="", imagePath=""; 13 | 14 | import processing.sound.*; 15 | import javax.sound.sampled.*; 16 | import java.io.*; 17 | // https://discourse.processing.org/t/saving-audiosample-as-a-sound-file-of-any-format/23174/5 18 | PGraphics pg; 19 | 20 | void setup() { 21 | size(400, 245); 22 | pg = createGraphics(width, height); 23 | background(130); 24 | 25 | // GUI 26 | cp5 = new ControlP5(this); 27 | cp5.addButton("load_ref").setCaptionLabel("LOAD AUDIO").setPosition(10, 10).setSize(120, 25); 28 | cp5.addButton("load_image").setCaptionLabel("LOAD IMAGE").setPosition(10, 40).setSize(120, 25); 29 | cp5.addButton("load_crypt").setCaptionLabel("LOAD CRYPT AUDIO").setPosition(10, 70).setSize(120, 25); 30 | 31 | cp5.addTextfield("key") 32 | .setPosition(10, 150) 33 | .setSize(120, 25) 34 | .setFont(createFont("arial", 15)) 35 | .setAutoClear(false) 36 | .setCaptionLabel("") 37 | .setText("key") 38 | ; 39 | cp5.addButton("encrypt").setCaptionLabel("ENCRYPT AND SAVE").setPosition(10, 180).setSize(120, 25); 40 | cp5.addButton("decrypt").setCaptionLabel("DECRYPT AND SAVE").setPosition(10, 210).setSize(120, 25); 41 | 42 | debugArea = cp5.addTextarea("decryptText") 43 | .setPosition(10, 100) 44 | .setSize(120, 40) 45 | .setFont(createFont("arial", 12)) 46 | .setLineHeight(14) 47 | .setColor(color(0)) 48 | .setColorBackground(color(180)) 49 | .setColorForeground(color(180)); 50 | ; 51 | 52 | debugArea.setText("CryptoAmpli v1.0 by AlexGyver"); 53 | } 54 | 55 | void draw() { 56 | image(pg, 0, 0); // вывод картинки в окне программы 57 | } 58 | 59 | // получаем сид из ключа шифрования 60 | int getSeed() { 61 | String thisKey = cp5.get(Textfield.class, "key").getText(); 62 | int keySeed = 1; 63 | for (int i = 0; i < thisKey.length(); i++) keySeed *= int(thisKey.charAt(i)); // перемножением 64 | return keySeed; 65 | } 66 | 67 | // получить незанятое случайное число 68 | int getFreeRnd(int[] buf, int max, int count) { 69 | while (true) { 70 | int thisVal = (int)random(0, max); 71 | boolean check = true; 72 | for (int k = 0; k < count; k++) { 73 | if (thisVal == buf[k]) check = false; 74 | } 75 | if (check) { 76 | buf[count] = thisVal; 77 | return thisVal; 78 | } 79 | } 80 | } 81 | 82 | // кнопка шифровки 83 | void encrypt() { 84 | if (refPath.length() != 0 && imagePath.length() != 0) { 85 | randomSeed(getSeed()); 86 | SoundFile file = new SoundFile(this, refPath); 87 | byte[] pcmRef = new byte[2 * file.frames() * file.channels()]; 88 | int framerate = int(file.frames() / file.duration()); // частота оцифровки 89 | loadSound(file, pcmRef); 90 | 91 | PImage image = loadImage(imagePath); 92 | image.loadPixels(); 93 | if (pcmRef.length < (image.width * image.height) * 3 * 2 + 4) { // 3 байта, через фрейм + 4 служебных 94 | debugArea.setText("Audio is too small for image"); 95 | return; 96 | } 97 | 98 | int[] used = new int[pcmRef.length / 2]; 99 | int count = 0; 100 | int maxVal = pcmRef.length / 2; 101 | pcmRef[getFreeRnd(used, maxVal, count++) * 2 + 1] = byte((image.width) & 0xFF); 102 | pcmRef[getFreeRnd(used, maxVal, count++) * 2 + 1] = byte((int(image.width) & 0xFF00) >> 8); 103 | pcmRef[getFreeRnd(used, maxVal, count++) * 2 + 1] = byte((image.height) & 0xFF); 104 | pcmRef[getFreeRnd(used, maxVal, count++) * 2 + 1] = byte((int(image.height) & 0xFF00) >> 8); 105 | 106 | for (int i = 0; i < image.width * image.height; i++) { 107 | pcmRef[getFreeRnd(used, maxVal, count++) * 2] = byte(constrain( ((image.pixels[i] & 0xFF0000) >> 16), 1, 254)); 108 | pcmRef[getFreeRnd(used, maxVal, count++) * 2] = byte(constrain( ((image.pixels[i] & 0xFF00) >> 8), 1, 254)); 109 | pcmRef[getFreeRnd(used, maxVal, count++) * 2] = byte(constrain( (image.pixels[i] & 0xFF), 1, 254)); 110 | } 111 | saveSound(pcmRef, framerate, file.channels()); 112 | debugArea.setText("Finished"); 113 | } else debugArea.setText("Image is not selected"); 114 | } 115 | 116 | 117 | // кнопка дешифровки 118 | void decrypt() { 119 | if (cryptPath.length() != 0) { 120 | randomSeed(getSeed()); 121 | SoundFile file = new SoundFile(this, cryptPath); 122 | byte[] pcmCrypt = new byte[2 * file.frames() * file.channels()]; 123 | loadSound(file, pcmCrypt); 124 | int[] used = new int[pcmCrypt.length / 2]; 125 | int count = 0; 126 | int maxVal = pcmCrypt.length / 2; 127 | 128 | int w = (pcmCrypt[getFreeRnd(used, maxVal, count++) * 2 + 1] & 0xFF) 129 | | ((pcmCrypt[getFreeRnd(used, maxVal, count++) * 2 + 1] & 0xFF) << 8); 130 | int h = (pcmCrypt[getFreeRnd(used, maxVal, count++) * 2 + 1] & 0xFF) 131 | | ((pcmCrypt[getFreeRnd(used, maxVal, count++) * 2 + 1] & 0xFF) << 8); 132 | 133 | if (w*h*2*3+4 > pcmCrypt.length) { 134 | debugArea.setText("Error"); 135 | return; 136 | } 137 | PImage decrypt = createImage(w, h, RGB); 138 | 139 | decrypt.loadPixels(); 140 | for (int i = 0; i < w * h; i++) { 141 | decrypt.pixels[i] |= ((pcmCrypt[getFreeRnd(used, pcmCrypt.length / 2, count++) * 2] & 0xFF) << 16); 142 | decrypt.pixels[i] |= ((pcmCrypt[getFreeRnd(used, pcmCrypt.length / 2, count++) * 2] & 0xFF) << 8); 143 | decrypt.pixels[i] |= (pcmCrypt[getFreeRnd(used, pcmCrypt.length / 2, count++) * 2] & 0xFF); 144 | } 145 | 146 | decrypt.updatePixels(); // обновляем изображение 147 | decrypt.save("decrypt_image.bmp"); // сохраняем 148 | debugArea.setText("Finished"); 149 | 150 | // вывести в окно программы 151 | pg.beginDraw(); 152 | pg.background(130); 153 | int maxW = width-130; 154 | int maxH = height-20; 155 | decrypt.resize(0, maxH); 156 | if (decrypt.width > maxW) decrypt.resize(maxW, 0); 157 | pg.image(decrypt, 150, 10); 158 | pg.endDraw(); 159 | } else debugArea.setText("Crypted image is not selected"); 160 | } 161 | 162 | // загрузить файл (моно или стерео) в pcmRef 163 | void loadSound(SoundFile file, byte[] pcm) { 164 | float floatData[] = new float [file.frames() * file.channels()]; // полный массив 165 | file.read(floatData); // читаем в массив 166 | for (int i = 0; i < floatData.length; i++) { 167 | int aux = floor(32767 * floatData[i]); 168 | pcm[i * 2] = byte(aux); 169 | pcm[(i * 2) + 1] = byte((int)aux >> 8); 170 | } 171 | } 172 | 173 | // сохранить pcm как wav 174 | void saveSound(byte[] pcm, int rate, int channels) { 175 | // https://discourse.processing.org/t/saving-audiosample-as-a-sound-file-of-any-format/23174/5 176 | // Samplerate, Samplesize em Bits, channels, signed, bigendian 177 | AudioFormat frmt = new AudioFormat(rate, 16, channels, true, false); 178 | AudioInputStream ais = new AudioInputStream( 179 | new ByteArrayInputStream(pcm), 180 | frmt, 181 | pcm.length / frmt.getFrameSize() 182 | ); 183 | try { 184 | AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(dataPath("") + "_crypt.wav")); 185 | } 186 | catch(Exception e) { 187 | e.printStackTrace(); 188 | } 189 | } 190 | 191 | 192 | void load_ref() { 193 | selectInput("", "selectRef"); 194 | } 195 | 196 | void selectRef(File selection) { 197 | if (selection != null) { 198 | refPath = selection.getAbsolutePath(); 199 | debugArea.setText(refPath); 200 | } else debugArea.setText("Audio is not selected"); 201 | } 202 | 203 | void load_image() { 204 | selectInput("", "selectImage"); 205 | } 206 | 207 | void selectImage(File selection) { 208 | if (selection != null) { 209 | imagePath = selection.getAbsolutePath(); 210 | debugArea.setText(imagePath); 211 | } else debugArea.setText("Image is not selected"); 212 | } 213 | 214 | void load_crypt() { 215 | selectInput("", "selectCrypt"); 216 | } 217 | 218 | void selectCrypt(File selection) { 219 | if (selection != null) { 220 | cryptPath = selection.getAbsolutePath(); 221 | debugArea.setText(cryptPath); 222 | } else debugArea.setText("Crypted sound is not selected"); 223 | } 224 | -------------------------------------------------------------------------------- /image-sound/cryptoAmpli/jazz.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoAmpli/jazz.wav -------------------------------------------------------------------------------- /image-sound/cryptoAmpli/loadPixels_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoAmpli/loadPixels_.png -------------------------------------------------------------------------------- /image-sound/cryptoAmpli/rick.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoAmpli/rick.jpg -------------------------------------------------------------------------------- /image-sound/cryptoProSound/cryptoProSound.pde: -------------------------------------------------------------------------------- 1 | // упаковщик-распаковщик звука в изображение 2 | // AlexGyver, 2020, https://alexgyver.ru/ 3 | 4 | /* 5 | В Processing зайти "Набросок / Импортировать библиотеку... / Добавить библиотеку..." 6 | В поиске найти и установить библиотеку ControlP5 7 | В поиске найти и установить библиотеку Sound 8 | */ 9 | import controlP5.*; 10 | ControlP5 cp5; 11 | Textarea debugArea; 12 | String cryptPath="", refPath="", soundPath=""; 13 | PImage imageCrypt, imageRef; 14 | int imgWidth; 15 | 16 | import processing.sound.*; 17 | import javax.sound.sampled.*; 18 | import java.io.*; 19 | SoundFile file; 20 | // https://discourse.processing.org/t/saving-audiosample-as-a-sound-file-of-any-format/23174/5 21 | 22 | byte[] pcm_data; 23 | int divider = 1; 24 | int bits = 8; 25 | 26 | void setup() { 27 | size(400, 245); 28 | background(130); 29 | 30 | // GUI 31 | cp5 = new ControlP5(this); 32 | cp5.addButton("load_ref").setCaptionLabel("LOAD IMAGE").setPosition(10, 10).setSize(120, 25); 33 | cp5.addButton("load_crypt_text").setCaptionLabel("LOAD AUDIO").setPosition(10, 40).setSize(120, 25); 34 | cp5.addButton("load_crypt").setCaptionLabel("LOAD CRYPT IMAGE").setPosition(10, 70).setSize(120, 25); 35 | 36 | cp5.addToggle("bit_res").setCaptionLabel("8/16 bit").setPosition(10, 100).setSize(45, 25).setMode(ControlP5.SWITCH).setValue(true); 37 | 38 | cp5.addSlider("quality").setCaptionLabel("QUALITY").setPosition(65, 100).setSize(65, 25).setRange(1, 8).setValue(1).setNumberOfTickMarks(8); 39 | cp5.getController("quality").getCaptionLabel().setPaddingX(-35); 40 | 41 | cp5.addTextfield("key") 42 | .setPosition(10, 150) 43 | .setSize(120, 25) 44 | .setFont(createFont("arial", 15)) 45 | .setAutoClear(false) 46 | .setCaptionLabel("") 47 | .setText("key") 48 | ; 49 | cp5.addButton("encrypt").setCaptionLabel("ENCRYPT AND SAVE").setPosition(10, 180).setSize(120, 25); 50 | cp5.addButton("decrypt").setCaptionLabel("DECRYPT AND SAVE").setPosition(10, 210).setSize(120, 25); 51 | 52 | debugArea = cp5.addTextarea("decryptText") 53 | .setPosition(150, 10) 54 | .setSize(240, 85) 55 | .setFont(createFont("arial", 12)) 56 | .setLineHeight(14) 57 | .setColor(color(0)) 58 | .setColorBackground(color(180)) 59 | .setColorForeground(color(180)); 60 | ; 61 | 62 | debugArea.setText("CryptoProSound v1.0 by AlexGyver"); 63 | } 64 | 65 | void draw() { 66 | } 67 | 68 | // получаем сид из ключа шифрования 69 | int getSeed() { 70 | String thisKey = cp5.get(Textfield.class, "key").getText(); 71 | int keySeed = 1; 72 | for (int i = 0; i < thisKey.length(); i++) keySeed *= int(thisKey.charAt(i)); // перемножением 73 | return keySeed; 74 | } 75 | 76 | // кнопка шифровки 77 | void encrypt() { 78 | if (refPath.length() != 0 && soundPath.length() != 0) { 79 | // загружаем картинку и считаем её размер 80 | imageCrypt = loadImage(refPath); 81 | imageCrypt.loadPixels(); 82 | int imgSize = imageCrypt.width * imageCrypt.height; 83 | 84 | // ошибки 85 | if (pcm_data.length == 0) { 86 | debugArea.setText("Empty sound file"); 87 | return; 88 | } 89 | if (pcm_data.length >= imgSize) { 90 | debugArea.setText("Image is too small"); 91 | return; 92 | } 93 | 94 | // добавляем ноль (ноль как число!) в самый конец 95 | pcm_data[pcm_data.length-1] = 0; 96 | 97 | randomSeed(getSeed()); 98 | 99 | // переменные 100 | int[] pixs = new int[pcm_data.length]; // запоминает предыдущие занятые пиксели 101 | int counter = 0; 102 | 103 | // цикл шифрования 104 | for (int i = 0; i < pcm_data.length; i++) { // пробегаем по фреймам (минус последний нулевой) 105 | // поиск свободного пикселя 106 | int thisPix; 107 | while (true) { 108 | thisPix = (int)random(0, imgSize); // выбираем случайный 109 | boolean check = true; // флаг проверки 110 | for (int k = 0; k < counter; k++) { // пробегаем по предыдущим выбранным пикселям 111 | if (thisPix == pixs[k]) check = false; // если пиксель уже занят, флаг опустить 112 | } 113 | if (check) { // пиксель свободен 114 | pixs[counter] = thisPix; // запоминаем в буфер 115 | counter++; // ++ 116 | break; // покидаем цикл 117 | } 118 | } 119 | 120 | int thisFrame = pcm_data[i]; // читаем текущий фрейм 121 | if (thisFrame == 0) thisFrame = 1; // не даём фрейму быть 0 122 | //thisFrame = byte(thisFrame + 128); 123 | //if (thisFrame == 0) thisFrame = 1; 124 | int thisColor = imageCrypt.pixels[thisPix]; // читаем пиксель 125 | 126 | // упаковка в RGB 323 127 | int newColor = (thisColor & 0xF80000); // 11111000 00000000 00000000 128 | newColor |= (thisFrame & 0xE0) << 11; // 00000111 00000000 00000000 129 | newColor |= (thisColor & (0x3F << 10)); // 00000000 11111100 00000000 130 | newColor |= (thisFrame & 0x18) << 5; // 00000000 00000011 00000000 131 | newColor |= (thisColor & (0x1F << 3)); // 00000000 00000000 11111000 132 | newColor |= (thisFrame & 0x7); // 00000000 00000000 00000111 133 | 134 | imageCrypt.pixels[thisPix] = newColor; // запихиваем обратно в картинку 135 | } 136 | imageCrypt.updatePixels(); // обновляем изображение 137 | imageCrypt.save("crypt_image.bmp"); // сохраняем 138 | debugArea.setText("Finished"); 139 | 140 | } else debugArea.setText("Image is not selected"); 141 | } 142 | 143 | // кнопка дешифровки 144 | void decrypt() { 145 | if (cryptPath.length() != 0) { 146 | // загружаем картинку и считаем её размер 147 | imageCrypt = loadImage(cryptPath); 148 | imageCrypt.loadPixels(); 149 | int imgSize = imageCrypt.width * imageCrypt.height; 150 | 151 | randomSeed(getSeed()); 152 | 153 | int[] pixs = new int[imgSize]; // буфер занятых пикселей 154 | byte[] pcmBuf = new byte[imgSize]; // буфер значений 155 | int counter = 0; 156 | 157 | // цикл дешифровки 158 | while (true) { 159 | 160 | // поиск свободного пикселя, такой же как выше 161 | int thisPix; 162 | while (true) { 163 | thisPix = (int)random(0, imgSize); 164 | boolean check = true; 165 | for (int k = 0; k < counter; k++) { 166 | if (thisPix == pixs[k]) check = false; 167 | } 168 | if (check) { 169 | pixs[counter] = thisPix; 170 | //counter++; 171 | break; 172 | } 173 | } 174 | 175 | // читаем пиксель 176 | int thisColor = imageCrypt.pixels[thisPix]; 177 | 178 | // распаковка из RGB 323 обратно в байт 179 | int thisFrame = 0; 180 | thisFrame |= (thisColor & 0x70000) >> 11; // 00000111 00000000 00000000 -> 00000000 00000000 11100000 181 | thisFrame |= (thisColor & 0x300) >> 5; // 00000000 00000011 00000000 -> 00000000 00000000 00011000 182 | thisFrame |= (thisColor & 0x7); // 00000000 00000000 00000111 183 | 184 | if (thisFrame == 0) break; // конец расшифровки (этот ноль мы сами добавили в конец). Выходим 185 | pcmBuf[counter] = byte(thisFrame); 186 | counter++; 187 | } 188 | // закидываем в новый буфер размером с принятые данные 189 | byte[] pcm = new byte[counter]; // буфер значений 190 | for (int i = 0; i < counter; i++) pcm[i] = pcmBuf[i]; 191 | 192 | // и сохраняем 193 | saveSound(pcm, divider, bits); 194 | debugArea.setText("Saved in decrypt_audio.wav"); 195 | } else debugArea.setText("Crypted image is not selected"); 196 | } 197 | 198 | // преобразовать float массив в целые числа. Вернёт размер 199 | int processSound(SoundFile file, int reducer, int bits, int chs) { 200 | float[] floatData = new float [file.frames() * chs]; 201 | file.read(floatData); 202 | if (bits == 8) { 203 | pcm_data = new byte[floatData.length/reducer/chs+1]; // +1 для нулевого 204 | for (int i = 0; i < floatData.length/reducer/chs; i++) { 205 | pcm_data[i] = byte(255 * floatData[i*reducer*chs]); 206 | } 207 | } else if (bits == 16) { 208 | pcm_data = new byte[2 * floatData.length/reducer/chs+1]; // +1 для нулевого 209 | for (int i = 0; i < floatData.length/reducer/chs; i++) { 210 | int aux = floor(32767 * floatData[i*reducer*chs]); 211 | pcm_data[i * 2] = byte(aux); 212 | pcm_data[(i * 2) + 1] = (byte)((int) aux >> 8); 213 | } 214 | } 215 | return pcm_data.length; 216 | } 217 | 218 | // сохранить целочисленный звук в файл 219 | void saveSound(byte[] pcm_data, int reducer, int bits) { 220 | // Samplerate, Samplesize em Bits, channels, signed, bigendian 221 | AudioFormat frmt = new AudioFormat(44100/reducer, bits, 1, true, false); 222 | AudioInputStream ais = new AudioInputStream( 223 | new ByteArrayInputStream(pcm_data), 224 | frmt, 225 | pcm_data.length / frmt.getFrameSize() 226 | ); 227 | try { 228 | AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new 229 | File(dataPath("") + "decrypt_audio.wav") 230 | ); 231 | } 232 | catch(Exception e) { 233 | e.printStackTrace(); 234 | } 235 | } 236 | 237 | // прочие кнопки 238 | void quality(int val) { 239 | divider = 9-val; 240 | } 241 | void bit_res(boolean state) { 242 | bits = state ? 8 : 16; 243 | } 244 | 245 | void load_ref() { 246 | selectInput("", "selectRef"); 247 | } 248 | 249 | void selectRef(File selection) { 250 | if (selection != null) { 251 | refPath = selection.getAbsolutePath(); 252 | PImage image = loadImage(refPath); 253 | 254 | String debug = ""; 255 | debug += refPath + "\r\n"; 256 | debug += "size " + (image.width * image.height) + " pixels \r\n"; 257 | 258 | debugArea.setText(debug); 259 | } else debugArea.setText("Image is not selected"); 260 | } 261 | 262 | void load_crypt() { 263 | selectInput("", "selectCrypt"); 264 | } 265 | 266 | void selectCrypt(File selection) { 267 | if (selection != null) { 268 | cryptPath = selection.getAbsolutePath(); 269 | PImage image = loadImage(cryptPath); 270 | 271 | String debug = ""; 272 | debug += cryptPath + "\r\n"; 273 | debug += "size " + (image.width * image.height) + " pixels \r\n"; 274 | 275 | debugArea.setText(debug); 276 | } else debugArea.setText("Crypted image is not selected"); 277 | } 278 | 279 | void load_crypt_text() { 280 | selectInput("", "selectSound"); 281 | } 282 | 283 | void selectSound(File selection) { 284 | if (selection != null) { 285 | soundPath = selection.getAbsolutePath(); 286 | file = new SoundFile(this, soundPath); 287 | 288 | // файл, делитель фреймов (1-10), битность (8 или 16), колво каналов (1 или 2) 289 | processSound(file, divider, bits, file.channels()); 290 | 291 | String debug = ""; 292 | debug += soundPath + "\r\n"; 293 | debug += "loaded " + (pcm_data.length) + " frames \r\n"; 294 | 295 | debugArea.setText(debug); 296 | } else debugArea.setText("Audio file is not selected"); 297 | } 298 | -------------------------------------------------------------------------------- /image-sound/cryptoProSound/gyver.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/gyver.wav -------------------------------------------------------------------------------- /image-sound/cryptoProSound/jazz.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/jazz.wav -------------------------------------------------------------------------------- /image-sound/cryptoProSound/loadPixels_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/loadPixels_.png -------------------------------------------------------------------------------- /image-sound/cryptoProSound/rick.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/rick.jpg -------------------------------------------------------------------------------- /image-sound/cryptoProSound/качество нужно менять ПЕРЕД загрузкой аудио!.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/качество нужно менять ПЕРЕД загрузкой аудио!.txt -------------------------------------------------------------------------------- /image-sound/cryptoProSound/расшифровка качественных аудио может занимать пару минут.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoProSound/расшифровка качественных аудио может занимать пару минут.txt -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoSpectrum/cat.jpg -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/cryptoSpectrum.pde: -------------------------------------------------------------------------------- 1 | // AlexGyver, 2020, https://alexgyver.ru/ 2 | float phaseShift = 147.9; 3 | 4 | /* 5 | В Processing зайти "Набросок / Импортировать библиотеку... / Добавить библиотеку..." 6 | В поиске найти и установить библиотеку ControlP5 7 | В поиске найти и установить библиотеку Sound 8 | */ 9 | import controlP5.*; 10 | ControlP5 cp5; 11 | Textarea debugArea; 12 | String refPath="", imagePath=""; 13 | PImage imageCrypt; 14 | int imgWidth; 15 | 16 | import processing.sound.*; 17 | import javax.sound.sampled.*; 18 | import java.io.*; 19 | 20 | SoundFile file; 21 | float[] ref, img; 22 | float refAmpl = 1.0, imgAmpl = 1.0; 23 | int spectW = 370; 24 | PGraphics pg; 25 | boolean updFlag = true; 26 | boolean saveFlag = false; 27 | float phaseVal = 0; 28 | int framerate = 44100; 29 | int audioSize = 5; 30 | boolean createFlag = false; 31 | 32 | void setup() { 33 | size(500, 350); 34 | background(130); 35 | 36 | // GUI 37 | cp5 = new ControlP5(this); 38 | cp5.addButton("load_ref").setCaptionLabel("LOAD AUDIO").setPosition(10, 10).setSize(100, 25); 39 | cp5.addButton("create_ref").setCaptionLabel("CREATE AUDIO").setPosition(10, 40).setSize(100, 25); 40 | 41 | cp5.addSlider("audio_size").setCaptionLabel("LENGTH").setPosition(10, 70).setSize(100, 25).setRange(0, 30).setValue(5); 42 | cp5.getController("audio_size").getCaptionLabel().setPaddingX(-35); 43 | 44 | cp5.addButton("load_image").setCaptionLabel("LOAD IMAGE").setPosition(10, 100).setSize(100, 25); 45 | cp5.addButton("encrypt").setCaptionLabel("ENCRYPT AND SAVE").setPosition(10, 130).setSize(100, 25); 46 | 47 | cp5.addSlider("ref_vol").setCaptionLabel("REF VOL").setPosition(120, 10).setSize(10, 50).setRange(0, 200).setValue(100); 48 | cp5.addSlider("img_vol").setCaptionLabel("IMG VOL").setPosition(310, 10).setSize(10, 50).setRange(0, 200).setValue(100); 49 | 50 | cp5.addSlider("spect_w").setCaptionLabel("WIDTH").setPosition(10, 310).setSize(100, 25).setRange(0, 370).setValue(370); 51 | cp5.getController("spect_w").getCaptionLabel().setPaddingX(-35); 52 | 53 | //cp5.addSlider("phase").setCaptionLabel("PHASE").setPosition(10, 130).setSize(100, 25).setRange(0, 3).setValue(1.0); 54 | //cp5.getController("phase").getCaptionLabel().setPaddingX(-35); 55 | 56 | pg = createGraphics(width, height); 57 | } 58 | 59 | void draw() { 60 | background(130); 61 | update(); 62 | image(pg, 0, 0); 63 | } 64 | 65 | 66 | // обновление слоя графики 67 | void update() { 68 | if (updFlag) { 69 | updFlag = false; 70 | int spectX = 120; 71 | int spectY = 80; 72 | int vol1X = 150; 73 | int vol2X = 340; 74 | int volSize = 150; 75 | 76 | pg.beginDraw(); 77 | pg.background(130); 78 | pg.noFill(); 79 | pg.stroke(0); 80 | pg.strokeWeight(1); 81 | pg.rect(vol1X, 10, volSize, 50); 82 | pg.rect(vol2X, 10, volSize, 50); 83 | pg.rect(spectX, spectY, spectW, 128*2); 84 | 85 | if (refPath.length() != 0 || createFlag) { 86 | for (int i = 0; i < volSize; i++) { 87 | float maxVal = 0; 88 | int part = ref.length / volSize; 89 | for (int j = 0; j < part; j++) { 90 | if (ref[i*part+j] > maxVal) maxVal = ref[i*part+j]; 91 | } 92 | maxVal *= refAmpl; 93 | pg.line(vol1X + i, 60, vol1X + i, 60 - maxVal*50); 94 | } 95 | } 96 | 97 | if (imagePath.length() != 0) { 98 | for (int i = 0; i < img.length; i++) img[i] = 0; 99 | for (int i = 0; i < imageCrypt.width; i++) { 100 | for (int j = 0; j < 128; j++) { 101 | int val = (int)brightness(imageCrypt.pixels[i + imageCrypt.width * (127-j)]); 102 | for (int k = 0; k < 256; k++) { 103 | img[i * 256 + k] += val/255.0 * 0.006 * sin((k+j*phaseVal)/framerate*2*PI*(500+j*150)); 104 | } 105 | } 106 | } 107 | for (int i = 0; i < volSize; i++) { 108 | float maxVal = 0; 109 | int part = img.length / volSize; 110 | for (int j = 0; j < part; j++) { 111 | if (img[i*part+j] > maxVal) maxVal = img[i*part+j]; 112 | } 113 | maxVal *= imgAmpl; 114 | pg.line(vol2X + i, 60, vol2X + i, 60 - maxVal*50); 115 | } 116 | } 117 | 118 | if (refPath.length() != 0 || createFlag) { 119 | float[] fitImg = new float[ref.length]; 120 | 121 | if (imagePath.length() != 0) { 122 | int amount = ref.length/img.length; 123 | if (amount == 0) return; 124 | int counter = 0; 125 | for (int i = 0; i < img.length/256; i++) { 126 | for (int j = 0; j < amount; j++) { 127 | for (int k = 0; k < 256; k++) { 128 | fitImg[counter++] = img[i * 256 + k]; 129 | } 130 | } 131 | } 132 | } 133 | 134 | int parts = ref.length / spectW; 135 | for (int i = 0; i < spectW; i++) { 136 | float soundPiece[] = new float[256]; 137 | for (int j = 0; j < 256; j++) { 138 | soundPiece[j] = ref[i*parts+j]*refAmpl; 139 | soundPiece[j] += fitImg[i*parts+j]*imgAmpl; 140 | } 141 | float[] spectrum = new float[256]; 142 | FFT(soundPiece, spectrum, 256, 256); 143 | for (int j = 0; j < 256; j++) { 144 | pg.stroke(spectrum[j/2]*30000); 145 | pg.point(spectX+i, spectY+256-j); 146 | } 147 | } 148 | if (saveFlag) { 149 | saveFlag = false; 150 | for (int i = 0; i < fitImg.length; i++) { 151 | fitImg[i] = ref[i]*refAmpl + fitImg[i]*imgAmpl; 152 | } 153 | processSound(fitImg, 1); 154 | } 155 | } 156 | 157 | pg.endDraw(); 158 | } 159 | } 160 | 161 | // крутилки 162 | void ref_vol(int val) { 163 | refAmpl = val / 100.0; 164 | updFlag = true; 165 | } 166 | void img_vol(int val) { 167 | imgAmpl = val / 100.0; 168 | updFlag = true; 169 | } 170 | void spect_w(int val) { 171 | spectW = val; 172 | updFlag = true; 173 | } 174 | void audio_size(int val) { 175 | audioSize = val; 176 | updFlag = true; 177 | } 178 | void phase(float val) { 179 | phaseVal = val; 180 | updFlag = true; 181 | } 182 | 183 | // кнопка шифровки 184 | void encrypt() { 185 | if (refPath.length() != 0 || createFlag) { 186 | saveFlag = true; 187 | updFlag = true; 188 | } 189 | } 190 | 191 | 192 | void load_ref() { 193 | selectInput("", "selectRef"); 194 | createFlag = false; 195 | } 196 | 197 | void create_ref() { 198 | framerate = 44100; 199 | phaseVal = phaseShift * framerate / 44100; 200 | ref = new float [framerate*audioSize]; 201 | updFlag = true; 202 | createFlag = true; 203 | } 204 | 205 | 206 | void selectRef(File selection) { 207 | if (selection != null) { 208 | refPath = selection.getAbsolutePath(); 209 | file = new SoundFile(this, refPath); 210 | float newRef[] = new float [file.frames() * file.channels()]; 211 | framerate = int(file.frames() / file.duration()); 212 | phaseVal = phaseShift * framerate / 44100; 213 | ref = new float [file.frames()]; 214 | file.read(newRef); 215 | for (int i = 0; i < ref.length; i++) ref[i] = newRef[i*file.channels()]; 216 | updFlag = true; 217 | } 218 | } 219 | 220 | 221 | void load_image() { 222 | selectInput("", "selectImage"); 223 | } 224 | 225 | void selectImage(File selection) { 226 | if (selection != null) { 227 | imagePath = selection.getAbsolutePath(); 228 | imageCrypt = loadImage(imagePath); 229 | imageCrypt.resize(0, 128); 230 | imageCrypt.filter(GRAY); 231 | imageCrypt.loadPixels(); 232 | img = new float[imageCrypt.width * 256]; 233 | updFlag = true; 234 | } 235 | } 236 | 237 | // сохранить float массив как wav 238 | void processSound(float[] floatData, int chs) { 239 | byte[] pcm_data = new byte[2 * floatData.length / chs]; 240 | for (int i = 0; i < floatData.length / chs; i++) { 241 | int aux = floor(32767 * floatData[i * chs]); 242 | pcm_data[i * 2] = byte(aux); 243 | pcm_data[(i * 2) + 1] = byte((int)aux >> 8); 244 | } 245 | 246 | // https://discourse.processing.org/t/saving-audiosample-as-a-sound-file-of-any-format/23174/5 247 | // Samplerate, Samplesize em Bits, channels, signed, bigendian 248 | AudioFormat frmt = new AudioFormat(framerate, 16, chs, true, false); 249 | AudioInputStream ais = new AudioInputStream( 250 | new ByteArrayInputStream(pcm_data), 251 | frmt, 252 | pcm_data.length / frmt.getFrameSize() 253 | ); 254 | try { 255 | AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new 256 | File(dataPath("") + "new.wav") 257 | ); 258 | } 259 | catch(Exception e) { 260 | e.printStackTrace(); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/fft.pde: -------------------------------------------------------------------------------- 1 | // https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B5_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%A4%D1%83%D1%80%D1%8C%D0%B5 2 | // AVal - массив анализируемых данных, Nvl - длина массива должна быть кратна степени 2. 3 | // FTvl - массив полученных значений, Nft - длина массива должна быть равна Nvl. 4 | 5 | void FFT(float[] AVal, float[] FTvl, int Nvl, int Nft) { 6 | int i, j, n, m, Mmax, Istp; 7 | float Tmpr, Tmpi, Wtmp, Theta; 8 | float Wpr, Wpi, Wr, Wi; 9 | float[] Tmvl; 10 | 11 | n = Nvl * 2; 12 | Tmvl = new float[n]; 13 | 14 | for (i = 0; i < n; i+=2) { 15 | Tmvl[i] = 0; 16 | Tmvl[i+1] = AVal[i/2]; 17 | } 18 | 19 | i = 1; 20 | j = 1; 21 | while (i < n) { 22 | if (j > i) { 23 | Tmpr = Tmvl[i]; 24 | Tmvl[i] = Tmvl[j]; 25 | Tmvl[j] = Tmpr; 26 | Tmpr = Tmvl[i+1]; 27 | Tmvl[i+1] = Tmvl[j+1]; 28 | Tmvl[j+1] = Tmpr; 29 | } 30 | i = i + 2; 31 | m = Nvl; 32 | while ((m >= 2) && (j > m)) { 33 | j = j - m; 34 | m = m >> 1; 35 | } 36 | j = j + m; 37 | } 38 | 39 | Mmax = 2; 40 | while (n > Mmax) { 41 | Theta = -TWO_PI / Mmax; 42 | Wpi = sin(Theta); 43 | Wtmp = sin(Theta / 2); 44 | Wpr = Wtmp * Wtmp * 2; 45 | Istp = Mmax * 2; 46 | Wr = 1; 47 | Wi = 0; 48 | m = 1; 49 | 50 | while (m < Mmax) { 51 | i = m; 52 | m = m + 2; 53 | Tmpr = Wr; 54 | Tmpi = Wi; 55 | Wr = Wr - Tmpr * Wpr - Tmpi * Wpi; 56 | Wi = Wi + Tmpr * Wpi - Tmpi * Wpr; 57 | 58 | while (i < n) { 59 | j = i + Mmax; 60 | Tmpr = Wr * Tmvl[j] - Wi * Tmvl[j-1]; 61 | Tmpi = Wi * Tmvl[j] + Wr * Tmvl[j-1]; 62 | 63 | Tmvl[j] = Tmvl[i] - Tmpr; 64 | Tmvl[j-1] = Tmvl[i-1] - Tmpi; 65 | Tmvl[i] = Tmvl[i] + Tmpr; 66 | Tmvl[i-1] = Tmvl[i-1] + Tmpi; 67 | i = i + Istp; 68 | } 69 | } 70 | 71 | Mmax = Istp; 72 | } 73 | 74 | for (i = 0; i < Nft; i++) { 75 | j = i * 2; 76 | FTvl[i] = 2*sqrt(pow(Tmvl[j], 2) + pow(Tmvl[j+1], 2))/Nvl; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/loadPixels_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoSpectrum/loadPixels_.png -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/logo500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoSpectrum/logo500.jpg -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/test1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoSpectrum/test1.wav -------------------------------------------------------------------------------- /image-sound/cryptoSpectrum/test2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/cryptoSpectrum/test2.wav -------------------------------------------------------------------------------- /image-sound/kek.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-sound/kek.bmp -------------------------------------------------------------------------------- /image-text/colorTest/colorTest.pde: -------------------------------------------------------------------------------- 1 | import controlP5.*; 2 | ControlP5 cp5; 3 | int R, G, B, Add; 4 | 5 | void setup() { 6 | size(350, 220); 7 | 8 | cp5 = new ControlP5(this); 9 | cp5.addSlider("R") 10 | .setPosition(10, 10) 11 | .setSize(200, 20) 12 | .setRange(0, 255) 13 | .setValue(0) 14 | ; 15 | cp5.addSlider("G") 16 | .setPosition(10, 35) 17 | .setSize(200, 20) 18 | .setRange(0, 255) 19 | .setValue(0) 20 | ; 21 | cp5.addSlider("B") 22 | .setPosition(10, 60) 23 | .setSize(200, 20) 24 | .setRange(0, 255) 25 | .setValue(0) 26 | ; 27 | 28 | cp5.addSlider("ADD") 29 | .setPosition(10, 85) 30 | .setSize(200, 20) 31 | .setRange(0, 255) 32 | .setValue(0) 33 | ; 34 | } 35 | 36 | void R(int val) { 37 | R = val; 38 | } 39 | void G(int val) { 40 | G = val; 41 | } 42 | void B(int val) { 43 | B = val; 44 | } 45 | void ADD(int val) { 46 | Add = val; 47 | } 48 | 49 | void draw() { 50 | background(150); 51 | color col = color(R, G, B); 52 | // col += Add; // прибавление 53 | 54 | // упаковка 55 | int newColor = (col & 0xF80000); // 11111000 00000000 00000000 56 | newColor |= (Add & 0xE0) << 11; // 00000111 00000000 00000000 57 | newColor |= (col & (0x3F << 10)); // 00000000 11111100 00000000 58 | newColor |= (Add & 0x18) << 5; // 00000000 00000011 00000000 59 | newColor |= (col & (0x1F << 3)); // 00000000 00000000 11111000 60 | newColor |= (Add & 0x7); // 00000000 00000000 00000111 61 | 62 | col = newColor | 0xFF000000; // + альфа канал 63 | // упаковка 64 | 65 | fill(col); 66 | noStroke(); 67 | rect(10, 110, 100, 100); 68 | textSize(15); 69 | text("R: " + red(col), 120, 140); 70 | text("G: " + green(col), 120, 160); 71 | text("B: " + blue(col), 120, 180); 72 | text(binary(col&0xFFFFFF), 35, 200); 73 | } 74 | -------------------------------------------------------------------------------- /image-text/crypto/appls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/appls.png -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/crypto.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/crypto.exe -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/controlP5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/controlP5.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/core.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/crypto.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/crypto.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/gluegen-rt-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/gluegen-rt-natives-windows-i586.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/gluegen-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/gluegen-rt.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/jogl-all-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/jogl-all-natives-windows-i586.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows32/lib/jogl-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows32/lib/jogl-all.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/crypto.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/crypto.exe -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/controlP5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/controlP5.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/core.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/crypto.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/crypto.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/gluegen-rt-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/gluegen-rt-natives-windows-amd64.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/gluegen-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/gluegen-rt.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/jogl-all-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/jogl-all-natives-windows-amd64.jar -------------------------------------------------------------------------------- /image-text/crypto/bin/application.windows64/lib/jogl-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/bin/application.windows64/lib/jogl-all.jar -------------------------------------------------------------------------------- /image-text/crypto/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/black.jpg -------------------------------------------------------------------------------- /image-text/crypto/blackwhite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/blackwhite.jpg -------------------------------------------------------------------------------- /image-text/crypto/crypto.pde: -------------------------------------------------------------------------------- 1 | import controlP5.*; 2 | ControlP5 cp5; 3 | Textarea myTextarea; 4 | String cryptPath="", refPath="", textPath=""; 5 | PImage imageCrypt, imageRef; 6 | int imgWidth; 7 | 8 | void setup() { 9 | size(400, 205); 10 | cp5 = new ControlP5(this); 11 | cp5.addButton("load_ref").setCaptionLabel("LOAD REFERENCE IMAGE").setPosition(10, 10).setSize(120, 25); 12 | cp5.addButton("load_crypt_text").setCaptionLabel("LOAD TEXT").setPosition(10, 40).setSize(120, 25); 13 | cp5.addButton("encrypt").setCaptionLabel("ENCRYPT AND SAVE").setPosition(10, 70).setSize(120, 25); 14 | cp5.addButton("load_crypt").setCaptionLabel("LOAD CRYPT IMAGE").setPosition(10, 140).setSize(120, 25); 15 | cp5.addButton("decrypt").setCaptionLabel("DECRYPT AND SAVE").setPosition(10, 170).setSize(120, 25); 16 | 17 | myTextarea = cp5.addTextarea("decryptText") 18 | .setPosition(150, 10) 19 | .setSize(240, 185) 20 | .setFont(createFont("arial", 12)) 21 | .setLineHeight(14) 22 | .setColor(color(0)) 23 | .setColorBackground(color(180)) 24 | .setColorForeground(color(180)); 25 | ; 26 | } 27 | 28 | void draw() { 29 | } 30 | 31 | void encrypt() { 32 | if (refPath.length() != 0 && textPath.length() != 0) { 33 | imageCrypt = loadImage(refPath); 34 | imageCrypt.loadPixels(); 35 | String[] lines = loadStrings(textPath); 36 | int imgSize = imageCrypt.width * imageCrypt.height; 37 | int textSize = 0; 38 | for (int i = 0; i < lines.length; i++) textSize += lines[i].length(); 39 | if (textSize == 0) return; 40 | int pixStep = imageCrypt.width * imageCrypt.height / textSize; 41 | int thisPix = 1; 42 | /*if ((int)imageCrypt.pixels[0] < -200)*/ imageCrypt.pixels[0] += pixStep; 43 | //else imageCrypt.pixels[0] -= pixStep; 44 | 45 | for (int i = 0; i < lines.length; i++) { 46 | for (int j = 0; j < lines[i].length(); j++) { 47 | int thisChar = lines[i].charAt(j); 48 | if (thisChar > 1000) thisChar -= 800; // костыль для русских букоф 49 | 50 | if (thisChar > pixStep) { // вмещаем с остатком 51 | int whole = thisChar / (pixStep-1); 52 | int left = thisChar % (pixStep-1); 53 | for (int k = 0; k < pixStep-1; k++) { 54 | imageCrypt.pixels[thisPix+k] += whole;//((int)imageCrypt.pixels[thisPix+k] < -200) ? whole : -whole; 55 | } 56 | imageCrypt.pixels[thisPix+pixStep-1] += left;//((int)imageCrypt.pixels[thisPix+whole] < -200) ? left : -left; 57 | } else { // по 1 58 | for (int k = 0; k < thisChar; k++) { 59 | imageCrypt.pixels[thisPix+k] += 1;//((int)imageCrypt.pixels[thisPix+k] < -200) ? 1 : -1; 60 | } 61 | } 62 | thisPix += pixStep; 63 | if (thisPix+pixStep > imgSize) break; 64 | } 65 | } 66 | imageCrypt.updatePixels(); 67 | imageCrypt.save("crypt_image.bmp"); 68 | } else println("not selected"); 69 | } 70 | 71 | void decrypt() { 72 | if (refPath.length() != 0 && cryptPath.length() != 0) { 73 | imageRef = loadImage(refPath); 74 | imageCrypt = loadImage(cryptPath); 75 | imageRef.loadPixels(); 76 | imageCrypt.loadPixels(); 77 | int imgSize = imageCrypt.width * imageCrypt.height; 78 | String decryptText = ""; 79 | int thisPix = 1; 80 | int pixStep; 81 | /*if ((int)imageRef.pixels[0] < -200)*/ pixStep = imageCrypt.pixels[0] - imageRef.pixels[0]; 82 | //else pixStep = imageRef.pixels[0] - imageCrypt.pixels[0]; 83 | 84 | while (true) { 85 | int thisChar = 0; 86 | for (int i = 0; i < pixStep; i++) { 87 | /*if ((int)imageRef.pixels[thisPix+i] < -200)*/ thisChar += imageCrypt.pixels[thisPix+i] - imageRef.pixels[thisPix+i]; 88 | //else thisChar += imageRef.pixels[thisPix+i] - imageCrypt.pixels[thisPix+i]; 89 | } 90 | 91 | if (thisChar == 0) break; 92 | if (thisChar > 200) thisChar += 800; // костыль для русских букоф 93 | decryptText += char(thisChar); 94 | thisPix += pixStep; 95 | if (thisPix+pixStep > imgSize) break; 96 | } 97 | myTextarea.setText(decryptText); 98 | String[] lines = new String[1]; 99 | lines[0] = decryptText; 100 | saveStrings("decrypt_text.txt", lines); 101 | } else println("not selected"); 102 | } 103 | 104 | void load_ref() { 105 | selectInput("", "selectRef"); 106 | } 107 | 108 | void selectRef(File selection) { 109 | if (selection != null) refPath = selection.getAbsolutePath(); 110 | } 111 | 112 | void load_crypt() { 113 | selectInput("", "selectCrypt"); 114 | } 115 | 116 | void selectCrypt(File selection) { 117 | if (selection != null) cryptPath = selection.getAbsolutePath(); 118 | } 119 | 120 | void load_crypt_text() { 121 | selectInput("", "selectCryptText"); 122 | } 123 | 124 | void selectCryptText(File selection) { 125 | if (selection != null) textPath = selection.getAbsolutePath(); 126 | } 127 | -------------------------------------------------------------------------------- /image-text/crypto/old.pde: -------------------------------------------------------------------------------- 1 | /* 2 | // ======= РАЗМАЗЫВАЕМ ======= 3 | void encrypt() { 4 | if (refPath.length() != 0 && textPath.length() != 0) { 5 | imageCrypt = loadImage(refPath); 6 | imageCrypt.loadPixels(); 7 | String[] lines = loadStrings(textPath); 8 | int imgSize = imageCrypt.width * imageCrypt.height; 9 | int textSize = 0; 10 | for (int i = 0; i < lines.length; i++) textSize += lines[i].length(); 11 | if (textSize == 0) return; 12 | int pixStep = imageCrypt.width * imageCrypt.height / textSize; 13 | int thisPix = 1; 14 | if ((int)imageCrypt.pixels[0] < -200) imageCrypt.pixels[0] += pixStep; 15 | else imageCrypt.pixels[0] -= pixStep; 16 | 17 | for (int i = 0; i < lines.length; i++) { 18 | for (int j = 0; j < lines[i].length(); j++) { 19 | int thisChar = lines[i].charAt(j); 20 | if (thisChar > 1000) thisChar -= 800; // костыль для русских букоф 21 | 22 | if (thisChar > pixStep) { // вмещаем с остатком 23 | int whole = thisChar / (pixStep-1); 24 | int left = thisChar % (pixStep-1); 25 | for (int k = 0; k < pixStep-1; k++) { 26 | imageCrypt.pixels[thisPix+k] += ((int)imageCrypt.pixels[thisPix+k] < -200) ? whole : -whole; 27 | } 28 | imageCrypt.pixels[thisPix+pixStep-1] += ((int)imageCrypt.pixels[thisPix+whole] < -200) ? left : -left; 29 | } else { // по 1 30 | for (int k = 0; k < thisChar; k++) { 31 | imageCrypt.pixels[thisPix+k] += ((int)imageCrypt.pixels[thisPix+k] < -200) ? 1 : -1; 32 | } 33 | } 34 | thisPix += pixStep; 35 | if (thisPix+pixStep > imgSize) break; 36 | } 37 | } 38 | imageCrypt.updatePixels(); 39 | imageCrypt.save("crypt_image.bmp"); 40 | } else println("not selected"); 41 | } 42 | 43 | void decrypt() { 44 | if (refPath.length() != 0 && cryptPath.length() != 0) { 45 | imageRef = loadImage(refPath); 46 | imageCrypt = loadImage(cryptPath); 47 | imageRef.loadPixels(); 48 | imageCrypt.loadPixels(); 49 | int imgSize = imageCrypt.width * imageCrypt.height; 50 | String decryptText = ""; 51 | int thisPix = 1; 52 | int pixStep; 53 | if ((int)imageRef.pixels[0] < -200) pixStep = imageCrypt.pixels[0] - imageRef.pixels[0]; 54 | else pixStep = imageRef.pixels[0] - imageCrypt.pixels[0]; 55 | 56 | while (true) { 57 | int thisChar = 0; 58 | for (int i = 0; i < pixStep; i++) { 59 | if ((int)imageRef.pixels[thisPix+i] < -200) thisChar += imageCrypt.pixels[thisPix+i] - imageRef.pixels[thisPix+i]; 60 | else thisChar += imageRef.pixels[thisPix+i] - imageCrypt.pixels[thisPix+i]; 61 | } 62 | 63 | if (thisChar == 0) break; 64 | if (thisChar > 200) thisChar += 800; // костыль для русских букоф 65 | decryptText += char(thisChar); 66 | thisPix += pixStep; 67 | if (thisPix+pixStep > imgSize) break; 68 | } 69 | myTextarea.setText(decryptText); 70 | String[] lines = new String[1]; 71 | lines[0] = decryptText; 72 | saveStrings("decrypt_text.txt", lines); 73 | } else println("not selected"); 74 | } 75 | */ 76 | 77 | /* 78 | // ======= РАНДОМ ======= 79 | void encrypt() { 80 | if (refPath.length() != 0 && textPath.length() != 0) { 81 | imageCrypt = loadImage(refPath); 82 | imageCrypt.loadPixels(); 83 | String[] lines = loadStrings(textPath); 84 | int textSize = 0; 85 | for (int i = 0; i < lines.length; i++) textSize += lines[i].length(); 86 | if (textSize == 0) return; 87 | long imgSize = imageCrypt.width * imageCrypt.height; 88 | randomSeed(imageCrypt.pixels[0]); 89 | long[] pixs = new long[textSize]; 90 | int curPix = 0; 91 | for (int i = 0; i < lines.length; i++) { 92 | for (int j = 0; j < lines[i].length(); j++) { 93 | int thisPix; 94 | while (true) { 95 | thisPix = (int)random(0, imgSize); 96 | boolean check = true; 97 | for (int k = 0; k < curPix; k++) { 98 | if (thisPix == pixs[k]) check = false; 99 | } 100 | if (check) { 101 | pixs[curPix] = thisPix; 102 | curPix++; 103 | break; 104 | } 105 | } 106 | int thisChar = lines[i].charAt(j); 107 | if (thisChar > 1000) thisChar -= 800; // костыль для русских букоф 108 | if ((int)imageCrypt.pixels[thisPix] < -200) imageCrypt.pixels[thisPix] += thisChar; 109 | else imageCrypt.pixels[thisPix] -= thisChar; 110 | } 111 | } 112 | imageCrypt.updatePixels(); 113 | imageCrypt.save("crypt_image.bmp"); 114 | } else println("not selected"); 115 | } 116 | 117 | void decrypt() { 118 | if (refPath.length() != 0 && cryptPath.length() != 0) { 119 | imageRef = loadImage(refPath); 120 | imageCrypt = loadImage(cryptPath); 121 | imageRef.loadPixels(); 122 | imageCrypt.loadPixels(); 123 | String decryptText = ""; 124 | long imgSize = imageCrypt.width * imageCrypt.height; 125 | randomSeed(imageRef.pixels[0]); 126 | long[] pixs = new long[(int)imgSize]; 127 | int curPix = 0; 128 | while (true) { 129 | int thisChar; 130 | int thisPix; 131 | while (true) { 132 | println(curPix); 133 | thisPix = (int)random(0, imgSize); 134 | boolean check = true; 135 | for (int k = 0; k < curPix; k++) { 136 | if (thisPix == pixs[k]) check = false; 137 | } 138 | if (check) { 139 | pixs[curPix] = thisPix; 140 | curPix++; 141 | break; 142 | } 143 | } 144 | if ((int)imageRef.pixels[thisPix] < -200) thisChar = imageCrypt.pixels[thisPix] - imageRef.pixels[thisPix]; 145 | else thisChar = imageRef.pixels[thisPix] - imageCrypt.pixels[thisPix]; 146 | if (thisChar == 0) break; 147 | if (thisChar > 200) thisChar += 800; // костыль для русских букоф 148 | decryptText += char(thisChar); 149 | } 150 | myTextarea.setText(decryptText); 151 | String[] lines = new String[1]; 152 | lines[0] = decryptText; 153 | saveStrings("decrypt_text.txt", lines); 154 | } else println("not selected"); 155 | } 156 | */ 157 | /* 158 | // ======= РАНДОМ ======= 159 | void encrypt() { 160 | if (refPath.length() != 0 && textPath.length() != 0) { 161 | imageCrypt = loadImage(refPath); 162 | imageCrypt.loadPixels(); 163 | String[] lines = loadStrings(textPath); 164 | int textSize = 0; 165 | for (int i = 0; i < lines.length; i++) textSize += lines[i].length(); 166 | if (textSize == 0) return; 167 | long imgSize = imageCrypt.width * imageCrypt.height; 168 | randomSeed(imageCrypt.pixels[0]); 169 | long[] pixs = new long[textSize]; 170 | int curPix = 0; 171 | for (int i = 0; i < lines.length; i++) { 172 | for (int j = 0; j < lines[i].length(); j++) { 173 | int thisPix; 174 | while (true) { 175 | thisPix = (int)random(0, imgSize); 176 | boolean check = true; 177 | for (int k = 0; k < curPix; k++) { 178 | if (thisPix == pixs[k]) check = false; 179 | } 180 | if (check) { 181 | pixs[curPix] = thisPix; 182 | curPix++; 183 | break; 184 | } 185 | } 186 | 187 | if ((int)imageCrypt.pixels[thisPix] < -200) imageCrypt.pixels[thisPix] += byte(lines[i].charAt(j)); 188 | else imageCrypt.pixels[thisPix] -= byte(lines[i].charAt(j)); 189 | } 190 | } 191 | imageCrypt.updatePixels(); 192 | imageCrypt.save("crypt_image.bmp"); 193 | } else println("not selected"); 194 | } 195 | 196 | void decrypt() { 197 | if (refPath.length() != 0 && cryptPath.length() != 0) { 198 | imageRef = loadImage(refPath); 199 | imageCrypt = loadImage(cryptPath); 200 | imageRef.loadPixels(); 201 | imageCrypt.loadPixels(); 202 | String decryptText = ""; 203 | long imgSize = imageCrypt.width * imageCrypt.height; 204 | randomSeed(imageRef.pixels[0]); 205 | long[] pixs = new long[(int)imgSize]; 206 | int curPix = 0; 207 | while (true) { 208 | int thisChar; 209 | int thisPix; 210 | while (true) { 211 | println(curPix); 212 | thisPix = (int)random(0, imgSize); 213 | boolean check = true; 214 | for (int k = 0; k < curPix; k++) { 215 | if (thisPix == pixs[k]) check = false; 216 | } 217 | if (check) { 218 | pixs[curPix] = thisPix; 219 | curPix++; 220 | break; 221 | } 222 | } 223 | if ((int)imageRef.pixels[thisPix] < -200) thisChar = imageCrypt.pixels[thisPix] - imageRef.pixels[thisPix]; 224 | else thisChar = imageRef.pixels[thisPix] - imageCrypt.pixels[thisPix]; 225 | if (thisChar == 0) break; 226 | decryptText += char(thisChar); 227 | } 228 | myTextarea.setText(decryptText); 229 | String[] lines = new String[1]; 230 | lines[0] = decryptText; 231 | saveStrings("decrypt_text.txt", lines); 232 | } else println("not selected"); 233 | } 234 | */ 235 | 236 | /* 237 | // ======= ШАГ 1 ======= 238 | // зашифровать 239 | void encrypt() { 240 | if (refPath.length() != 0 && textPath.length() != 0) { 241 | // загружаем картинку и текст 242 | imageCrypt = loadImage(refPath); 243 | imageCrypt.loadPixels(); 244 | String[] lines = loadStrings(textPath); 245 | 246 | int thisPix = 0; 247 | for (int i = 0; i < lines.length; i++) { // каждая строка в файле 248 | for (int j = 0; j < lines[i].length(); j++) { // каждый символ в строке 249 | int thisChar = lines[i].charAt(j); // читаем символ 250 | if (thisChar > 1000) thisChar -= 800; // костыль для русских букоф (UTF-8) 251 | imageCrypt.pixels[thisPix] += thisChar; // прибавляем код к цвету 252 | thisPix++; // следующий пиксель 253 | } 254 | } 255 | 256 | // сохраняем зашифрованную картинку 257 | imageCrypt.updatePixels(); 258 | imageCrypt.save("crypt_image.bmp"); 259 | } else println("not selected"); 260 | } 261 | 262 | // расшифровать 263 | void decrypt() { 264 | if (refPath.length() != 0 && cryptPath.length() != 0) { 265 | // загружаем картинки 266 | imageRef = loadImage(refPath); 267 | imageCrypt = loadImage(cryptPath); 268 | imageRef.loadPixels(); 269 | imageCrypt.loadPixels(); 270 | 271 | int thisPix = 0; 272 | String decryptText = ""; 273 | while (true) { 274 | // код символа как разница цветов 275 | int thisChar = imageCrypt.pixels[thisPix] - imageRef.pixels[thisPix]; 276 | if (thisChar == 0) break; // нулевой - конец 277 | if (thisChar > 200) thisChar += 800; // костыль для русских букоф 278 | decryptText += char(thisChar); // собираем текст 279 | thisPix++; // следующий пиксель 280 | } 281 | // выводим текст в окно программы 282 | myTextarea.setText(decryptText); 283 | String[] lines = new String[1]; 284 | lines[0] = decryptText; 285 | saveStrings("decrypt_text.txt", lines); 286 | } else println("not selected"); 287 | } 288 | */ 289 | 290 | /* 291 | // ======= ЗАПИСЫВАЕМ ШАГ В ПЕРВЫЙ ПИКС ======= 292 | void encrypt() { 293 | if (refPath.length() != 0 && textPath.length() != 0) { 294 | // загружаем картинку и текст 295 | imageCrypt = loadImage(refPath); 296 | imageCrypt.loadPixels(); 297 | String[] lines = loadStrings(textPath); 298 | 299 | // находим длину текста 300 | int textSize = 0; 301 | for (int i = 0; i < lines.length; i++) textSize += lines[i].length(); 302 | if (textSize == 0) return; // текста нет, выход 303 | 304 | // считаем шаг как размер изображения / размер текста 305 | int pixStep = imageCrypt.width * imageCrypt.height / textSize; 306 | 307 | int thisPix = 1; // записывать будем с 1 пикселя (0 занят) 308 | imageCrypt.pixels[0] += pixStep; // 0 пиксель хранит размер шага 309 | 310 | // пробегаем по всем буквам во всех строках 311 | for (int i = 0; i < lines.length; i++) { 312 | for (int j = 0; j < lines[i].length(); j++) { 313 | imageCrypt.pixels[thisPix] += byte(lines[i].charAt(j)); 314 | thisPix += pixStep; // следующий пиксель на величину шага 315 | } 316 | } 317 | imageCrypt.updatePixels(); 318 | imageCrypt.save("crypt_image.bmp"); 319 | } else println("not selected"); 320 | } 321 | 322 | void decrypt() { 323 | if (refPath.length() != 0 && cryptPath.length() != 0) { 324 | // загружаем обе картинки 325 | imageRef = loadImage(refPath); 326 | imageCrypt = loadImage(cryptPath); 327 | imageRef.loadPixels(); 328 | imageCrypt.loadPixels(); 329 | 330 | String decryptText = ""; 331 | int thisPix = 1; 332 | int pixStep = imageCrypt.pixels[0] - imageRef.pixels[0]; // размер шага 333 | 334 | while (true) { 335 | // вычитаем 336 | int thisChar = imageCrypt.pixels[thisPix] - imageRef.pixels[thisPix]; 337 | if (thisChar == 0) break; // завершение (одинаковые пиксели, текст кончился) 338 | decryptText += char(thisChar); // буфер текста 339 | thisPix += pixStep; // двигаемся на следующий 340 | } 341 | 342 | // вывод и сохранение 343 | myTextarea.setText(decryptText); 344 | String[] lines = new String[1]; 345 | lines[0] = decryptText; 346 | saveStrings("decrypt_text.txt", lines); 347 | } else println("not selected"); 348 | } 349 | */ 350 | -------------------------------------------------------------------------------- /image-text/crypto/text.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -------------------------------------------------------------------------------- /image-text/crypto/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/crypto/white.jpg -------------------------------------------------------------------------------- /image-text/cryptoText/apples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/apples.png -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/cryptoText.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/cryptoText.exe -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/controlP5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/controlP5.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/core.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/cryptoText.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/cryptoText.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/gluegen-rt-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/gluegen-rt-natives-windows-i586.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/gluegen-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/gluegen-rt.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/jogl-all-natives-windows-i586.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/jogl-all-natives-windows-i586.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows32/lib/jogl-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows32/lib/jogl-all.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/cryptoText.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/cryptoText.exe -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/controlP5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/controlP5.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/core.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/core.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/cryptoText.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/cryptoText.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/gluegen-rt-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/gluegen-rt-natives-windows-amd64.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/gluegen-rt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/gluegen-rt.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/jogl-all-natives-windows-amd64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/jogl-all-natives-windows-amd64.jar -------------------------------------------------------------------------------- /image-text/cryptoText/bin/application.windows64/lib/jogl-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/bin/application.windows64/lib/jogl-all.jar -------------------------------------------------------------------------------- /image-text/cryptoText/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/cat.jpg -------------------------------------------------------------------------------- /image-text/cryptoText/cryptoText.pde: -------------------------------------------------------------------------------- 1 | // упаковщик-распаковщик текста в изображение 2 | // AlexGyver, 2020, https://alexgyver.ru/ 3 | // Добавил парсинг переноса строк 4 | 5 | /* 6 | В Processing зайти "Набросок / Импортировать библиотеку... / Добавить библиотеку..." 7 | В поиске найти и установить библиотеку ControlP5 8 | */ 9 | import controlP5.*; 10 | ControlP5 cp5; 11 | Textarea debugArea; 12 | String cryptPath="", refPath="", textPath=""; 13 | PImage imageCrypt, imageRef; 14 | int imgWidth; 15 | 16 | void setup() { 17 | size(400, 205); 18 | 19 | // GUI 20 | cp5 = new ControlP5(this); 21 | cp5.addButton("load_ref").setCaptionLabel("LOAD IMAGE").setPosition(10, 10).setSize(120, 25); 22 | cp5.addButton("load_crypt_text").setCaptionLabel("LOAD TEXT").setPosition(10, 40).setSize(120, 25); 23 | cp5.addButton("load_crypt").setCaptionLabel("LOAD CRYPT IMAGE").setPosition(10, 70).setSize(120, 25); 24 | cp5.addTextfield("key") 25 | .setPosition(10, 110) 26 | .setSize(120, 25) 27 | .setFont(createFont("arial", 15)) 28 | .setAutoClear(false) 29 | .setCaptionLabel("") 30 | .setText("key") 31 | ; 32 | cp5.addButton("encrypt").setCaptionLabel("ENCRYPT AND SAVE").setPosition(10, 140).setSize(120, 25); 33 | cp5.addButton("decrypt").setCaptionLabel("DECRYPT AND SAVE").setPosition(10, 170).setSize(120, 25); 34 | 35 | debugArea = cp5.addTextarea("decryptText") 36 | .setPosition(150, 10) 37 | .setSize(240, 185) 38 | .setFont(createFont("arial", 12)) 39 | .setLineHeight(14) 40 | .setColor(color(0)) 41 | .setColorBackground(color(180)) 42 | .setColorForeground(color(180)); 43 | ; 44 | debugArea.setText("CryptoText v1.0 by AlexGyver"); 45 | } 46 | 47 | void draw() { 48 | } 49 | 50 | // получаем сид из ключа шифрования 51 | int getSeed() { 52 | String thisKey = cp5.get(Textfield.class, "key").getText(); 53 | int keySeed = 1; 54 | for (int i = 0; i < thisKey.length()-1; i++) 55 | keySeed *= int(thisKey.charAt(i) * (thisKey.charAt(i)-thisKey.charAt(i+1))); // перемножением с разностью 56 | return keySeed; 57 | } 58 | 59 | // кнопка шифровки 60 | void encrypt() { 61 | if (refPath.length() != 0 && textPath.length() != 0) { 62 | // загружаем картинку и считаем её размер 63 | imageCrypt = loadImage(refPath); 64 | imageCrypt.loadPixels(); 65 | int imgSize = imageCrypt.width * imageCrypt.height; 66 | 67 | // загружаем текст и считаем его размер 68 | String[] lines = loadStrings(textPath); 69 | int textSize = 0; 70 | for (int i = 0; i < lines.length; i++) textSize += (lines[i].length() + 1); // +1 на перенос 71 | 72 | // ошибки 73 | if (textSize == 0) { 74 | debugArea.setText("Empty text file"); 75 | return; 76 | } 77 | if (textSize >= imgSize) { 78 | debugArea.setText("Image is too small"); 79 | return; 80 | } 81 | 82 | // добавляем ноль (ноль как число!) в самый конец текста 83 | lines[lines.length-1] += '\0'; 84 | textSize += 1; 85 | 86 | randomSeed(getSeed()); 87 | 88 | // переменные 89 | int[] pixs = new int[textSize]; // запоминает предыдущие занятые пиксели 90 | int counter = 0; 91 | 92 | // цикл шифрования 93 | for (int i = 0; i < lines.length; i++) { // пробегаем по строкам 94 | for (int j = 0; j < lines[i].length() + 1; j++) { // и каждому символу в них +1 95 | 96 | // поиск свободного пикселя 97 | int thisPix; 98 | while (true) { 99 | thisPix = (int)random(0, imgSize); // выбираем случайный 100 | boolean check = true; // флаг проверки 101 | for (int k = 0; k < counter; k++) { // пробегаем по предыдущим выбранным пикселям 102 | if (thisPix == pixs[k]) check = false; // если пиксель уже занят, флаг опустить 103 | } 104 | if (check) { // пиксель свободен 105 | pixs[counter] = thisPix; // запоминаем в буфер 106 | counter++; // ++ 107 | break; // покидаем цикл 108 | } 109 | } 110 | 111 | int thisChar; 112 | if (j == lines[i].length()) thisChar = int('\n'); // последний - перенос строки 113 | else thisChar = lines[i].charAt(j); // читаем текущий символ 114 | 115 | if (thisChar > 1000) thisChar -= 890; // костыль для русских букоф 116 | 117 | int thisColor = imageCrypt.pixels[thisPix]; // читаем пиксель 118 | 119 | // упаковка в RGB 323 120 | int newColor = (thisColor & 0xF80000); // 11111000 00000000 00000000 121 | newColor |= (thisChar & 0xE0) << 11; // 00000111 00000000 00000000 122 | newColor |= (thisColor & (0x3F << 10)); // 00000000 11111100 00000000 123 | newColor |= (thisChar & 0x18) << 5; // 00000000 00000011 00000000 124 | newColor |= (thisColor & (0x1F << 3)); // 00000000 00000000 11111000 125 | newColor |= (thisChar & 0x7); // 00000000 00000000 00000111 126 | 127 | imageCrypt.pixels[thisPix] = newColor; // запихиваем обратно в картинку 128 | } 129 | } 130 | imageCrypt.updatePixels(); // обновляем изображение 131 | imageCrypt.save("crypt_image.bmp"); // сохраняем 132 | debugArea.setText("Finished"); 133 | } else debugArea.setText("Image is not selected"); 134 | } 135 | 136 | // кнопка дешифровки 137 | void decrypt() { 138 | if (cryptPath.length() != 0) { 139 | // загружаем картинку и считаем её размер 140 | imageCrypt = loadImage(cryptPath); 141 | imageCrypt.loadPixels(); 142 | int imgSize = imageCrypt.width * imageCrypt.height; 143 | 144 | randomSeed(getSeed()); 145 | 146 | int[] pixs = new int[imgSize]; // буфер занятых пикселей 147 | String decryptText = ""; // буфер текста 148 | int counter = 0; 149 | 150 | // цикл дешифровки 151 | while (true) { 152 | 153 | // поиск свободного пикселя, такой же как выше 154 | int thisPix; 155 | while (true) { 156 | thisPix = (int)random(0, imgSize); 157 | boolean check = true; 158 | for (int k = 0; k < counter; k++) { 159 | if (thisPix == pixs[k]) check = false; 160 | } 161 | if (check) { 162 | pixs[counter] = thisPix; 163 | counter++; 164 | break; 165 | } 166 | } 167 | 168 | // читаем пиксель 169 | int thisColor = imageCrypt.pixels[thisPix]; 170 | 171 | // распаковка из RGB 323 обратно в байт 172 | int thisChar = 0; 173 | thisChar |= (thisColor & 0x70000) >> 11; // 00000111 00000000 00000000 -> 00000000 00000000 11100000 174 | thisChar |= (thisColor & 0x300) >> 5; // 00000000 00000011 00000000 -> 00000000 00000000 00011000 175 | thisChar |= (thisColor & 0x7); // 00000000 00000000 00000111 176 | 177 | if (thisChar > 130) thisChar += 890; // костыль для русских букоф 178 | if (thisChar == 0) break; // конец текста (этот ноль мы сами добавили в конец). Выходим 179 | decryptText += char(thisChar); // пишем в буфер 180 | } 181 | debugArea.setText(decryptText); // выводим в гуи 182 | 183 | // и сохраняем в txt 184 | String[] lines = new String[1]; 185 | lines[0] = decryptText; 186 | saveStrings("decrypt_text.txt", lines); 187 | } else debugArea.setText("Crypted image is not selected"); 188 | } 189 | 190 | // прочие кнопки 191 | void load_ref() { 192 | selectInput("", "selectRef"); 193 | } 194 | 195 | void selectRef(File selection) { 196 | if (selection != null) { 197 | refPath = selection.getAbsolutePath(); 198 | debugArea.setText(refPath); 199 | } else debugArea.setText("Image is not selected"); 200 | } 201 | 202 | void load_crypt() { 203 | selectInput("", "selectCrypt"); 204 | } 205 | 206 | void selectCrypt(File selection) { 207 | if (selection != null) { 208 | cryptPath = selection.getAbsolutePath(); 209 | debugArea.setText(cryptPath); 210 | } else debugArea.setText("Crypted image is not selected"); 211 | } 212 | 213 | void load_crypt_text() { 214 | selectInput("", "selectCryptText"); 215 | } 216 | 217 | void selectCryptText(File selection) { 218 | if (selection != null) { 219 | textPath = selection.getAbsolutePath(); 220 | debugArea.setText(textPath); 221 | } else debugArea.setText("Text file is not selected"); 222 | } 223 | -------------------------------------------------------------------------------- /image-text/cryptoText/logo150.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/logo150.jpg -------------------------------------------------------------------------------- /image-text/cryptoText/rick.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/rick.jpg -------------------------------------------------------------------------------- /image-text/cryptoText/text.txt: -------------------------------------------------------------------------------- 1 | Всем привет! После долгого перерыва хотелось показать вам что-то круто и железное, но буквально пару дней назад у меня появилась интересная идея для видоса на тему алгоритмов и всего такого. Поэтому сегодня вас ждёт небольшое погружение в цифровой мир, щепотка школьной информатики и рассказ о моих попытках закодировать текст внутри картинки. Будет научпоп, наливайте чай. 2 | На днях мой соведущий со второго канала предложил мне снять видос о методах шифрования, на что я ответил что абсолютно ничего в этом не смыслю, потому что никогда с этим не сталкивался, да и звучит как то скучно и все методы давно описаны на википедии. Я подумал, а как можно так извратиться, чтобы сделать что то необычное и интересное? У меня на канале уже был ролик, где я успешно передавал изображение по лучу лазера, и он вроде как вам понравился. И тут я понял, что было бы жутко интересно зашифровать не текст в тексте, а текст в картинке, потому что картинка на самом деле это тот же самый текст. Давайте попробуем. 3 | Для работы я буду использовать бесплатную среду разработки processing, которая создана для того, что программировать могли всякие дизайнеры и домохозяйки. Её даже устанавливать не нужно, скачал запустил и кодишь себе на какой то смеси Java с картоном. Кстати на западе процессинг очень активно используют в школах и универах, не знаю почему мы до сих пор ковыряем паскаль и не идём в ногу со временем. 4 | А мы с вами, прежде чем начать кодить, вспомним некоторые базовые вещи, чтобы понять как это всё будет работать, а именно – как компьютер хранит и обрабатывает изображение и текст. Изображения бывают двух типов – векторные и растровые. Файл векторного изображения содержит в себе грубо говоря набор уравнений, которые описывают каждую линию, область и фигуру, из которой состоит изображение. Такие изображения нам не подходят. Растровое изображение представляет собой набор точек, пикселей, каждый имеет свой цвет и положение на картинке. Вот это уже интереснее. На данный момент существует довольно таки много различных форматов изображения, но в основе всего лежит формат bmp, файл которого содержит в себе просто список пикселей, то есть фактически цвет каждого пикселя. Именно так мы работали с картинками когда передавали их по лазеру. После появления бмп появились алгоритмы сжатия изображения, например тот же жипег, он содержит намного меньше информации за счёт алгоритмов сжатия, из за которых также теряется часть информации. Так что сегодня мы будем работать именно с бмп, так как он не испортит цветовые данные и сокрытый среди них текст. 5 | Немного цветовой теории. Цвет в представлении компьютера задаётся тремя базовыми цветами, красным зелёным и синим. Смешивая эти три цвета в разных соотношениях можно получить другие цвета и их оттенки. Очень много где используется стандарт глубины цвета 24 бита, я думаю вы не раз видели такую цифру. А ещё чаще вы могли видеть цифру 16,7 миллионов цветов и оттенков, применительно к дисплеям. Эти две цифры связаны через степень, потому что 24 бита это и есть 16,7 миллионов значений. Также 24 бита это 3 по 8, по 8 бит на каждый из трёх базовых цветов. 8 бит это значение от 0 до 255, то есть каждый цвет имеет всего 256 градаций яркости, но вместе они дают 16,7 млн комбинаций и оттенков. Вот такая математика. Стандартный бмп файл также имеет глубину 24 бита и очень несложно представить, что у него там под капотом. 6 | А что у нас с текстовыми файлами? Текст – это такой же набор байтов, закодированный особым образом. Каждой букве и символу соответствует число, это соответствие задаёт таблица ASCII. Вот её стандартный вид, русских букв тут нет и они кодируются другими числами в зависимости от кодировки файла. Как несложно заметить, весь алфавит и символы умещаются в один байт. Чтож, осталось нам сделать РРАР, совместить одни цифры с другими, давайте подумаем как это может быть сделано. Я не буду углубляться в код на процессинге, он довольно простой и желающие могут сами его поковырять так как я выложу все исходники на гитхаб, а вся документация есть на официальном сайте. 7 | Начать предлагаю с самого примитивного: берём исходное изображение и к значению каждого пикселя по порядку просто прибавляем код символа в тексте по порядку. Диапазон цвета у нас от 0 до почти 17 миллионов, а буквы – не более 120. Фактически цвет и не должен даже измениться от такой незначительной прибавки. В итоге у нас получится два изображения: оригинальное и с зашитым текстом. Используя оригинальное изображение как ключ, можно попиксельно вычесть его из зашифрованного и останется только текст. То есть если у нас и у того, кому мы хотим передать шифровку есть оригинал изображения, мы с ним можем обмениваться скрытыми сообщениями. 8 | Я сделал не побоюсь этого слова программу, в которой есть кнопощки, и можно выбрать файл исходного изображения в любом формате, выбрать текст в формате текстового файла, нажать на энкрипт и получить зашифрованную картинку в формате бмп. В обратную сторону: загружаем исходную картинку, загружаем зашифрованную, нажимаем декрипт и получаем текст. Работает? Работает. Текст также выводится в тхт файл. А теперь в вопросу о том, как выглядит наше изображение, и выглядит оно заметно не очень. А точнее, оно посинело там, где зашифрован текст. 9 | Сейчас давайте попробуем решить проблему в лоб. Мы знаем длину текста и размер изображения, соответственно можем равномерно распределить все буквы по пикселям. При расшифровке мы не будем знать длину текста, поэтому можно в самый первый пиксель зашифровать размер шага, и со второго пикселя с этим шагом шифровать буквы. При расшифровке повторить процесс в обратном порядке, и всё. Работает? Работает. Картинка выглядит вот так. Стало ли лучше? Ну хз, теперь появились синие полосы. 10 | Продолжим решать проблему в лоб и сделаем следующее: размажем значение буквы по всему промежутку между двумя соседними буквами. Если текст сильно меньше картинки, то буква размажется по единичкам и не внесёт никакого визуального изменения в исходное изображение. Проверяем. Работает. Картинка стала выглядеть вот так и кажется задача решена, но есть два больших но. Если на изображении будет область с полностью белым цветом, мы ничего не сможем туда записать, потому что это уже максимум. А если там почти белый, то часть информации потеряется и мы опять же получим битые символы. А если на изображении будет синий цвет, то даже небольшое прибавленное значение может полностью его исказить. Почему? И тут в дело вступает школьная информатика, а именно бинарная математика. 11 | Дело в том, что результирующий цвет не является перемножением или сложением основных цветов, там процесс гораздо более сложный и интересный. У каждого базового цвета в основном цвете есть своё определённое место, так как это именно 24 битный цвет. Каждый байт содержит 8 бит, итоговый цвет строится вот так. То есть красный цвет на самом деле имеет значение примерно от 65536 до 16711680, зелёный от 256 до 65280, и синий от 0 до 255. Прибавляя какое то значение к общему цвету мы фактически увеличиваем только синий канал, и если байт синего канала переполняется, он возвращается обратно в 0 и увеличивает также соседний зелёный канал. Таким образом если цвет пикселя содержал синий, то после прибавления кода буквы он рискует этот синий просто потерять. Причём если это был например серый, то без синего он станет жёлтым, так как в нём останется только красный и зелёный. То есть если мы хотим зашифровать картинку так, чтобы визуально не было вообще никаких искажений, нам придётся полностью менять стратегию. 12 | На самом деле исходная картинка для этого дела вообще не нужна, потому что текст можно зашить прямо в изображение практически не внося изменений в цвет. Если менять младший бит одного цвета, или даже два, итоговый цвет практически не изменится, то есть мы можем прямо хранить там букву и не нужно будет искать никакой разности с исходной картинкой. И тут нам нужно будет сделать следующее: у нас есть три байта цвета и один байт буквы. Мы разбиваем байт буквы на 3 кусочка, например 3 2 3, и записываем как младшие биты основных цветов. Данная операция делается при помощи сдвигов и выглядит примерно вот так. При расшифровке мы собираем наш байт обратно вот таким образом. И такой способ не вносит никаких видимых изменений в цвет несмотря на то, что мы прямо таки записали буквы в пиксели. И это реально круто. Но как нам теперь защитить изображение от расшифровки? Я решил действовать максимально хитро и использовать случайные числа. 13 | Как известно, компьютер не может генерировать именно случайные числа, потому что он выполняет только строгие математические операции. В процессинг у нас есть функция рандом, которая делает псевдослучайные числа. Псевдослучайные числа генерируются довольно простым образом: берётся некое стартовое базовое число, называемое сидом, то есть зерном. С этим числом производится ряд математических операций и на выходе получается другое число. Генератор перезапускается на новый круг с учетом предыдущих вычислений и выдаёт новое число, и так далее. То есть сид по сути задаёт огромную последовательность чисел, и каждому сиду будет соответствовать своя уникальная последовательность. Если в качестве ключа шифрования мы возьмём сид, а он может быть 32 битным, то получим весьма неплохой набор вариантов. Мы можем записывать наш текст в пиксели, номера которых будут получены из генератора псевдослучайных чисел. Зная этот сид, можно будет прочитать нужные пиксели в нужном порядке и восстановить исходный текст. Если генератор вдруг подкинет номер пикселя, который мы уже записали, нужно будет пропустить этот шаг и получить новое число, для чего будем запоминать номера уже занятых пикселей. 14 | Чтобы при расшифровке знать, что текст закончился, в конце текста я зашиваю в пиксель ноль, то есть вот так. Как только при расшифровке программа натыкается на такой ноль, текст считается расшифрованным. Вот такая маленькая хитрость. 15 | Я добавил в программу окошко для ввода ключа шифрования, сам ключ может состоять из любых букв цифр и символов и иметь любую длину. В исходнике который я оставлю, сид получается простым перемножением кодов символов, что не очень надёжно. Предлагайте в комментариях более надёжные и криптографически стойкие способы генерации пароля, будет интересно почитать. Можно например дополнительно умножать каждый символ на его разность с предыдущим, или что то в этом роде. При плотном расположении пикселей, то есть когда текст занимает почти всю картинку, процесс расшифровки может занимать больше секунды. И взломать такую картинку подбором получится ой как небыстро. 16 | Что я получил в итоге: текст зашивается в изображение, зашивается в псевдослучайный набор пикселей и минимально меняет само изображение, вот даже муха не заметит как говорится. Если закрасить зашифрованные пиксели чёрным, то можно увидеть где именно хранятся буквы. Довольно таки равномерно получается. Чтобы расшифровать такое изображение нужен текстовый ключ шифрования. Теперь к вопросу о размере текста. Фактически один пиксель хранит одну букву, поэтому в картинку с размером 150 на 150 пикселей можно зашакалить аж 22,5 тысячи символов, а это кстати размер сценария к этому видео, 3 листа А4. Не знаю, пригодятся ли кому данные наработки, но как минимум было чертовски интересно во всём этом разобраться. Скачать исходники и готовую скомпилированную программу можно по ссылке в описании, забирайте изучайте. На этом у меня сегодня всё, если у вас есть идеи по поводу того, что ещё и куда можно зашифровать, пишите в коментах, я попробую реализовать ещё что нибудь и сделаю видос. С вами был алекс гайвер, надеюсь, до скорой встречи. 17 | А ЕЩЁ Я ОСТАВИЛ НЕСКОЛЬКО ЗАШИФРОВАННЫХ КАРТИНОК В ПАПКЕ С ПРОГРАММОЙ =) ПАРОЛЬ ALEX_GYVER -------------------------------------------------------------------------------- /image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_1.bmp -------------------------------------------------------------------------------- /image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_2.bmp -------------------------------------------------------------------------------- /image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_3.bmp -------------------------------------------------------------------------------- /image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/image-text/cryptoText/шифровки от Гувера =) Пароль в видео/crypted_4.bmp -------------------------------------------------------------------------------- /logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexGyver/crypto/3f065ff405ad895c4dafa9f5d2bb958f22d54f16/logo.bmp --------------------------------------------------------------------------------