Use steganography to hide Unicode message bytes in an image in C#


[hide Unicode]

The post Use steganography to hide Unicode messages in an image in C# stores the bits in a message in the least significant bits of an image’s alpha, red, green, and blue color components.

The post Use steganography to hide one picture inside another in C# lets you experiment with using different numbers of bits to store different images. For example, you can use two bits per color component and still get a pretty good result.

This example combines those two examples to hide Unicode more efficiently. It uses the technique in the first post but using two bits in each color component. This is sort of a lucky combination because two bits for each of the alpha, red, green, and blue color components lets you store a byte of Unicode data in each pixel of the main image.

The code works the same as the earlier example except at the lowest level where it needs to store and retrieve bits. The following code shows the new EncodeBits method.

// Encode four bits. Values pos1 through pos4 give the
// positions from the left of the bits in b to encode.
// Value dest_bit gives the bit in the pixel that should
// hold the values. It should be 0 or 1.
private void EncodeBits(ref int x, ref int y, Bitmap bm,
    byte b, int pos1, int pos2, int pos3, int pos4, int dest_bit)
{
    // Get the pixel's color.
    Color color = bm.GetPixel(x, y);

    // A mask to set the bit we are setting.
    byte only_1 = (byte)(0x01 << dest_bit);

    // A mask to clear all bits except the bit we're setting.
    byte clear_1 = (byte)(only_1 ^ 0xFF);

    // Add the bits to the color components.
    byte alpha, red, green, blue;
    pos1 -= dest_bit;
    byte bit1 = (byte)((b >> pos1) & only_1);
    alpha = (byte)((color.A & clear_1) | bit1);

    pos2 -= dest_bit;
    byte bit2 = (byte)((b >> pos2) & only_1);
    red = (byte)((color.R & clear_1) | bit2);

    pos3 -= dest_bit;
    byte bit3 = (byte)((b >> pos3) & only_1);
    green = (byte)((color.G & clear_1) | bit3);

    pos4 -= dest_bit;
    byte bit4 = (byte)((b >> pos4) & only_1);
    blue = (byte)((color.B & clear_1) | bit4);

    // Update the pixel.
    bm.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue));
    UsedBitmap.SetPixel(x, y, Color.Red);

    // Move to the next pixel.
    if (dest_bit == 1) NextRowCol(ref x, ref y, bm);
}

This method first gets the pixel’s color. It then creates a mask that contains a 1 in the bit that we are setting. If dest_bit is 0, then the mask is 00000001. If dest_bit is 1, then the mask is 00000010.

The method then finds the inverse of that mask, either 11111110 or 11111101.

The code then saves the data bits in the pixel’s color components. For the alpha component, it first subtracts dest_bit from the position of the first data bit. It then shifts the data value by that number of positions. The result is that the data bit is shifted so it lies in position dest_bit.

For example, suppose we’re encoding the least significant bit in the data byte so pos1 is 0. Also suppose dest_bit is 1 so we’re trying to encode the values in the color components’ second bits.

Let the data byte have the value xxxxxxxB. The code subtracts 1 from pos1 to get 0 – 1 = -1. It then shifts the data byte -1 bits right, which is equivalent to 1 bit left, to get xxxxxxxB >> -1 = xxxxxxxB << 1 = xxxxxxB0. Now the data bit B is in the second position as desired. (That’s where we want it because dest_bit is 1.)

Next the code uses & to combine that value with the mask value only_1, which has value 00000010. The new result is 000000B0.

The code then combines the pixel’s alpha value (call it xxxxxxxx) with the clear_1 mask, which has value 00000010. That gives xxxxxx0x.

Finally the code uses | to combine that value xxxxxx0x with the shifted data value 000000B0. The result is xxxxxxBx. So the data bit B has been placed in bit 1 as desired.

The code that saves bits in the red, green, and blue color components works similarly.

After it sets the correct data bits in all four color components, the method updates the pixel’s colors.

Then if dest_bit is 1, the code increments the pixel’s X and Y position so the program stores the next data byte in the next pixel.

The DecodeBits method shown in the following code reverses the process.

// Decode four bits. Values pos1, pos2, and pos3 give the
// positions from the left of the bits in b to decode.
// Value dest_bit gives the bit in the pixel that should
// hold the values. It should be 0 or 1.
private void DecodeBits(ref int x, ref int y, Bitmap bm,
    ref byte b, int pos1, int pos2, int pos3, int pos4,
    int dest_bit)
{
    // Get the pixel's color.
    Color color = bm.GetPixel(x, y);

    // A mask to get the bit we're using.
    byte only_1 = (byte)(0x01 << dest_bit);

    // Get the encoded bits from the color components.
    byte bit1 = (byte)(color.A & only_1);
    pos1 -= dest_bit;
    b |= (byte)(bit1 << pos1);

    byte bit2 = (byte)(color.R & only_1);
    pos2 -= dest_bit;
    b |= (byte)(bit2 << pos2);

    byte bit3 = (byte)(color.G & only_1);
    pos3 -= dest_bit;
    b |= (byte)(bit3 << pos3);

    byte bit4 = (byte)(color.B & only_1);
    pos4 -= dest_bit;
    b |= (byte)(bit4 << pos4);

    // Move to the next pixel.
    if (dest_bit == 1) NextRowCol(ref x, ref y, bm);
}

The result of all this is that the program uses half as many pixels to store data as the previous version while still producing a high-quality visible image. Equivalently this means you can store a message twice as large as you could in the previous example.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in algorithms, cryptography, graphics, image processing, mathematics and tagged , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

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