Простий інструмент для стеґанографії на C++

Вступ

Стеґанографія — звучить елегантно, чи не так? По суті, це мистецтво приховувати інформацію на виду. Коли-небудь замислювалися над тим, як вмонтувати секретне повідомлення в зображення? Ось саме це я і зробив за допомогою цього інструменту для BMP стеґанографії.

Ця маленька програма, яку я написав, дозволяє вам приховувати (і отримувати) текстові повідомлення у BMP зображеннях. І ні, це не магія — це наука. Змінюючи найменші, майже непомітні частини зображення, ми можемо зашифрувати повідомлення, не викликаючи підозр у когось. До того ж, для додаткової безпеки я додав шифрування на основі XOR для прихованого повідомлення.

У цьому пості я проведу вас через принципи роботи інструменту, розберу код і покажу, як ви можете використовувати його самі. Поглянемо, як це працює!

pic

Як це працює

Ідея проста: BMP зображення зберігає дані пікселів, і кожен піксель має значення кольорів для червоного, зеленого та синього каналів. Кожне з цих значень зберігається як байт (8 біт). Людське око не надто чутливе до незначних змін у цих значеннях кольору, тому ми можемо безпечно змінювати найменш значущі біти (LSB), не змінюючи вигляд зображення.

Ця програма:

  1. Приховує повідомлення в цих LSB червоного каналу BMP файлу.
  2. Шифрує повідомлення за допомогою ключа для додаткової безпеки.
  3. Витягує і дешифрує повідомлення, коли ви хочете його отримати.

Звучить круто, чи не так? Тепер давайте подивимося, як це все працює "під капотом".

Розбір коду

Налаштування

Спочатку нам потрібні деякі базові налаштування:

#include   
#include   
#include   
#include   

using namespace std;  

const int HEADER_SIZE = 54;   
const int BITS_PER_BYTE = 8;   
const int CHANNELS = 3;

Тут я включив бібліотеки для роботи з файлами (fstream) та управління рядками (string і vector). Константи, як от HEADER_SIZE, визначають важливі моменти. Заголовок BMP займає перші 54 байти файлу, тому ми їх залишаємо незмінними.

Кодування повідомлення

Ось де відбувається магія:

void encode(const string& inPath, const string& message, const string& outPath) {  
 ifstream input(inPath, ios::binary);  
 ofstream output(outPath, ios::binary);  

 if (!input || !output) {  
 cerr << "Error: Cannot open files." << endl;  
 exit(1);  
 }  

 // Копіюємо заголовок без змін  
 vector header(HEADER_SIZE);  
 input.read(header.data(), HEADER_SIZE);  
 output.write(header.data(), HEADER_SIZE);  

 // Кодуємо довжину повідомлення в перших 32 пікселях  
 size_t len = message.length();  
 for (int i = 0; i < 32; i++) {  
 char pixel[CHANNELS];  
 input.read(pixel, CHANNELS);  
 pixel[0] = (pixel[0] & 0xFE) | ((len >> i) & 1);  
 output.write(pixel, CHANNELS);  
 }  

 // Кодуємо саме повідомлення  
 size_t pos = 0;  
 int bit = 0;  
 while (pos < len) {  
 char pixel[CHANNELS];  
 input.read(pixel, CHANNELS);  
 pixel[0] = (pixel[0] & 0xFE) | ((message[pos] >> bit) & 1);  
 bit++;  
 if (bit == BITS_PER_BYTE) {  
 bit = 0;  
 pos++;  
 }  
 output.write(pixel, CHANNELS);  
 }  

 // Копіюємо решту даних зображення  
 char buffer[CHANNELS];  
 while (input.read(buffer, CHANNELS)) {  
 output.write(buffer, CHANNELS);  
 }  
}

Ось що відбувається:

  1. Обробка файлів: Ми відкриваємо вхідний BMP файл (оригінальне зображення) і вихідний BMP файл (зображення з прихованим повідомленням).
  2. Збереження заголовка: Перші 54 байти файлу BMP — це заголовок, який ми копіюємо без змін, щоб зберегти формат зображення.
  3. Кодування довжини повідомлення: Перші 32 пікселі зберігають довжину повідомлення. Це вказує програмі, скільки даних потрібно буде декодувати пізніше.
  4. Кодування самого повідомлення: Саме повідомлення розбивається на біти і зберігається в LSB червоного каналу наступних пікселів.
  5. ...

Цей переклад намагається зберегти точність і натуральність української мови при перекладі технічного тексту.
Остаточний штрих: Решта даних зображення копіюється без змін.

Декодування повідомлення

Тепер давайте розвернемо процес:

string decode(const string& path) {  
 ifstream input(path, ios::binary);  
 if (!input) {  
 cerr << "Error: Cannot open file." << endl;  
 exit(1);  
 }  

 input.seekg(HEADER_SIZE); // Пропускаємо заголовок  

 // Читаємо довжину повідомлення з перших 32 пікселів  
 size_t len = 0;  
 for (int i = 0; i < 32; i++) {  
 char pixel[CHANNELS];  
 input.read(pixel, CHANNELS);  
 len |= ((pixel[0] & 1) << i);  
 }  

 // Декодуємо повідомлення  
 string message;  
 message.reserve(len);  

 size_t pos = 0;  
 char byte = 0;  
 int bit = 0;  

 while (pos < len) {  
 char pixel[CHANNELS];  
 input.read(pixel, CHANNELS);  
 byte |= ((pixel[0] & 1) << bit);  
 bit++;  
 if (bit == BITS_PER_BYTE) {  
 message.push_back(byte);  
 byte = 0;  
 bit = 0;  
 pos++;  
 }  
 }  

 return message;  
}

Ця функція пропускає заголовок, читає довжину повідомлення і відновлює приховане повідомлення біт за бітом.

Додавання шифрування

Для підвищення безпеки я додав шифрування на основі XOR.

string hehee(const string& input, const string& key) {  
 string output = input;  
 size_t keyLen = key.length();  
 for (size_t i = 0; i < input.length(); i++) {  
 output[i] ^= key[i % keyLen];  
 }  
 return output;  
}

Цей простий шифр змінює біти повідомлення за допомогою наданого користувачем ключа. Він легкий і простий у реалізації, що робить його чудовим доповненням до цього інструменту.

Об'єднання всього

Основна функція об'єднує все:

int main() {  
 cout << "Welcome to BMP Steganography Tool!" << endl;  
 cout << "1. Encode a message\n2. Decode a message\nChoose an option: ";  
 // парадоксально, правда?  
 int choice;  
 cin >> choice;  
 cin.ignore();  

 if (choice == 1) {  
 string inPath, message, outPath, key;  
 cout << "Input BMP path: ";  
 getline(cin, inPath);  
 cout << "Message: ";  
 getline(cin, message);  
 cout << "Encryption key: ";  
 getline(cin, key);  
 cout << "Output BMP path: ";  
 getline(cin, outPath);  

 string encryptedMessage = hehee(message, key);  
 encode(inPath, encryptedMessage, outPath);  
 cout << "Message encoded successfully!" << endl;  
 } else if (choice == 2) {  
 string path, key;  
 cout << "BMP path: ";  
 getline(cin, path);  
 cout << "Decryption key: ";  
 getline(cin, key);  

 string encryptedMessage = decode(path);  
 string decryptedMessage = hehee(encryptedMessage, key);  
 cout << "Decoded Message: " << decryptedMessage << endl;  
 }  

 return 0;  
}

Меню дозволяє користувачам вибирати між кодуванням та декодуванням. Воно також гарантує, що повідомлення буде збережено в безпеці за допомогою ключа.

Підсумок

Цей проект — чудовий спосіб зануритися в стеґанографію, маніпуляції з файлами та базову криптографію. Він простий, але ефективний і дає вам практичне розуміння того, як цифрові дані можна приховати та захистити.

Експериментуйте з кодом, додавайте свої корективи або розширюйте його для підтримки інших форматів файлів. Якщо вам сподобався цей проект або у вас є пропозиції, дайте знати!

Щасливого кодування!

Ось посилання на репозиторій GitHub!

GitHub - BerryBlaast/Simple-Stegnography-Tool-in-C-

Співпрацюйте у розробці Simple-Stegnography-Tool-in-C- на GitHub.

Перекладено з: Simple Stegnography Tool in C++

Leave a Reply

Your email address will not be published. Required fields are marked *