|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionNow that we have hidden data in bitmaps, MIDI tracks and .NET assemblies, you might miss one important file format. You might miss the files that can hide lots of bytes without becoming larger, and can be generated in a few seconds, so that you don't have to store the original files on your disk. It is time to add Wave Audio to the list. This article uses code from A full-duplex audio player in C# using the waveIn/waveOut APIs. The Wave File FormatHave you ever looked at a Wave file in a HEX editor? It starts like that, and continues with unreadable binary data:
Every RIFF file starts with the text "RIFF", followed by the
The next fields say that this RIFF file contains Wave data and open the format chunk:
The length of the following format chunk must be 16 for PCM files:
Now the format is being specified by a
The format chunk can be followed by some extra information. Then the interesting parts begin with the
The Hiding the MessageHiding a message in Wave samples is very similar to hiding it in the pixels of a bitmap. Again, we use a key stream to skip a number of carrier units (samples/pixels), grab one carrier unit, put one bit of the message into the lowest bit of the carrier unit, and write the changed unit to the destination stream. When the entire message has been hidden like that, we copy the rest of the carrier stream. public void Hide(Stream messageStream, Stream keyStream){
byte[] waveBuffer = new byte
Extracting the MessageAgain, we use the key stream to locate the right samples, just as we did while hiding the message. Then we read the last bit of the sample and shift it into the current byte of the message. When the byte is complete, we write it into the message stream and continue with the next one. public void Extract(Stream messageStream, Stream keyStream){
byte[] waveBuffer = new byte
Recording a WaveKeeping the original clean carriers can be dangerous. Somebody who has already got a carrier file with a secret message in it, and manages to get the original file without the hidden message, can easily compare the two files, count the distance in bytes between two non-equal samples, and quickly reconstruct the key. That is why we have to delete and destroy our clean carrier files after we've used them once, or record a wave on the fly. Thanks to Ianier Munoz' WaveInRecorder, it is no problem to record Wave data and hide the message in it before saving anything to a disk. There is no original file, so we do not need to care about one. In the main form, the user can choose between using an existing Wave file or recording a sound right then. If he wants to record a unique, not reproducible sound, he can plug in a microphone and speak/play/... whatever he likes: if(rdoSrcFile.Checked){ //use a .wav file as the carrier //do not complain later on, you have been warned sourceStream = new FileStream(txtSrcFile.Text, FileMode.Open); }else{ //record a carrier wave frmRecorder recorder = new frmRecorder(countSamplesRequired); recorder.ShowDialog(this); sourceStream = recorder.RecordedStream; }
The new sound is stored in a WaveUtility utility = new WaveUtility(sourceStream, destinationStream);
utility.Hide(messageStream, keyStream);
|
||||||||||||||||||||||