/// <summary> /// Invokes the <see cref="FileManager"/> to load a stego image from a specified path to the system. /// </summary> /// <param name="path">Preferably the absolute path of a desired stego image</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="OutOfMemoryException"></exception> /// <exception cref="Exceptions.WrongPixelFormatException"></exception> /// <exception cref="FormatException"></exception> private void LoadStegoImage(string path) { // Do nothing if the file does not exist if (!File.Exists(path)) { return; } // Do nothing if the image is stored using an inappropriate format if (!_imageExtensions.Contains(Path.GetExtension(path).ToLowerInvariant())) { return; } // Generate stego image object _stegoImage = new StegoImage( _fm.ReadImageFile(path, false), Path.GetFileName(path), _fm.GetFileSizeInBytes(path) ); // Display image stegoImagePictureBox.Image = _stegoImage.Image; // Fill labels with data stegoImageNameLabel.Text = _stegoImage.Name; stegoImageSizeLabel.Text = Converter.BytesToHumanReadableString(_stegoImage.SizeInBytes); // Check GUI components CheckEverything(); }
/// <summary> /// Invokes the <see cref="FileManager"/> to load a carrier image from a specified path to the system. /// </summary> /// <param name="path">Preferably the absolute path of a desired carrier image</param> /// <param name="forceTrueColor">true if the image should be recreated in case it uses a wrong pixel format and false otherwise</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="OutOfMemoryException"></exception> /// <exception cref="Exceptions.WrongPixelFormatException">Always thrown when forceTrueColor is false but the image is not RGB-based</exception> /// <exception cref="FormatException"></exception> private void LoadCarrierImage(string path, bool forceTrueColor) { // Do nothing if the file does not exist if (!File.Exists(path)) { return; } // Do nothing if the image is stored using an inappropriate format if (!_imageExtensions.Contains(Path.GetExtension(path).ToLowerInvariant())) { return; } // Generate carrier image object _carrier = new StegoImage( _fm.ReadImageFile(path, forceTrueColor), Path.GetFileName(path), _fm.GetFileSizeInBytes(path) ); // Display image carrierImagePictureBox.Image = _carrier.Image; // Fill labels with data carrierNameLabel.Text = _carrier.Name; carrierSizeLabel.Text = Converter.BytesToHumanReadableString(_carrier.SizeInBytes); carrierCapacityLabel.Text = Converter.BytesToHumanReadableString( _embedder.CalculateCapacity(_carrier, (byte)(bppComboBox.SelectedIndex + 1))); // Check GUI components CheckEverything(); }
/// <summary> /// Calculates the hiding capacity of a given carrier /// based on the amount of specified bit planes and returns it in bytes. /// </summary> /// <param name="carrier">The carrier whose capacity should be calculated</param> /// <param name="bitPlanes">The amount of the carrier's bit planes that are allowed to be used</param> /// <exception cref="FormatException"></exception> /// <returns>The capacity in bytes</returns> public uint CalculateCapacity(StegoImage carrier, int bitPlanes) { if (bitPlanes < 0 || bitPlanes > 7) { throw new FormatException(); } uint width = (uint)carrier.Image.Width; uint height = (uint)carrier.Image.Height; // Calculate the capacity in bytes and substract 67 bytes for the name and message length // which is embedded before the actual payload return((uint)(((bitPlanes * 3 * width * height) / 8) - 67)); }
private void hideMessageButton_Click(object sender, EventArgs e) { hideMessageButton.Text = @"Hiding ..."; hideMessageButton.Enabled = false; try { // Generate stego image _stegoImage = _embedder.HideMessage( _carrier, _message, stegoPasswordTextbox.Text, bppComboBox.SelectedIndex + 1, bitPlaneFirstRadio.Checked ); // Fill labels with data stegoImageNameLabel.Text = _stegoImage.Name; stegoImageSizeLabel.Text = _defaultLabelValue; // Display image stegoImagePictureBox.Image = _stegoImage.Image; } catch (MessageTooBigException) { MessageBox.Show( @"Could not hide the message since it is too big!", @"Error!", MessageBoxButtons.OK, MessageBoxIcon.Error ); } catch (MessageNameTooBigException) { MessageBox.Show( @"Could not hide the message since its file name is too long!", @"Error!", MessageBoxButtons.OK, MessageBoxIcon.Error ); } catch (Exception ex) { MessageBox.Show( @"The sysem caught an exception:" + "\nType: " + ex.GetType().Name + "\nMessage: " + ex.Message, @"Critical error!", MessageBoxButtons.OK, MessageBoxIcon.Error ); } // Check GUI components hideMessageButton.Text = @"Hide message"; CheckEverything(); }
private void EncryptImage(string message) { OpenFileDialog openFileDialog = new OpenFileDialog(); if (openFileDialog.ShowDialog() == true) { StegoImage stegoImage = new StegoImage(openFileDialog.FileName); SaveFileDialog saveFileDialog = new SaveFileDialog(); if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { stegoImage.EmbedPayload(message).Save(saveFileDialog.FileName); } } }
private string DecryptImage() { OpenFileDialog openFileDialog = new OpenFileDialog(); if (openFileDialog.ShowDialog() == true) { StegoImage stegoImage = new StegoImage(openFileDialog.FileName); byte[] extractBytes = stegoImage.ExtractBytes().ToArray(); string unCutMessage = Encoding.Default.GetString(extractBytes); string[] splitArray = unCutMessage.Split(','); int messageStart = int.Parse(splitArray[0]); int messageLength = int.Parse(splitArray[1]); string secureText = new string(splitArray[2].Take(messageLength).ToArray()); return(messageStart + "," + messageLength + "," + secureText); } return(null); }
/// <summary> /// Collects all LSBs of a given carrier image ordered from pixel /// (0, 0) to (xMax, yMax) and from color R over G to B and returns them as string. /// </summary> /// <param name="carrier">The carrier image whose LSBs are to be taken from</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <returns></returns> private string CollectCarrierLsbs(StegoImage carrier) { StringBuilder sb = new StringBuilder(); int width = carrier.Image.Width; int height = carrier.Image.Height; // Iterate over the whole image for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var pixel = carrier.Image.GetPixel(x, y); sb.Append(GetBit(pixel.R, 0)); sb.Append(GetBit(pixel.G, 0)); sb.Append(GetBit(pixel.B, 0)); } } return(sb.ToString()); }
/// <summary> /// Rates a carrier image based on the amount of bits that have to be changed during the embedding process. /// The result is the exact amount of LSBs inside a carrier that stay the same /// during sequential embedding (without a stego password) in percent. /// </summary> /// <param name="carrier">The carrier image which is to be rated</param> /// <param name="message">The message which is to be hidden inside the carrier image</param> /// <exception cref="MessageNameTooBigException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="EncoderFallbackException"></exception> /// <returns>The suitability rating of the carrier for the specific message</returns> public float RateCarrier(StegoImage carrier, StegoMessage message) { // Get all necessary information of the carrier uint capacityInBytes = CalculateCapacity(carrier, 1); // Only use LSBs uint capacityInBits = capacityInBytes * 8; string completeMessage = GenerateMessageBitPattern(message); // Directly return 0 if the message exceeds the capacity if (completeMessage.Length > capacityInBits) { return(0.00f); } // Collect all LSBs of the carrier //string carrierBits = collectCarrierBits(carrier, 1, bitPlanesFirst); string carrierLsbs = CollectCarrierLsbs(carrier); // Calculate the Hamming distance uint hammingDistance = 0; int lsbCounter = 0; foreach (char bit in completeMessage) { // If the index of an array reaches 2^31 it needs to be resetted // This is because an array is accessible only by int values if (lsbCounter == int.MaxValue) { carrierLsbs = carrierLsbs.Substring(lsbCounter); lsbCounter = 0; } // Increase Hamming distance if message bit and carrier bit do not match if (!char.Equals(bit, carrierLsbs[lsbCounter])) { hammingDistance++; } lsbCounter++; } double rating = (double)(capacityInBits - hammingDistance) / capacityInBits; return((float)Math.Round((rating * 100), 3)); }
/// <summary> /// Removes the stego image from the system. /// </summary> private void ClearStegoImage() { // Reset stego image object _stegoImage = null; // Remove image if (stegoImagePictureBox.Image != null) { stegoImagePictureBox.Image.Dispose(); stegoImagePictureBox.Image = null; } // Remove data from labels stegoImageNameLabel.Text = _defaultLabelValue; stegoImageSizeLabel.Text = _defaultLabelValue; // Check GUI components CheckEverything(); }
/// <summary> /// Collects the bits of all specified bit planes from a given carrier image /// beginning with the least significant bit plane ordered from pixel /// (0, 0) to (xMax, yMax) and from color R over G to B and returns them as string. /// </summary> /// <param name="carrier">The carrier image whose bits are to be collected</param> /// <param name="bitPlanes">The amount of bit planes the bits are to be collected from</param> /// <param name="bitPlanesFirst">true for bit planes first-mode and false for pixels first-mode</param> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <returns>The binary pattern containing all desired bits from the carrier image</returns> private string CollectCarrierBits(StegoImage carrier, int bitPlanes, bool bitPlanesFirst) { StringBuilder sb = new StringBuilder(); int width = carrier.Image.Width; int height = carrier.Image.Height; Color pixel; if (bitPlanesFirst) { for (int currentBitPlane = 0; currentBitPlane <= bitPlanes; currentBitPlane++) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { pixel = carrier.Image.GetPixel(x, y); sb.Append(GetBit(pixel.R, currentBitPlane)); sb.Append(GetBit(pixel.G, currentBitPlane)); sb.Append(GetBit(pixel.B, currentBitPlane)); } // for } // for } // for } else { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { for (int currentBitPlane = 0; currentBitPlane < bitPlanes; currentBitPlane++) { pixel = carrier.Image.GetPixel(x, y); sb.Append(GetBit(pixel.R, currentBitPlane)); sb.Append(GetBit(pixel.G, currentBitPlane)); sb.Append(GetBit(pixel.B, currentBitPlane)); } // for } // for } // for } // else return(sb.ToString()); }
/// <summary> /// Removes the carrier image from the system. /// </summary> private void ClearCarrierImage() { // Reset carrier image object _carrier = null; // Remove image if (carrierImagePictureBox.Image != null) { carrierImagePictureBox.Image.Dispose(); carrierImagePictureBox.Image = null; } // Remove data from labels carrierNameLabel.Text = _defaultLabelValue; carrierSizeLabel.Text = _defaultLabelValue; carrierCapacityLabel.Text = _defaultLabelValue; carrierRatingLabel.Text = _defaultLabelValue; // Check GUI components CheckEverything(); }
public void EmbedBytes_should_embed_a_byte_array_into_the_image() { var path = @"images/iguana.png"; var image = new StegoImage(path); var message = "We exist without skin color," + "without nationality, without religious bias... and you call us criminals." + "You build atomic bombs, you wage wars, you murder, cheat, and lie to us" + "and try to make us believe it's for our own good, yet we're the criminals."; var resultPath = @"iguana-embedded.png"; image.EmbedPayload(message) .Save(resultPath); var imageWithMessage = new StegoImage(resultPath); var embeddedString = Encoding.Default.GetString(imageWithMessage.ExtractBytes().ToArray()); var embedded = embeddedString.Substring(0, message.Length); Assert.Equal(message, embedded); }
public void EmbeddedImages_should_work() { var message = "The probability of success is difficult to estimate; but if we never search the chance of success is zero."; var slothPath = @"images/sloth.png"; var slothEmbeddedPath = @"sloth-embedded.png"; using (var slothImage = new StegoImage(slothPath)) { slothImage.Strategy.PixelSelection = p => p.Index % 2 == 0; slothImage.EmbedPayload(Encoding.Default.GetBytes(message)); slothImage.Save(slothEmbeddedPath); } var slothBytes = File.ReadAllBytes(slothEmbeddedPath); // embed the sloth into the astronaut var astronautPath = @"images/astronaut.png"; var embeddedAstronautPath = @"astronaut-embedded.png"; using (var astronautImage = new StegoImage(astronautPath)) { astronautImage.EmbedPayload(slothBytes); // save the astronaut astronautImage.Save(embeddedAstronautPath); } var astronautBytes = File.ReadAllBytes(embeddedAstronautPath); // embed the astronaut into space var spacePath = @"images/space.png"; var spaceEmbeddedPath = @"space-embedded.png"; using (var spaceImage = new StegoImage(spacePath)) { spaceImage.EmbedPayload(astronautBytes); // save space spaceImage.Save(spaceEmbeddedPath); } // extract the astronaut using (var spaceEmbeddedImage = new StegoImage(spaceEmbeddedPath)) { var embeddedAstronautBytes = spaceEmbeddedImage.ExtractBytes() .Take(astronautBytes.Length) .ToArray(); Assert.Equal(astronautBytes, embeddedAstronautBytes); var astronautBytesPath = @"astronaut-embedded-bytes.png"; File.WriteAllBytes(astronautBytesPath, embeddedAstronautBytes); using (var astronautBytesImage = new StegoImage(astronautBytesPath)) { var embeddedSlothBytes = astronautBytesImage.ExtractBytes().Take(slothBytes.Length).ToArray(); Assert.Equal(slothBytes, embeddedSlothBytes); var slothBytesPath = @"sloth-embedded-bytes.png"; File.WriteAllBytes(slothBytesPath, embeddedSlothBytes); using (var slothBytesImage = new StegoImage(slothBytesPath)) { slothBytesImage.Strategy.PixelSelection = p => p.Index % 2 == 0; var embeddedMessage = Encoding.Default.GetString(slothBytesImage.ExtractBytes().ToArray()) .Substring(0, message.Length); Assert.Equal(message, embeddedMessage); } } } }
/// <summary> /// Hides a <see cref="StegoMessage"/> object inside a /// <see cref="StegoImage"/> object. /// </summary> /// <param name="carrierImage">The carrier image which is to be used to hide the message</param> /// <param name="message">The message which is to be hidden inside the carrier image</param> /// <param name="stegoPassword">The password which is to be used to hide the message (Randomized Hide and Seek)</param> /// <param name="bitPlanes">The amount of bit planes that are to be used to hide the message</param> /// <param name="bitPlanesFirst">true for bit planes first-mode and false for pixels first-mode</param> /// <exception cref="MessageNameTooBigException"></exception> /// <exception cref="MessageTooBigException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="FormatException"></exception> /// <exception cref="EncoderFallbackException"></exception> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="System.Reflection.TargetInvocationException"></exception> /// <exception cref="Exception"></exception> /// <returns>The stego image containing the hidden message</returns> public StegoImage HideMessage( StegoImage carrierImage, StegoMessage message, string stegoPassword, int bitPlanes, bool bitPlanesFirst) { // Check if a password is set bool passwordSet = !(stegoPassword.Equals("")); // Generate stego image (Pass by reference) StegoImage stegoImage = new StegoImage( new Bitmap( carrierImage.Image ), carrierImage.Name, carrierImage.SizeInBytes ); // Rename the stego image stegoImage.Name = "stegged_" + Path.GetFileNameWithoutExtension(stegoImage.Name) + ".png"; // Base variable declaration int carrierWidth = carrierImage.Image.Width; int carrierHeight = carrierImage.Image.Height; uint maxCarrierPixels = (uint)(carrierWidth * carrierHeight); uint pixelDistance = 1; // Get the binary string of a message object and its length string completeMessage = GenerateMessageBitPattern(message); uint completeMessageLength = (uint)completeMessage.Length; // Throw exception if the message is too big uint carrierCapacity = CalculateCapacity(carrierImage, bitPlanes); if (completeMessageLength > carrierCapacity * 8) { throw new MessageTooBigException(); } // If a stego password is specified, scramble the image and change the pixelDistance value if (passwordSet) { // Transform the password into a value defining the distance between pixels byte[] passwordBytes = Encoding.UTF8.GetBytes(stegoPassword); passwordBytes = Hasher.HashSha256(passwordBytes); pixelDistance = (uint)((ulong)BitConverter.ToInt64(passwordBytes, 0) % maxCarrierPixels); // Scramble image stegoImage.Image = ImageScrambler.ScrambleOne(stegoImage.Image); stegoImage.Image = ImageScrambler.ScrambleThree(stegoImage.Image); stegoImage.Image = ImageScrambler.ScrambleTwo(stegoImage.Image); } // Hiding variables int messageBitCounter = 0; // Counter iterating over all message bits uint currentPixel = 0; // Variable storing the currently considered pixel uint restClassCounter = 0; // Counter iterating over all rest classes byte bitPlaneSelector = 0; // Variable used to select which bit plane is used for embedding // While there is something left to hide while (messageBitCounter < completeMessageLength) { var currentPixelXValue = (int)(currentPixel % carrierWidth); // x coordinate of current pixel var currentPixelYValue = (int)(currentPixel / carrierWidth); // y coordinate of current pixel // Get current pixel var pixel = stegoImage.Image.GetPixel(currentPixelXValue, currentPixelYValue); // Pixel object used to generate the new color // Define which of the three LSBs of a pixel should be used byte color; switch (messageBitCounter % 3) { case 0: color = SetBit(pixel.R, completeMessage[messageBitCounter].ToString(), bitPlaneSelector); stegoImage.Image.SetPixel(currentPixelXValue, currentPixelYValue, Color.FromArgb(color, pixel.G, pixel.B)); break; case 1: color = SetBit(pixel.G, completeMessage[messageBitCounter].ToString(), bitPlaneSelector); stegoImage.Image.SetPixel(currentPixelXValue, currentPixelYValue, Color.FromArgb(pixel.R, color, pixel.B)); break; case 2: color = SetBit(pixel.B, completeMessage[messageBitCounter].ToString(), bitPlaneSelector); stegoImage.Image.SetPixel(currentPixelXValue, currentPixelYValue, Color.FromArgb(pixel.R, pixel.G, color)); // If the whole bit plane should be filled before a pixel should be reused if (bitPlanesFirst) { // Go to the next pixel currentPixel += pixelDistance; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxCarrierPixels) { currentPixel = ++restClassCounter; // If all rest classes are exhausted, // begin at pixel 0 again but go to the next bit plane if (restClassCounter >= pixelDistance) { currentPixel = 0; restClassCounter = 0; bitPlaneSelector++; } } // If a pixel should be used in full before the next pixel is chosen } else { // Go to the next bit plane bitPlaneSelector++; // If all allowed bits of a single pixel are used // go to the next pixel if (bitPlaneSelector >= bitPlanes) { currentPixel += pixelDistance; bitPlaneSelector = 0; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxCarrierPixels) { currentPixel = ++restClassCounter; } } // if } // else break; } // switch messageBitCounter++; } // If a password has been used, scramble back the image if (passwordSet) { stegoImage.Image = ImageScrambler.ScrambleOne(ImageScrambler.ScrambleThree(ImageScrambler.ScrambleTwo(stegoImage.Image))); } return(stegoImage); }
/// <summary> /// Extracts a <see cref="StegoMessage"/> object from a /// <see cref="StegoImage"/> object. /// </summary> /// <param name="stegoImage">The stego image which hides the message</param> /// <param name="stegoPassword">The password used to hide the message (Randomized Hide and Seek)</param> /// <param name="bitPlanes">The amount of bit planes that have been used to hide the message</param> /// <param name="bitPlanesFirst">true for bit planes first-mode and false for pixels first-mode</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="System.Reflection.TargetInvocationException"></exception> /// <exception cref="FormatException"></exception> /// <exception cref="OverflowException"></exception> /// <exception cref="DecoderFallbackException"></exception> /// <exception cref="Exception"></exception> /// <returns>The message that has been hidden inside the stego image</returns> public StegoMessage ExtractMessage(StegoImage stegoImage, string stegoPassword, int bitPlanes, bool bitPlanesFirst) { // Generate new stego image object to omit f*****g pass by reference Bitmap stegoImageCopy = new Bitmap(stegoImage.Image); // Set extraction option bool passwordSet = !(stegoPassword.Equals("")); // Base variable declaration StringBuilder messageNameBuilder = new StringBuilder(); StringBuilder payloadSizeBuilder = new StringBuilder(); StringBuilder payloadBuilder = new StringBuilder(); int stegoWidth = stegoImageCopy.Width; int stegoHeight = stegoImageCopy.Height; uint maxStegoPixels = (uint)(stegoWidth * stegoHeight); uint pixelDistance = 1; // If a stego password is specified if (passwordSet) { // Transform the password into a value defining the distance between pixels byte[] passwordBytes = Encoding.UTF8.GetBytes(stegoPassword); passwordBytes = Hasher.HashSha256(passwordBytes); pixelDistance = (uint)((ulong)BitConverter.ToInt64(passwordBytes, 0) % maxStegoPixels); // Scramble image stegoImageCopy = ImageScrambler.ScrambleOne(stegoImageCopy); stegoImageCopy = ImageScrambler.ScrambleThree(stegoImageCopy); stegoImageCopy = ImageScrambler.ScrambleTwo(stegoImageCopy); } // Variables for LSB extraction int messageBitCounter = 0; // Counter iterating over all message bits Color pixel; // Pixel object used to generate the new color int currentPixelXValue; // x coordinate of current pixel int currentPixelYValue; // y coordinate of current pixel uint currentPixel = 0; // Variable storing the currently considered pixel uint restClassCounter = 0; // Counter iterating over all rest classes byte bitPlaneSelector = 0; // Variable used to select which bit plane is used for embedding // Extract the first 512 bits which encode the message's name while (messageBitCounter < 512) { // Get current pixel currentPixelXValue = (int)currentPixel % stegoWidth; currentPixelYValue = (int)currentPixel / stegoWidth; pixel = stegoImageCopy.GetPixel(currentPixelXValue, currentPixelYValue); switch (messageBitCounter % 3) { case 0: messageNameBuilder.Append(GetBit(pixel.R, bitPlaneSelector)); break; case 1: messageNameBuilder.Append(GetBit(pixel.G, bitPlaneSelector)); break; case 2: messageNameBuilder.Append(GetBit(pixel.B, bitPlaneSelector)); // If the whole bit plane should be filled before a pixel should be reused if (bitPlanesFirst) { // Go to the next pixel currentPixel += pixelDistance; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; // If all rest classes are exhausted, // begin at pixel 0 again but go to the next bit plane if (restClassCounter >= pixelDistance) { currentPixel = 0; restClassCounter = 0; bitPlaneSelector++; } } // If a pixel should be used in full before the next pixel is chosen } else { // Go to the next bit plane bitPlaneSelector++; // If all allowed bits of a single pixel are used // go to the next pixel if (bitPlaneSelector >= bitPlanes) { currentPixel += pixelDistance; bitPlaneSelector = 0; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; } } // if } // else break; } // switch messageBitCounter++; } // Compose the message's name string messageNameString = messageNameBuilder.ToString(); string messageName = Converter.BinaryToString(messageNameString).Replace("\0", ""); // Extract the next 24 bits which encode the message's payload size while (messageBitCounter < 536) { // Get current pixel currentPixelXValue = (int)currentPixel % stegoWidth; currentPixelYValue = (int)currentPixel / stegoWidth; pixel = stegoImageCopy.GetPixel(currentPixelXValue, currentPixelYValue); switch (messageBitCounter % 3) { case 0: payloadSizeBuilder.Append(GetBit(pixel.R, bitPlaneSelector)); break; case 1: payloadSizeBuilder.Append(GetBit(pixel.G, bitPlaneSelector)); break; case 2: payloadSizeBuilder.Append(GetBit(pixel.B, bitPlaneSelector)); // If the whole bit plane should be filled before a pixel should be reused if (bitPlanesFirst) { // Go to the next pixel currentPixel += pixelDistance; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; // If all rest classes are exhausted, // begin at pixel 0 again but go to the next bit plane if (restClassCounter >= pixelDistance) { currentPixel = 0; restClassCounter = 0; bitPlaneSelector++; } } // If a pixel should be used in full before the next pixel is chosen } else { // Go to the next bit plane bitPlaneSelector++; // If all allowed bits of a single pixel are used // go to the next pixel if (bitPlaneSelector >= bitPlanes) { currentPixel += pixelDistance; bitPlaneSelector = 0; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; } } // if } // else break; } // switch messageBitCounter++; } // Compose the payloads's size string payloadSizeString = payloadSizeBuilder.ToString(); uint payloadSize = Converter.BinaryToUint(payloadSizeString); // Extract the payload while (messageBitCounter < payloadSize + 536) { // Get current pixel currentPixelXValue = (int)currentPixel % stegoWidth; currentPixelYValue = (int)currentPixel / stegoWidth; pixel = stegoImageCopy.GetPixel(currentPixelXValue, currentPixelYValue); switch (messageBitCounter % 3) { case 0: payloadBuilder.Append(GetBit(pixel.R, bitPlaneSelector)); break; case 1: payloadBuilder.Append(GetBit(pixel.G, bitPlaneSelector)); break; case 2: payloadBuilder.Append(GetBit(pixel.B, bitPlaneSelector)); // If the whole bit plane should be filled before a pixel should be reused if (bitPlanesFirst) { // Go to the next pixel currentPixel += pixelDistance; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; // If all rest classes are exhausted, // begin at pixel 0 again but go to the next bit plane if (restClassCounter >= pixelDistance) { currentPixel = 0; restClassCounter = 0; bitPlaneSelector++; } } // If a pixel should be used in full before the next pixel is chosen } else { // Go to the next bit plane bitPlaneSelector++; // If all allowed bits of a single pixel are used // go to the next pixel if (bitPlaneSelector >= bitPlanes) { currentPixel += pixelDistance; bitPlaneSelector = 0; // If the pixel exceeds the maximum amount of pixels // go to the next rest class if (currentPixel >= maxStegoPixels) { currentPixel = ++restClassCounter; } } // if } // else break; } // switch messageBitCounter++; } // Compose the message object string payloadString = payloadBuilder.ToString(); byte[] payload = payloadString.ConvertBitstringToByteArray(); StegoMessage message = new StegoMessage(messageName, payload); return(message); }
/// <summary> /// Invokes the <see cref="FileManager"/> to save a stego image to a specified path. /// </summary> /// <param name="stegoImage">The stego image object that should be written to the file system</param> /// <param name="path">Preferably the absolute path where the stego image should be written to</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="PathTooLongException"></exception> /// <exception cref="IOException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="DirectoryNotFoundException"></exception> /// <exception cref="NotSupportedException"></exception> /// <exception cref="System.Security.SecurityException"></exception> /// <exception cref="System.Runtime.InteropServices.ExternalException"></exception> private void SaveStegoImage(StegoImage stegoImage, string path) { _fm.WriteImageFile(stegoImage.Image, path); stegoImageSizeLabel.Text = Converter.BytesToHumanReadableString(_fm.GetFileSizeInBytes(path)); }