Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Keeping Secrets Secret: Steganography with .NET : Page 2

Steganography is a way to protect information by hiding it "in plain sight" within other types of digital content. Steganography complements rather than replaces encryption by adding another layer of security—it's much more difficult to decrypt a message if you don't know that there is a message. See how to leverage .NET to create steganographic techniques that hide encrypted information inside common digital data files.

The Stego Library
With the basic theory out of the way, you can start to design and implement a basic .NET library that supplies a simple API for hiding a message in a 24-bit .bmp image. The class diagram in Figure 2 shows the interfaces and classes you are going to meet next in this article.

Figure 2. Stego Library Class Diagram: The stego library defines interfaces that support different types of cover and stego files. The BmpCoverFile and BmpStegoFile classes are concrete implementations that operate on 24-bit bitmapped images.
To handle both the cover and the stego file, you need two interfaces:

ICoverFileI is an abstraction of the cover and defines the CreateStegoFile method that creates the stego file for hiding a message. The method requires three parameters: the filename for the resulting (output) stego file, the message to hide, and a password that you'll need later to retrieve the hidden message.

IStegoFile is an abstraction of the stego file, and defines the HiddenMessage property that extracts a hidden message.

The BmpCoverFile and BmpStegoFile classes implement the interfaces using the LSB substitution method. The LSBHelper class contains the implemented logic. Both classes use classes from the System.IO.Stream namespace to perform file I/O operations.

After implementing that API, it's trivial to hide a message inside a .bmp file:

ICoverFile cover = new BMPCoverFile("cover.bmp"); cover.CreateStegoFile("stego.bmp","Hello","MyPwd");

Likewise, you can extract the message just as easily:

IStegoFile stego = new BMPStegoFile("stego.bmp","MyPwd"); Console.WriteLine(stego.HiddenMessage);

Because the library uses interfaces, you can extend it by implementing new classes that support different file types, such as other image file formats such as .jpg, .gif, .tiff etc., or audio/video file formats such as .wav, .mp3.avi, .mpeg, .asf, etc. For example, you might implement Mp3CoverFile and Mp3StegoFile classes that function similarly to hide a message inside an MP3 file.

The LSBHelper Class
The LSBHelper class is low-level code that operates on bits and bytes of cover and stego file. The Encode method hides an array of bytes inside data coming from a stream, and writes the result in another stream. Here's the code:

public static void Encode(Stream inStream, byte[] message, Stream outStream) { int byteRead; byte byteWrite; int i = 0; int j = 0; byte bit; while((byteRead = inStream.ReadByte()) != -1) { byteWrite = (byte) byteRead; if (i<message.Length) { // Extract the bit at the j position bit = Bit.Extract(message[i], j++); // Replace the LSB of byteWrite with "bit" Bit.Replace(ref byteWrite, 0, bit); // Every 8 bits, // process another byte of "message" if (j==8) { j=0; i++; } } outStream.WriteByte(byteWrite); } if (i<message.Length) throw new Exception ("The cover is too small to contain the " + "message to hide"); }

The Encode method uses the variable i to index the message byte-array and j to index a single bit of message[i]. The method reads a byte from the input stream, replaces the LSB with the bit at position j of message[i], and then writes the resulting byte to the output stream. Every 8 bits, the method processes the next element of the message array. After reading the entire input stream, the method checks if i is less than the message length. If true, there are still bytes to hide, but the cover is too small to contain them, so the method throws an exception.

The Bit class, used within the Encode method, contains the Replace and Extract methods that—by using bitwise operators—replace or extract a particular bit of a byte:

public static void Replace(ref byte b, int pos, byte value) { b = (byte) (value == 1 ? b | (1 << pos) : b & ~(1 << pos)); } public static byte Extract(byte b, int pos) { return (byte) ((b & (1 << pos)) >> pos); }

The LSBHelper.Decode method extracts hidden bytes from an input stream as shown below.

public static byte[] Decode(Stream stream, int length) { byte[] hidden = new byte[length]; int i = 0; int j = 0; byte bit; int byteRead; while((byteRead = stream.ReadByte()) != -1) { // Extract the LSB of byteRead bit = Bit.Extract((byte) byteRead, 0); // Replace the bit at the j position with "bit" Bit.Replace(ref hidden[i], j++, bit); // Every 8 bits process another byte of "hidden" if (j==8) {j=0; i++;} // Check bytes left if (i==length) break; } // The hidden var contains the hidden bytes return hidden; }

Decode is complementary to Encode—the method reads bytes from an input stream and composes the hidden message by extracting the LSB from every byte read. The length parameter represents the number of bytes to extract. After extracting length bytes, the method returns the hidden[] byte array.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.