LSB steganography

Once upon a time I wrote my first post on hub. And that post was dedicated to a very interesting problem, namely steganography. Of course, the solution proposed in that old topic cannot be called steganography in the true sense of the word. It's just a game of file formats, but a pretty interesting game nonetheless.

Today we will try to dig a little deeper and look at the LSB algorithm. If you are interested, you are welcome under cat. (Under the cut traffic: about a megabyte.)

First of all, it is necessary to make a small introduction. Everyone knows that the purpose of cryptography is to make it impossible to read secret information. Of course, cryptography has its uses, but there is another approach to protecting data. You can not encrypt the information, but pretend that we do not have it. That's what steganography is for. Wikipedia assures us that, “steganography (from the Greek στεγανοσ - hidden and the Greek γραφω - I write, literally “secret writing”) is the science of covert transmission of information by keeping the very fact of transmission secret.

Of course, no one forbids combining cryptographic and steganographic methods. Moreover, in practice they do this, but our task is to understand the basics. If you carefully study the article from Wikipedia, you can find out that the so-called steganography algorithms appear in the algorithms. container and message. A container is any piece of information that helps hide our secret message.

In our case, the container will be a picture in BMP format. First, let's look at the structure of this file. The file can be conditionally divided into 4 parts: file header, image header, palette and the image itself. For our purposes, we need to know only what is written in the title.

The first two bytes of the header are the BM signature, then the double word contains the file size in bytes, the next 4 bytes are reserved and must contain zeros, and finally, another double word contains the offset from the beginning of the file to the actual bytes of the image. In a 24-bit bmp file, each pixel is encoded with three BGR bytes.

Now we know how to get to the image, it remains to understand how we can write the information we need there. To do this, we need the LSB method. The essence of the method is as follows: we replace the least significant bits in the bytes responsible for color encoding. Suppose if the next byte of our secret message is 11001011, and the bytes in the image are ... 11101100 01001110 01111100 0101100111 ..., then the encoding will look like this. We will split the secret message byte into 4 two-bit parts: 11, 00, 10, 11, and replace the resulting fragments with the low bits of the image: …11101111 01001100 01111110 0101100111…. Such a change is generally not visible to the human eye. Moreover, many older output devices will not even be able to display such minor changes.

It is clear that you can change not only the 2 least significant bits, but any number of them. There is the following pattern: the more bits we change, the more information we can hide, and the more noise it will cause in the original image. For example, here are two images:

LSB steganography
LSB steganography

With all my desire, I have not been able to see the difference between them, but nevertheless, in the second image, using the described method, Lewis Carroll's poem "The Hunting of the Snark" is hidden. If you have read up to this point, then you are probably interested in learning about the implementation. It is quite simple, but I will immediately warn you that everything was done in Delphi. There are two reasons for this: 1. I think Delphi is a good, useful language; 2. This program was born in the process of preparing a course on the basics of machine vision, and the guys to whom I read this course still know nothing but Delphi. For those who are not familiar with the syntax, one thing needs to be clarified shl x is a bitwise left shift by x, shr x is a bitwise right shift by x.

We consider that we write the text stored in the string into the container and replace the lower two bytes:
Write code:

for i:=1 to length(str) do
    begin
      l1:=byte(str[i]) shr 6;
      l2:=byte(str[i]) shl 2; l2:=l2 shr 6;
      l3:=byte(str[i]) shl 4; l3:=l3 shr 6;
      l4:=byte(str[i]) shl 6; l4:=l4 shr 6;
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l1;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l2;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l3;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l4;
      f.WriteBuffer(tmp,1);
 
    end;

read code:

for i:=1 to MsgSize do
    begin
      f.ReadBuffer(tmp,1);
      l1:=tmp shl 6;
      f.ReadBuffer(tmp,1);
      l2:=tmp shl 6; l2:=l2 shr 2;
      f.ReadBuffer(tmp,1);
      l3:=tmp shl 6; l3:=l3 shr 4;
      f.ReadBuffer(tmp,1);
      l4:=tmp shl 6; l4:=l4 shr 6;
      str:=str+char(l1+l2+l3+l4);
    end;

Well, for the very lazy - link to the program and its source code.

Thank you.

Source: habr.com

Add a comment