Exemplo n.º 1
0
        /// <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();
        }
Exemplo n.º 2
0
        /// <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();
        }
Exemplo n.º 3
0
        /// <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));
        }
Exemplo n.º 4
0
        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();
        }
Exemplo n.º 5
0
        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);
                }
            }
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 7
0
        /// <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());
        }
Exemplo n.º 8
0
        /// <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));
        }
Exemplo n.º 9
0
        /// <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();
        }
Exemplo n.º 10
0
        /// <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());
        }
Exemplo n.º 11
0
        /// <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();
        }
Exemplo n.º 12
0
        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);
        }
Exemplo n.º 13
0
        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);
                    }
                }
            }
        }
Exemplo n.º 14
0
        /// <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);
        }
Exemplo n.º 15
0
        /// <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);
        }
Exemplo n.º 16
0
 /// <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));
 }