📜 ⬆️ ⬇️

Steganography. Practical implementation of hiding data in BMP format using .net

Hello. In connection with a recent post about steganography, I want to talk about the practical side of the issue. The easiest way to hide data somewhere is to put it in a bmp file.

Why bmp?

BMP uses the RGB color model to represent colors, i.e. the color that a person sees is obtained by mixing the three colors Red, Green, Blue (red, green, blue), and BMP usually does not use compression, which makes it possible to hide a sufficiently large amount of information in it.

How to hide information?

Each color (pixel) is encoded in one byte (8 bits). We have three such colors (red, blue, green) for a total of 3 bytes (24 bits). To record our information and not distort the image, we will write the data in the lower bits of the image colors. Those. we take a pixel, sort it into color components and replace the low bits with bits of our message. Let me explain in the diagram:

This is 1 byte of our message:
10 101 010
')
This is the RGB of our pixel:
R: 111100 00
G: 00001 000
B: 11001,000

Replace the lower bits and get a new pixel:
R: 111100 10
G: 00001 101
B: 11001 010

This operation will not introduce distortion into the image of the human eye.

Consider a software implementation on the .net framework.

Software implementation

.net in the software implementation will help us a lot, in the System.Drawing namespace there is a wonderful Color class, which will help you to break down a pixel into an RGB color model.

Consider the function of writing data to a file:
Bitmap image = Image.FromFile( "C:\\image.bmp" );
string message = "" ;

void BmpWrite()
{
//
Color pixel;

int x = 0;

// *
byte [] B = Encoding .GetEncoding(1251).GetBytes(message + '/' );

bool f = false ;

//
for ( int i = 0; i < image.Width; i++)
{
if (f) break ;

for ( int j = 0; j < image.Height; j++)
{
//
pixel = image.GetPixel(i, j);

// ,
if (x == B.Length) { f = true ; break ; }

// (. 11001100)
Bits m = new Bits(B[x++]);

// 8
while (m.Length != 8) m.Insert(0, 0);

// RGB , 8
Bits r = new Bits(pixel.R); while (r.Length != 8) r.Insert(0, 0);
Bits g = new Bits(pixel.G); while (g.Length != 8) g.Insert(0, 0);
Bits b = new Bits(pixel.B); while (b.Length != 8) b.Insert(0, 0);

//
r[6] = m[0];
r[7] = m[1];

g[5] = m[2];
g[6] = m[3];
g[7] = m[4];

b[5] = m[5];
b[6] = m[6];
b[7] = m[7];

//
image.SetPixel(i, j, Color.FromArgb(r.Number, g.Number, b.Number));
}
}
}


* This source code was highlighted with Source Code Highlighter .


* byte [] B = Encoding. GetEncoding (1251). GetBytes (message + '/'); - in this line we have added our message with the symbol '/' - this is done so that when pulling out our message from a file, we know how long we should read the message, because we do not really know its length. Of course, this is not the most elegant option, you can use another rare special character, but it is better to indicate the length of the message in the first pixel, but I will leave this task to you.

So in a simple way we recorded our message in a bmp-file, now we will read it:
Bitmap image = Image.FromFile( "C:\\image_secret.bmp" );

void BmpRead()
{
//
Color pixel;

//
ArrayList array = new ArrayList ();

bool f = false ;

//
for ( int i = 0; i < image.Width; i++)
{
if (f) break ;

for ( int j = 0; j < image.Height; j++)
{
//
pixel = image.GetPixel(i, j);

//
Bits m = new Bits(255);

// RGB , 8
Bits r = new Bits(pixel.R); while (r.Length != 8) r.Insert(0, 0);
Bits g = new Bits(pixel.G); while (g.Length != 8) g.Insert(0, 0);
Bits b = new Bits(pixel.B); while (b.Length != 8) b.Insert(0, 0);

//
m[0] = r[6];
m[1] = r[7];

m[2] = g[5];
m[3] = g[6];
m[4] = g[7];

m[5] = b[5];
m[6] = b[6];
m[7] = b[7];

// , ,
if (m.Char == '/' ) { f = true ; break ; }

//
array.Add(m.Number);
}
}

byte [] msg = new byte [array.Count];

// , ..
for ( int i = 0; i < array.Count; i++)
msg[i] = Convert .ToByte(array[i]);

//
string message = Encoding .GetEncoding(1251).GetString(msg);
}


* This source code was highlighted with Source Code Highlighter .

* The implementation of the Bits class can be found in the attached source codes.

Data can be written and read more cleverly, and not follow directly along the pixel lines of the image. For example, you can record data strictly on the edges of the image or use a more subtle pixel traversal algorithm, which will increase the reliability of this system.

A little bit about AVI

It is worth mentioning that avi without compression is a successive bmp, so this algorithm can be adapted for AVI video. An example implementation is in the attached source codes.

The source code of the program that implements the methods described above can be found here . Thanks for attention.

Source: https://habr.com/ru/post/114875/


All Articles