D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Это чисто авторская статья и код. Думаю в криптерах пригодится, кто понимает назначение.
Коротко берем одну фотку и зашиваем в нее текст, при расшифровке получаем зайца (текст). В тексте может тот же шеллкод или другие данные.
Так как EasyBMP пришлось ручками допилить, прикреплю код в архиве. Там есть cmake.
Представьте, что изображение - это огромная книга, каждая страница которой состоит из миллионов букв. А текст, который нужно зашифровать - это секретное послание, которое мы хотим спрятать в этой книге. Процесс шифрования можно представить как тайного писаря, который умело вплетает буквы послания в текст книги, заменяя некоторые символы на свои зашифрованные версии.
В данном коде мы видим три основных компонента:
1. Стратегия шифрования (EncryptionStrategy): Это абстрактный класс, определяющий методы для шифрования и расшифровки. В нашем случае используется конкретная реализация LSBEncryptionStrategy, которая использует метод LSB (Least Significant Bit) для шифрования.
2. Контекст шифрования (EncryptionContext): Это класс, который управляет процессом шифрования, принимая стратегию шифрования и данные для шифрования/расшифровки.
3. Вспомогательные функции: Такие как BitToByte и ByteToBit, которые помогают преобразовывать биты в байты и наоборот, необходимые для процесса шифрования.
Давайте проследим, как наш тайный писарь шифрует текст в изображении:
1. Сначала он проверяет, не был ли текст уже зашифрован в этом изображении (IsEncrypted). Если да, то процесс прерывается.
2. Затем писарь помечает первый пиксель изображения специальной меткой (EmbedEncryptionMarker), чтобы указать, что изображение зашифровано.
3. После этого он записывает размер текста в первые несколько пикселей (WriteCountText), чтобы при расшифровке знать, сколько символов нужно извлечь.
4. Далее идет самый интересный процесс - EmbedTextInImage. Здесь писарь берет каждый байт текста и преобразует его в биты (0 и 1). Затем он берет пиксели изображения и заменяет несколько младших бит цветовых компонентов (красный, зеленый, синий) на биты из текста. Это позволяет почти незаметно вплести текст в изображение.
5. Наконец, зашифрованное изображение сохраняется (SaveEncryptedImage).
Для расшифровки текста из изображения наш писарь выполняет обратный процесс:
1. Сначала он проверяет, было ли изображение зашифровано (IsEncrypted).
2. Затем он извлекает размер зашифрованного текста из первых нескольких пикселей (ReadCountText).
3. После этого он проходит по всем пикселям изображения и извлекает младшие биты цветовых компонентов, формируя из них байты расшифрованного текста.
4. Наконец, расшифрованный текст записывается в файл.
Вот так, шаг за шагом, наш тайный писарь умело манипулирует пикселями изображения, превращая его в хранилище для секретных посланий. А мы, читатели, теперь можем лучше понять этот процесс благодаря метафорам и визуализации.
Сам код
C++: Скопировать в буфер обмена
Коротко берем одну фотку и зашиваем в нее текст, при расшифровке получаем зайца (текст). В тексте может тот же шеллкод или другие данные.
Так как EasyBMP пришлось ручками допилить, прикреплю код в архиве. Там есть cmake.
Шифрование текста в изображении: понятное объяснение
Представьте, что изображение - это огромная книга, каждая страница которой состоит из миллионов букв. А текст, который нужно зашифровать - это секретное послание, которое мы хотим спрятать в этой книге. Процесс шифрования можно представить как тайного писаря, который умело вплетает буквы послания в текст книги, заменяя некоторые символы на свои зашифрованные версии.
Основные компоненты
В данном коде мы видим три основных компонента:
1. Стратегия шифрования (EncryptionStrategy): Это абстрактный класс, определяющий методы для шифрования и расшифровки. В нашем случае используется конкретная реализация LSBEncryptionStrategy, которая использует метод LSB (Least Significant Bit) для шифрования.
2. Контекст шифрования (EncryptionContext): Это класс, который управляет процессом шифрования, принимая стратегию шифрования и данные для шифрования/расшифровки.
3. Вспомогательные функции: Такие как BitToByte и ByteToBit, которые помогают преобразовывать биты в байты и наоборот, необходимые для процесса шифрования.
Процесс шифрования
Давайте проследим, как наш тайный писарь шифрует текст в изображении:
1. Сначала он проверяет, не был ли текст уже зашифрован в этом изображении (IsEncrypted). Если да, то процесс прерывается.
2. Затем писарь помечает первый пиксель изображения специальной меткой (EmbedEncryptionMarker), чтобы указать, что изображение зашифровано.
3. После этого он записывает размер текста в первые несколько пикселей (WriteCountText), чтобы при расшифровке знать, сколько символов нужно извлечь.
4. Далее идет самый интересный процесс - EmbedTextInImage. Здесь писарь берет каждый байт текста и преобразует его в биты (0 и 1). Затем он берет пиксели изображения и заменяет несколько младших бит цветовых компонентов (красный, зеленый, синий) на биты из текста. Это позволяет почти незаметно вплести текст в изображение.
5. Наконец, зашифрованное изображение сохраняется (SaveEncryptedImage).
Процесс расшифровки
Для расшифровки текста из изображения наш писарь выполняет обратный процесс:
1. Сначала он проверяет, было ли изображение зашифровано (IsEncrypted).
2. Затем он извлекает размер зашифрованного текста из первых нескольких пикселей (ReadCountText).
3. После этого он проходит по всем пикселям изображения и извлекает младшие биты цветовых компонентов, формируя из них байты расшифрованного текста.
4. Наконец, расшифрованный текст записывается в файл.
Вот так, шаг за шагом, наш тайный писарь умело манипулирует пикселями изображения, превращая его в хранилище для секретных посланий. А мы, читатели, теперь можем лучше понять этот процесс благодаря метафорам и визуализации.
Сам код
C++: Скопировать в буфер обмена
Код:
#include "../EasyBMP.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <vector>
// Constants
const int EncryptionPercentSize = 1;
const int EncryptionTextSize = 3;
const int EncryptionTextMaxSize = 1024 * 50; // 50 KB
ebmpBYTE BitToByte(const std::vector<bool>& src);
std::vector<bool> ByteToBit(ebmpBYTE src);
class EncryptionStrategy
{
public:
virtual void Encrypt(BMP& src, const std::string& fileText) = 0;
virtual void Decrypt(BMP& src) = 0;
};
class LSBEncryptionStrategy : public EncryptionStrategy
{
public:
void Encrypt(BMP& src, const std::string& fileText) override;
void Decrypt(BMP& src) override;
private:
bool IsEncrypted(BMP& src);
void WriteCountText(int count, BMP& src);
int ReadCountText(BMP& src);
std::vector<ebmpBYTE> ReadTextFile(const std::string& fileText);
bool ValidateTextSize(int countText, BMP& src);
void EmbedEncryptionMarker(BMP& src);
RGBApixel EmbedBitsInColor(const RGBApixel& color, const std::vector<bool>& bits);
void EmbedTextInImage(BMP& src, const std::vector<ebmpBYTE>& bList);
void SaveEncryptedImage(BMP& src);
};
class EncryptionContext
{
public:
void SetEncryptionStrategy(EncryptionStrategy* strategy)
{
m_strategy = strategy;
}
void Encrypt(BMP& src, const std::string& fileText)
{
m_strategy->Encrypt(src, fileText);
}
void Decrypt(BMP& src)
{
m_strategy->Decrypt(src);
}
private:
EncryptionStrategy* m_strategy;
};
ebmpBYTE BitToByte(const std::vector<bool>& src)
{
ebmpBYTE num = 0;
for (int i = 0; i < src.size(); i++)
{
if (src[i])
{
num |= 1 << i;
}
}
return num;
}
std::vector<bool> ByteToBit(ebmpBYTE src)
{
std::vector<bool> bitArray(8);
for (int i = 0; i < 8; i++)
{
bitArray[i] = (src >> i) & 1;
}
return bitArray;
}
bool LSBEncryptionStrategy::IsEncrypted(BMP& src)
{
RGBApixel color = src.GetPixel(0, 0);
std::vector<bool> colorArray = ByteToBit(color.Red);
std::vector<bool> messageArray = ByteToBit(color.Red);
messageArray[0] = colorArray[0];
messageArray[1] = colorArray[1];
colorArray = ByteToBit(color.Green);
messageArray[2] = colorArray[0];
messageArray[3] = colorArray[1];
messageArray[4] = colorArray[2];
colorArray = ByteToBit(color.Blue);
messageArray[5] = colorArray[0];
messageArray[6] = colorArray[1];
messageArray[7] = colorArray[2];
ebmpBYTE rez[1];
rez[0] = BitToByte(messageArray);
std::string m(reinterpret_cast<char*>(rez), 1);
return m == "/";
}
void LSBEncryptionStrategy::WriteCountText(int count, BMP& src)
{
std::vector<ebmpBYTE> countBytes;
for (int i = 0; i < EncryptionTextSize + 1; i++)
{
countBytes.push_back(static_cast<ebmpBYTE>((count >> (i * 8)) & 0xFF));
}
int bytesPerPixel = 3;
int requiredPixels = (countBytes.size() + bytesPerPixel - 1) / bytesPerPixel;
for (int i = 0; i < requiredPixels && i < src.TellHeight() - 1; i++)
{
int offset = i * bytesPerPixel;
int remainingBytes = countBytes.size() - offset;
int bytesToWrite = std::min(bytesPerPixel, remainingBytes);
ebmpBYTE pixelBytes[3] = { 0 };
for (int j = 0; j < bytesToWrite; j++)
{
pixelBytes[j] = countBytes[offset + j];
}
RGBApixel pixelColor(pixelBytes[0], pixelBytes[1], pixelBytes[2]);
src.SetPixel(0, i + 1, pixelColor);
}
}
int LSBEncryptionStrategy::ReadCountText(BMP& src)
{
std::vector<ebmpBYTE> countBytes;
int bytesPerPixel = 3;
for (int i = 1; i <= EncryptionTextSize; i++)
{
RGBApixel pixelColor = src.GetPixel(0, i);
countBytes.push_back(pixelColor.Red);
countBytes.push_back(pixelColor.Green);
countBytes.push_back(pixelColor.Blue);
}
int count = 0;
for (int i = 0; i < EncryptionTextSize; i++)
{
count |= static_cast<int>(countBytes[i]) << (i * 8);
}
return count;
}
void LSBEncryptionStrategy::Encrypt(BMP& src, const std::string& fileText)
{
std::vector<ebmpBYTE> bList = ReadTextFile(fileText);
int countText = bList.size();
if (!ValidateTextSize(countText, src))
{
return;
}
if (IsEncrypted(src))
{
std::cout << "The file is already encrypted." << std::endl;
return;
}
EmbedEncryptionMarker(src);
WriteCountText(countText, src);
EmbedTextInImage(src, bList);
SaveEncryptedImage(src);
}
std::vector<ebmpBYTE> LSBEncryptionStrategy::ReadTextFile(const std::string& fileText)
{
std::ifstream rText(fileText, std::ios::binary);
return std::vector<ebmpBYTE>((std::istreambuf_iterator<char>(rText)),
std::istreambuf_iterator<char>());
}
bool LSBEncryptionStrategy::ValidateTextSize(int countText, BMP& src)
{
if (countText > EncryptionTextMaxSize - EncryptionPercentSize - EncryptionTextSize)
{
std::cout << "The text size exceeds the maximum allowed size for this algorithm. Please reduce the size." << std::endl;
return false;
}
if (countText * 8 > (src.TellWidth() - EncryptionTextSize - 1) * src.TellHeight())
{
std::cout << "The selected image is too small to accommodate the selected text." << std::endl;
return false;
}
return true;
}
void LSBEncryptionStrategy::EmbedEncryptionMarker(BMP& src)
{
ebmpBYTE symbol[1] = { '/' };
std::vector<bool> arrBeginSymbol = ByteToBit(symbol[0]);
RGBApixel curColor = src.GetPixel(0, 0);
RGBApixel nColor = EmbedBitsInColor(curColor, arrBeginSymbol);
src.SetPixel(0, 0, nColor);
}
RGBApixel LSBEncryptionStrategy::EmbedBitsInColor(const RGBApixel& color, const std::vector<bool>& bits)
{
std::vector<bool> tempArray = ByteToBit(color.Red);
tempArray[0] = bits[0];
tempArray[1] = bits[1];
ebmpBYTE nR = BitToByte(tempArray);
tempArray = ByteToBit(color.Green);
tempArray[0] = bits[2];
tempArray[1] = bits[3];
tempArray[2] = bits[4];
ebmpBYTE nG = BitToByte(tempArray);
tempArray = ByteToBit(color.Blue);
tempArray[0] = bits[5];
tempArray[1] = bits[6];
tempArray[2] = bits[7];
ebmpBYTE nB = BitToByte(tempArray);
return RGBApixel(nR, nG, nB);
}
void LSBEncryptionStrategy::EmbedTextInImage(BMP& src, const std::vector<ebmpBYTE>& bList)
{
int index = 0;
for (int i = EncryptionTextSize + 1; i < src.TellWidth() && index < bList.size(); i++)
{
for (int j = 0; j < src.TellHeight() && index < bList.size(); j++)
{
RGBApixel pixelColor = src.GetPixel(i, j);
std::vector<bool> messageArray = ByteToBit(bList[index]);
RGBApixel newColor = EmbedBitsInColor(pixelColor, messageArray);
src.SetPixel(i, j, newColor);
index++;
}
}
}
void LSBEncryptionStrategy::SaveEncryptedImage(BMP& src)
{
std::string encryptedFilename = "C:\\Users\\WORKER\\Downloads\\Wallpaper1_with_text.bmp";
src.WriteToFile(encryptedFilename.c_str());
}
void LSBEncryptionStrategy::Decrypt(BMP& src)
{
if (!IsEncrypted(src))
{
std::cout << "The file does not contain encrypted information." << std::endl;
return;
}
int countSymbol = ReadCountText(src);
std::vector<ebmpBYTE> message(countSymbol);
int index = 0;
bool st = false;
for (int i = EncryptionTextSize + 1; i < src.TellWidth(); i++)
{
for (int j = 0; j < src.TellHeight(); j++)
{
RGBApixel pixelColor = src.GetPixel(i, j);
if (index == countSymbol)
{
st = true;
break;
}
std::vector<bool> colorArray = ByteToBit(pixelColor.Red);
std::vector<bool> messageArray = ByteToBit(pixelColor.Red);
messageArray[0] = colorArray[0];
messageArray[1] = colorArray[1];
colorArray = ByteToBit(pixelColor.Green);
messageArray[2] = colorArray[0];
messageArray[3] = colorArray[1];
messageArray[4] = colorArray[2];
colorArray = ByteToBit(pixelColor.Blue);
messageArray[5] = colorArray[0];
messageArray[6] = colorArray[1];
messageArray[7] = colorArray[2];
message[index] = BitToByte(messageArray);
index++;
}
if (st)
{
break;
}
}
std::string strMessage(message.begin(), message.end());
std::string sFileText = "C:\\Users\\WORKER\\Downloads\\te2st.txt";
std::ofstream wFile(sFileText, std::ios::binary);
wFile << strMessage;
std::cout << "The text has been written to the file." << std::endl;
}
int main()
{
std::string filePic = "C:\\Users\\WORKER\\Downloads\\Wallpaper1_src.bmp";
std::string fileText = "C:\\Users\\WORKER\\Downloads\\test.txt";
BMP bPic;
bPic.ReadFromFile(filePic.c_str());
EncryptionContext context{};
LSBEncryptionStrategy strategy;
context.SetEncryptionStrategy(&strategy);
context.Encrypt(bPic, fileText);
context.Decrypt(bPic);
return 0;
}