Home


          Bitmap Steganography

INSTRUCTIONS

Bitmap Steganography Utility Program - allows for the insertion of binary data into a standard 24-bit uncompressed bitmap image on a bit level such that it is not apparent nor detectable that within the image is additional information. Imagine that someone has one bit of information and places it in the LSB (least significant bit) of a random byte within a 5MB bitmap image. Which byte is it? And was the original bitmap image random byte's LSB a one or a zero? Has it changed? I can't tell by looking at the image. For example, red (255) looks pretty much the same as red (254.)

Bitmap Steganography Utility Program is stand-alone software. That is, it makes no entries in your Registry nor adds or changes any .sys, .inf, .cfg, etc. files. Simply copy it to your hard drive and run it. To uninstall simply delete it. Save and back it up. Keep two external copies. You may well be glad you did in the future.

There are three required inputs for embedding a source file into a bitmap image file: the original source file, an appropriate bitmap image, and a file filled with random binary numbers. You can get a random binary numbers file by downloading BulletProof Random Number Generator at KingKonglomerate.com and running that software and generating a random binary numbers file. Here are sample contents from such a file: 187 152 26 220 62 209... An appropriate bitmap image file is a standard uncompressed 24-bit bitmap that you'd make with Windows Paint or Photoshop. (There is no alpha channel.)

Let's say your original source file is, Lovely_Jane.jpg (39.2KB), and your random binary numbers file is called, RandomBinary (17,719KB), and your bitmap image is, SunnyApples.bmp (6,751KB.) Run Stega_BP_v32.exe. Select the Embed radio button. Uncheck the check boxes on the right. Click Start. In the first Open dialog box input your source file, Lovely_Jane.jpg. In the second Open dialog box input your cover bitmap image, SunnyApples.bmp. In the third Open dialog box input your random binary numbers file, RandomBinary. In the Save as bitmap file dialog box input, Embed_LovelyJanejpg_SunnyApples.bmp. The program immediately starts executing. On my compuuter it took about 0:26 min:secs. Elapsed time appears when the process is completed. (A 107KB source file took about 3:00 min:secs.) When done, click Close.

Here is how it works: each byte of the source file is split up into eight bits. So Lovely_Jane.jpg becomes 321,496 bits. Then the random binary numbers file is used to generate a sequence of 321,496 unique random integers from 0 - 6,911,999. (I'll explain soon.) This sequence of unique random integers is used to index the corresponding bitmap image data bytes. Since the integer sequence is random and no random integer is repeated, the order of the bitmap bytes chosen is random. Now, each source bit is XORed with the LSB of its corresponding random binary number (encryption) then the result is placed into the LSB of the randomly indexed bitmap image data byte (encryption, again.) On average, half of these bytes will be left unaltered. (More on this later.)

A bitmap is made up of three bytes per pixel: a blue byte, a green byte, and a red byte, in that order. That's 24 bits. Examining the bits of an embedded pixel would tell you nothing on their own about the pixel's original state. And by just looking at the original pixel and comparing it to the altered pixel, you cannot discern a difference.

Each bitmap image can be described by its pixel width and pixel height. Each bitmap is made up of scan lines. Each scan line has a width in bytes. The bitmap specification requires that each scanline, to keep it simple, must be evenly divisible by 4. So, if each pixel is composed of 3 bytes and there are, let's say, 1920 pixels in the width of our bitmap image, then there should be 5760 bytes in each scan line. And 5760 is evenly divisible by 4: 1440.0.

But if we have a bitmap with a width of 477 pixels at 3 bytes per pixel we'd get 1431 bytes. This is not evenly divisible by 4: 357.75. There is a remainder of 3: 4 x 357 = 1428. And 1431 - 1428= 3. So to conform to the bitmap specification, bitmap creation software will, in this case, add a zero byte to the end of each scan line. Thus, 1431 + 1 = 1432 which is evenly divisible by 4.

So, although your image is, say, 477x300 and by pixels should contain 143,100 pixels and consist of 429,300 image data bytes, the actual total image byte count for the bitmap image will be 429,600. 300 bytes have been added: 1 byte for each scan line. But each of these "padding" bytes is always a zero. So if any of them have a value of one, an astute analysis would reveal that the bitmap image had been altered.

Fortunately, the bitmap rules are known, the padding bytes are always placed at the end of each scan line, and the bitmap header provides all the other details required to precisely determine the number of scan lines, the number of bytes in each scan line, and the padding bytes added to the end of each scan line. The Bitmap Steganography Utility Program accounts for all of this. When the random integers are generated, any that would cause a bitmap byte that is a padding byte to be chosen for embedding is discarded. Only pixel image data bytes are used in the embedding process.

Here is how to extract your source file from the embedded bitmap image: Run Stega_BP_v32.exe. Select the Extract radio button. Click Start. In the first Open dialog box input the embedded bitmap image file, Embed_LovelyJanejpg_SunnyApples.bmp. In the second Open dialog box input the random binary numbers file, RandomBinary. In the Save as dialog box input, Extract_Embed_LovelyJanejpg_SunnyApples_bmp.jpg. The program immediately starts executing. On my compuuter it took about 0:24 min:secs. Elapsed time appears when the process is completed. (It took about 3:01 min:secs to extract a 107KB embedded file.) When done, click Close. Open the extracted .jpg file in your favorite picture viewer.

A twelve byte binary code is added to the end of the source file just prior to embedding. When the Extract process sees this code it knows to end the process. It is possible but extremely unlikely that a bitmap image file would already have this code as part of its binary data thus causing an early termination of the extraction process.

As you know, changing the LSB results in an indistinguishable change in the bitmap image. If you check the MSB (most significant bit) check box, the embedding process will embed the source file into the MSB of each random bitmap image data byte. You can easily see the difference between a red (255) and a red (127). You will be able to see firsthand the bitmap image data bytes that are being altered. Follow the same embed procedure above except check the MSB check box before clicking Start. When done, open the bitmap image in your favorite picture viewer. This facility is for educational purposes. You cannot extract a source file from a MSB embedded bitmap image file.

Here is how to make a 24-bit color depth solid white image using Paint.

Go to Image -> Attributes. Make width = 800 and Height = 600. Units = Pixels. Colors = Colors. Click OK.

Go to Colors-> Edit Colors. Select the White square in the bottom right corner of the Basic Colors. Click OK.

Select the Fill With Color icon in the Tool Box that looks like a bucket spilling paint. If the Tool Box is not visible, go to: View -> Tool Box. Move the bucket over the image and left-click the mouse.

Now you have your 800x600 solid white image.

To save it: go to: File -> Save. Save in: (select an appropriate directory.) File Name: SolidWhite_800x600_24. Save as Type: 24-bit Bitmap.

Right-click on SolidWhite_800x600_24.bmp and select Properties. Size: 1,440,054 bytes. Go to the Summary tab to see the .bmp statistics.

Here is proof that the Bitmap Steganography Utility Program works exactly as described up to this point.

I want to make a bitmap image file that is small enough to work with efficiently. I want a file with a short scan line width and a maximum number of padding bytes so when I embed a file into it, if the software does not work as described, it will show up right away. I choose a bitmap with a pixel width of 10 and padding of 3 to begin my search. Knowing the bitmap specification, I came up with an equation to obtain my test bitmap image specs.

Scan line width = (((pixel width) * 3) + padding bytes) and this must be evenly divisible by 4.

So I get:   Scan line width = (((10) * 3) + 3) and this must be evenly divisible by 4.  If not, I'll increase the pixel width.   Here is my table:

(10 * 3) + 3 = 33 evenly / 4 ?  no
(11 * 3) + 3 = 36 evenly / 4 ?  yes
(12 * 3) + 3 = 39 evenly / 4 ?  no
(13 * 3) + 3 = 42 evenly / 4 ?  no
(14 * 3) + 3 = 45 evenly / 4 ?  no
(15 * 3) + 3 = 48 evenly / 4 ?  yes
(16 * 3) + 3 = 51 evenly / 4 ?  no
(17 * 3) + 3 = 54 evenly / 4 ?  no
(18 * 3) + 3 = 57 evenly / 4 ?  no
(19 * 3) + 3 = 60 evenly / 4 ?  yes
(20 * 3) + 3 = 63 evenly / 4 ?  no
...

With a pixel width of 11 we get 3 padding bytes in each scan line having 36 total bytes and it is divisible by 4.   I'll use these specs.

So I'll make a solid white bitmap image (byte values:   red = green = blue = 255) with dimensions of 11x1000 to embed my source file into to see if any padding bytes get flipped from 0 to 1.   (A solid black umcompressed 24-bit bitmap image:   red = green = blue = 0.)

I figured out how to precisely determine which bitmap bytes in the bitmap image are the padding bytes but I won't bore you with the details because we are going to see these padding bytes with our own two eyes and closely examine them to see if any get flipped.   Nothing is more convincing than seeing it for yourself.

Alright.   I now have, SolidWhite_11x1000_24.bmp:   11,000 pixels = 33,000 image data bytes.   I want to embed a source file of 3300 bytes.   As I mentioned earlier, you can download BulletProof Random Number Generator at KingKonglomerate.com to generate a random binary numbers file, RandomBinary (17,719KB) that has been used to generate the random integers for this tutorial so far.   BulletProof can also be used to create our source file, RandomBinary_3300 (3300 bytes) from the RandomBinary file.

I'm running Stega_BP_v32.exe.   Here goes:

Source:   RandomBinary_3300
Bitmap image:   SolidWhite_11x1000_24.bmp
Random number file:   RandomBinary
Save bitmap as:   Embed_RandomBinary_3300_SolidWhite_11x1000_24.bmp

Elapsed embed time:   one second.

Run BulletProof_v313.exe.   From the start-up window, go to:   Utility Programs -> Additional Utility Programs -> Binary to Decimal.   Click Start.   In the Open binary file dialog box input, Embed_RandomBinary_3300_SolidWhite_11x1000_24.bmp.  In the Save as decimal character file enter, Embed_RandomBinary_3300_SolidWhite_11x1000_24_bmp.txt.

Open Embed_RandomBinary_3300_SolidWhite_11x1000_24_bmp.txt.   The bitmap image data begins at byte 54.   Each scan line ends with three padding bytes:   000.   As you visually scan through the file, you can see that in each scan line there is a very high frequency of 255 bytes being flipped to 254 but you don't see any 0 padding bytes being flipped.   Keep scanning through the file.   It doesn't take that long.

Scanning through a few hundred padding triplets and not finding a single one flipped should be enough to convince anyone when the probability of such an occurrence is taken into consideration.  Nevertheless, I continued to persevere and scanned through the entire embedded bitmap image file to the last byte (byte[36053]) and found that not a single padding byte was flipped.

You can also see that often the byte immediately before the three padding byte string and immediately afterwards is flipped.   This shows us that the random number indexed image data bytes are falling throughout the entire range of image data bytes in each and every scan line throughout the entire file.

As the source file becomes larger, more unique random integers are needed to index the bitmap image data bytes.   As the number of random integers increases, it takes longer and longer to verify that a newly generated random integer has not already been generated.   This is why the maximum source file length is 110KB = 112,640 bytes -> 8 * 112,640 bytes = 901,120 source bits.  

The maximum cover bitmap image file size is 100MB = 104,857,600 bytes.   The minimum cover bitmap image file size is 4000 bytes.   A smaller bitmap image limits the range of useable random integers thus increasing the likelihood that a newly generated random number has already been generated and the process will have to try again taking more time.

The cover bitmap image should be packed with as much varied information as possible:   lots of detail, contrast, colors, and different textures, etc.  and generally very busy.   You don't want a close-up of a large blue balloon.   You want to stay away from any image that has significant uniformities like that.   Certainly don't use a vector graphic generated bitmap image or the like.

I wanted to find out the relationship between the source file and the bitmap image file that allows for the best performance with the smallest bitmap image.   I decided to closely examine the maximum source file length and a medium source file length for this purpose.  

What I determined is that if your bitmap image file is too small, a 10,000,000 byte random binary number file may not generate enough random integers and the process will fail.   And if the bitmap image file is too big the law of diminishing returns sets in.   So there is a factor that relates the source bits to the bitmap image file size that gives us good performance and a not too large bitmap image file.   For the larger source files I'd say that factor would be 3.5 times the number of source bits and for the medium sized and smaller source files I'd say the factor would be 2.5.   Or maybe you'd like to use a factor of 3.0 for all files.   You already know that the larger the source file the longer the embed time.   You'll find that extraction is quicker than embedding.

The LSB of an image data byte from one bitmap image has no relationship to the LSB of an image data byte from a completely different bitmap image.   Likewise, there is no relationship between a bit from any byte in one source file with a bit from any byte in a completely different source file.   The uniquely random bytes chosen in one of our bitmap images cannot be determined nor can any LSB of any image data byte from any bitmap image be determined to have been flipped.   In other words, the original state of any LSB from any bitmap image data byte cannot be known.   Therefore, as long as you use a completely different bitmap image every time with a different source file every time, you can use the same RandomBinary random binary numbers file every time.   But for maximum security I recommend using a different random binary numbers file each time, as well.

Is there an optimal RandomBinary file length that will work with any bitmap image file.   If a source is 110KB = 112,640 * 8 = 901,120 source bits, you'd need to generate at least 901,120 unique random integers.   And you would also need a bitmap image containing at least about 2.6MB, using an image data byte to source bit ratio of 3 to 1.

If your RandomBinary file is truly random you can expect an 8,000,000 byte RandomBinary file to consistently generate enough random integers to successfully embed a maximum length source into a 2.6MB bitmap image all the time.   And if it can always successfully generate enough random integers for the maximum source file it can always successfully generate enough random integers to embed any source file of lesser length.   Therefore, a RandomBinary file of 8,000,000 random binary numbers should be adequate for all of your random integer generation needs with the Bitmap Steganography Utility Program.

You can output the random integers generated from your random binary numbers file that are used to index the bitmap image data bytes by checking the Output Random Numbers file check box.   The random integers file will be output with the generic name, Random_BMP_Index_Integers.txt.   Be aware that these random integers are used to index the bitmap image file starting at the first image data byte:   byte[54].

Here is how to use this file to prove that the Bitmap Steganography Utility Program operates exactly as described.   We will use the same SolidWhite_11x1000_24.bmp image file and RandomBinary random binary numbers file as before.   But create a new source file by simply opening Notepad and typing the digits 550.   Save the file as Digits_3.txt.

Run Stega_BP_v32.exe.   Check the Embed radio button.   Check the Output Random Numbers file check box.   Click Start.   Input Digits_3.txt for the source file.   Input SolidWhite_11x1000_24.bmp for the cover BMP image file.   Input RandomBinary for the random binary numbers file.   Save as Embed_3_SolidWhite_11x1000_24.bmp.   When done click Close.

Run BulletProof_v313.exe.   Go to Utility Programs->Additional Utility Programs->Binary to Decimal.   Click Start.   Input SolidWhite_11x1000_24.bmp.   Save as decimal character file SolidWhite_11x1000_24_bmp.txt.   When done click Close.

Go to Utility Programs->Additional Utility Programs->Binary to Decimal.   Click Start.   Open Embed_3_SolidWhite_11x1000_24.bmp.   Save as decimal character file Embed_3_SolidWhite_11x1000_24_bmp.txt.   When done click Close and quit BulletProof.

Open SolidWhite_11x1000_24_bmp.txt.   Make the window width just wide enough to see an entire line .   Open Embed_3_SolidWhite_11x1000_24_bmp.txt and adjust its width and place it in line and to the right of SolidWhite_11x1000_24_bmp.txt.

The first file column opened on the left, SolidWhite_11x1000_24_bmp.txt, is the binary to decimal conversion of the original bitmap image file.   The second file column to the right, Embed_3_SolidWhite_11x1000_24_bmp.txt, is the binary to decimal conversion of the original bitmap image file with the source data embedded into it.  

The first 54 bytes comprise the bitmap image header information.   So scroll down and bring byte position 54:   the fifty-fifth byte, to the top in each file.   This is where the bitmap image data bytes begin.   As you recall, each pixel is comprised of three bytes:   blue, green, and red.   Our bitmap image is 11x1000 so its width in pixels is 11 making 33 image data bytes per scan line.   Add three padding bytes and you get 36 bytes per scan line.   1000 lines at 36 bytes per line makes 36,000 bytes.   Adding the 54 header bytes makes 36,054 bytes in total for the bitmap image file, SolidWhite_11x1000_24.bmp.   Since our file is solid white, each byte in each pixel has a value of 255.  

Since there are three source bytes, there will be 24 source bits embedded into the bitmap image file.   Also remember that there is an extract termination string of 12 bytes that is appended to the end of the source bytes.   So there will be a total of 120 bits embedded into this bitmap image file.   We are only concerned with the source bits so you will only find 24 random integers.

Open Random_BMP_Index_Integers.txt.   Compare the 24 random integers with the corresponding list below.   These are the random integers that were generated from the random binary numbers file that were used to randomly index the bitmap image data bytes where the source bits were embedded.  

Each random integer designates a location where a source bit was embedded into the LSB of a random bitmap image data byte.   As a result of the Binary to Decimal conversion of bitmap image files, the locations designated by these random integers are offset from the first bitmap image data byte which is located at byte[54].   Therefore, to find a particular byte in a Binary to Decimal converted bitmap image file designated by a random integer, 54 must first be added to the random integer.   This is done in the example below.   Now, to find the first random image data byte, go down the left column of the converted text file where you'll find byte[30609].

Random_BMP_Index_Integers.txt file excerpt:

0 30555 + 54 = 30609
1 22974 + 54 = 23028
2 27208 + 54 = 27262
...

Open Digits_3.txt and compare it with the corresponding list below. The source bits for the digit character 5 come directly from the ASCII code. Therefore the first source bit for ASCII 53 is a zero. The second source bit is another zero. And the third source bit is a one.   Etc.

Digits_3.txt file expanded:

digit 5 -> ASCII 53 -> binary 0011 0101
digit 5 -> ASCII 53 -> binary 0011 0101
digit 0 -> ASCII 48 -> binary 0011 0000

Here is an excerpt from the random binary numbers file: 187 152 26 220 62 209... You can generate this random binary number file using BulletProof. The two keys are found in the BulletProof Help files in The Mother of All Tutorials - Part One. The RandomBinary file used in this Steganography tutorial is the final useable random binary number file, RandOut101.otp, just renamed here as, RandomBinary.

Now we will embed these three source bits using the first three random integers and the first three random binary numbers above .   First, we'll scroll through each file to byte[30609].   You can see that in the original bitmap image file that this byte is 255.   According to our embed rule, the first source bit:   0, is XORed with the LSB of the first random binary number:  187, which is odd so its LSB is a 1, the result comes from 0 XOR 1 = 1.   So 1 is embedded into the LSB of the bitmap image data byte[30609].   255 remains 255.

Next, we'll scroll through each file to byte[23028].   You can see that in the original bitmap image file that this byte is 255.   According to our embed rule, the second source bit:   0, is XORed with the LSB of the second random binary number:  152, which is even so its LSB is a 0, the result comes from 0 XOR 0 = 0.   So 0 is embedded into the LSB of the bitmap image data byte[23028].   255 is flipped to 254.

Lastly, we'll scroll through each file to byte[27262].   You can see that in the original bitmap image file that this byte is 255.   According to our embed rule, the third source bit:   1, is XORed with the LSB of the third random binary number:  26, which is even so its LSB is a 0, the result comes from 1 XOR 0 = 1.   So 1 is embedded into the LSB of the bitmap image data byte[27262].   255 remains 255.

You can continue checking using the remaining data in the Random_BMP_Index_Integers.txt file and the remaining source bits and the remaining random binary numbers.

Here is how the random integers are generated from the random binary numbers file. We know that our bitmap image file is 11 pixels wide so each scan line is 36 bytes long: 33 image data bytes and 3 padding bytes. There are 1000 scan lines so the bitmap image file less the 54 header bytes is 36,000 bytes long. If we are to randomly embed into any of these image data bytes we must generate random integers from 0 - 35,999. (The software will discard any generated random integer that indexes to padding bytes.)

Go to Windows Start->All Programs->Accessories->Calculator.   On Calculator Go To View->Scientific.   The first four random binary numbers as seen above are 187, 152, 26, 220.   Here are the two equations to employ when manually generating the random integers:   187 + 152*(256) + 26*(256^2) + 220*(256^3) = 3,692,730,555.

Then since we know that the bitmap image data byte range for embedding is from 0 - 35,999: 3,692,730,555 % 36,000 = 30,555. "%" is the modulo operator and is found on the Calculater to the upper right as the Mod button. Computer division results in the integer portion of the answer while dropping the remainder. The modulo operation results in the remainder portion only. This is the first random integer generated. The random integer generator uses successive 4-byte strings read from the random binary number file. You must use only the bitmap imaga data bytes' upper range in this modulo calculation, which is 36,000 in our example.

This should prove to you that the entire Bitmap Steganography Utility Program operates exactly as described.

Encryption is used to obscure data whereas steganography is intended to conceal data.   If you search on the web for steganography analysis you will find that digital steganography has significant limitations that cannot be ignored.   Generally speaking, the amount of data embedded into a bitmap image, in our case, is quite limited if one is to conceal data and avoid detection.

It has been suggested that there is a carrying capacity square root law for steganography that says the amount of secure data that can be embedded into a bitmap image is proportional to the square root of the number of available bitmap image data bytes.   The square root of a 10MB bitmap image is only about 3163.   Search the Internet for steganography detection or steganography carrying capacity, etc. for more information.

But this steganography freeware can also be used to obscure data.   Just think:   a source file XORed with a random number file (BulletProof / XOR encryption) then each resulting bit is XORed again with a random binary number's LSB (encryption, again, with this steganography implementation) then these bits are embedded into random bitmap image data bytes (encryption, again, with this steganography implementation.)

You have many tools available with the BulletProof Random Number Generator, the XOR Utility Program, and the Bitmap Steganography Utility Program.   Use your imagination and have lots of fun.  

 TOP       


Latest page update:  24 Mar '15
Page first published:  17 Jan '10