Вступ
Стеґанографія — звучить елегантно, чи не так? По суті, це мистецтво приховувати інформацію на виду. Коли-небудь замислювалися над тим, як вмонтувати секретне повідомлення в зображення? Ось саме це я і зробив за допомогою цього інструменту для BMP стеґанографії.
Ця маленька програма, яку я написав, дозволяє вам приховувати (і отримувати) текстові повідомлення у BMP зображеннях. І ні, це не магія — це наука. Змінюючи найменші, майже непомітні частини зображення, ми можемо зашифрувати повідомлення, не викликаючи підозр у когось. До того ж, для додаткової безпеки я додав шифрування на основі XOR для прихованого повідомлення.
У цьому пості я проведу вас через принципи роботи інструменту, розберу код і покажу, як ви можете використовувати його самі. Поглянемо, як це працює!
Як це працює
Ідея проста: BMP зображення зберігає дані пікселів, і кожен піксель має значення кольорів для червоного, зеленого та синього каналів. Кожне з цих значень зберігається як байт (8 біт). Людське око не надто чутливе до незначних змін у цих значеннях кольору, тому ми можемо безпечно змінювати найменш значущі біти (LSB), не змінюючи вигляд зображення.
Ця програма:
- Приховує повідомлення в цих LSB червоного каналу BMP файлу.
- Шифрує повідомлення за допомогою ключа для додаткової безпеки.
- Витягує і дешифрує повідомлення, коли ви хочете його отримати.
Звучить круто, чи не так? Тепер давайте подивимося, як це все працює "під капотом".
Розбір коду
Налаштування
Спочатку нам потрібні деякі базові налаштування:
#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);
}
}
Ось що відбувається:
- Обробка файлів: Ми відкриваємо вхідний BMP файл (оригінальне зображення) і вихідний BMP файл (зображення з прихованим повідомленням).
- Збереження заголовка: Перші 54 байти файлу BMP — це заголовок, який ми копіюємо без змін, щоб зберегти формат зображення.
- Кодування довжини повідомлення: Перші 32 пікселі зберігають довжину повідомлення. Це вказує програмі, скільки даних потрібно буде декодувати пізніше.
- Кодування самого повідомлення: Саме повідомлення розбивається на біти і зберігається в LSB червоного каналу наступних пікселів.
- ...
Цей переклад намагається зберегти точність і натуральність української мови при перекладі технічного тексту.
Остаточний штрих: Решта даних зображення копіюється без змін.
Декодування повідомлення
Тепер давайте розвернемо процес:
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++