using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.Drawing.Drawing2D; namespace iSpy { public partial class MainForm : Form { OpenFileDialog openfile = new OpenFileDialog(); SaveFileDialog savefile = new SaveFileDialog(); string binStr = ""; string gatherBits = ""; int red = 0; int blue = 0; int green = 0; int alpha = 0; Point startCropPoint; Point startCropPointNonRel; selectionWindow selectarea = new selectionWindow(); bool flag = false; public MainForm() { InitializeComponent(); } #region Open Base Image private void OpenOrigImageClick(object sender, EventArgs e) { openfile.Filter = "Image Files (*.png) | *.png"; if (openfile.ShowDialog() == DialogResult.OK) { Base_Image.Image = new Bitmap(openfile.FileName); Bitmap img = new Bitmap(Base_Image.Image); Base_Image.Image.Dispose(); if (img.Width > 300 || img.Height > 300) { float width = 300; float height = 300; Bitmap temp = new Bitmap(img, Convert.ToInt32(width), Convert.ToInt32(height)); Base_Image.Image = temp; Base_Image.Height = temp.Height; Base_Image.Width = temp.Width; } else { Bitmap temp = new Bitmap(img, Convert.ToInt32(img.Width), Convert.ToInt32(img.Height)); Base_Image.Image = temp; Base_Image.Height = temp.Height; Base_Image.Width = temp.Width; } } } #endregion #region Open Hidden Image private void OpenHiddenImageBtn_Click(object sender, EventArgs e) { openfile.Filter = "Image Files (*.png) | *.png"; if (openfile.ShowDialog() == DialogResult.OK) { binStr = ByteArrayToBinaryString(File.ReadAllBytes(openfile.FileName)); // save the bytes that comprise the hidden image into a binary string //string path = @"c:\Users\Public\temp\MyTest1.txt"; //File.WriteAllText(path, binStr); Image_to_Hide.Image = new Bitmap(openfile.FileName); Bitmap img = new Bitmap(Image_to_Hide.Image); Image_to_Hide.Image.Dispose(); if (img.Width > 300 || img.Height > 300) { float width = 300; float height = 300; Bitmap temp = new Bitmap(img, Convert.ToInt32(width), Convert.ToInt32(height)); Image_to_Hide.Image = temp; Image_to_Hide.Height = temp.Height; Image_to_Hide.Width = temp.Width; } else { Bitmap temp = new Bitmap(img, Convert.ToInt32(img.Width), Convert.ToInt32(img.Height)); Image_to_Hide.Image = temp; Image_to_Hide.Height = temp.Height; Image_to_Hide.Width = temp.Width; } } } #endregion #region Hiding Image // Hiding alg 1 // https://www.codeproject.com/Tips/635715/Steganography-Simple-Implementation-in-Csharp private void Manip_Pix_BtnClick(object sender, EventArgs e) { if (Base_Image == null) { MessageBox.Show("Must upload a base image!"); return; } if (Image_to_Hide == null) { MessageBox.Show("Must upload an image to hide!"); return; } Bitmap img = (Bitmap)Base_Image.Image; // store orig image in a bitmap Color currPixel; // used to hold the original image's pixels long dataWriteCtr = 0; // counter used to keep track of which bit we are currently processing char[] data = binStr.ToCharArray(); // binStr contains the entire content of long pixelElementIndex = 0; char[] dataLen = Convert.ToString(data.Length, 2).ToCharArray(); // convert the length of the data into binary to store in last 10 pixels int p = 0; long msgLenWriteCtr = 0; // used to copy over the length of the hidden message into image if (data.Length > 16777215) // Last 6 x 1 x 4 = 24 pixels equals 111111111111111111111111 { MessageBox.Show("Hidden image length too large to store!"); flag = true; return; } if (data.Length / 4 > ((img.Width * img.Height) - 6)) { MessageBox.Show("Hidden Image is too big!"); flag = true; return; } int width = img.Width; int height = img.Height; for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { currPixel = img.GetPixel(x, y); alpha = currPixel.A - currPixel.A % 2; // clear out the LSB for the alpha value red = currPixel.R - currPixel.R % 2; // clear out the LSB for the red value green = currPixel.G - currPixel.G % 2; // clear out the LSB for green blue = currPixel.B - currPixel.B % 2; // clear out the LSB for blue for (int n = 0; n < 4; n++) { if (pixelElementIndex % 8 == 0) { if (dataWriteCtr >= data.Length) { if ((pixelElementIndex - 1) % 4 < 3) { img.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); } } } // copy over the length of the hidden image into the last 6 pixels of base if (x > (width - 7) && y > (height - 2) && msgLenWriteCtr < dataLen.Length) { p = dataLen[msgLenWriteCtr++]; } // copy over the hidden image to base image's LSB else if (dataWriteCtr < data.Length) { p = data[dataWriteCtr++]; } // check which pixel element has the turn to hide a bit in its LSB // (alternates between hiding in red, green, and blue) switch (pixelElementIndex % 4) { case 0: { alpha += p % 2; // hiding a bit in the alpha val break; } case 1: { red += p % 2; break; } case 2: { green += p % 2; break; } case 3: { blue += p % 2; img.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); // set the new base image with the hidden image break; } } pixelElementIndex++; } } } if (savefile.ShowDialog() == DialogResult.OK) { savefile.Filter = "Image Files (*.png) | *.png"; img.Save(savefile.FileName); Img_in_an_Img.Image = new Bitmap(savefile.FileName); } Recover_btn.Enabled = true; } // Hiding alg 2 private void Manipulate_pixels_btnClick2(object sender, EventArgs e) { if (Base_Image.Image == null) { return; } if (Image_to_Hide.Image == null) { return; } // Counter used to keep track of what bit we are at int dataWriteCtr = 0; // The data to be written char[] data = binStr.ToCharArray(); // Length of the data int msgLenWriteCtr = 0; // Convert length of the data into binary char[] dataLen = Convert.ToString(data.Length, 2).PadLeft(24, '0').ToCharArray(); // MessageBox.Show(data.Length.ToString()); if (data.Length > 16777215) // Last 6 pixels { MessageBox.Show("Hidden image length too large to store!"); flag = true; return; } var img = (Bitmap)Base_Image.Image; if ((data.Length / 4) > (img.Width * img.Height) - 6) { MessageBox.Show("Hidden image is too big!"); flag = true; return; } red = 0; green = 0; blue = 0; alpha = 0; for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { Color currPixel = img.GetPixel(x, y); // save the base image pixel into currPixel alpha = currPixel.A; red = currPixel.R; green = currPixel.G; blue = currPixel.B; // copy over the length of the hidden img into the last 6 pixels of the base's LSBs if (x > (img.Width - 7) && y > (img.Height - 2)) { alpha = SetPixelChannel(currPixel.A, dataLen[msgLenWriteCtr++]); red = SetPixelChannel(currPixel.R, dataLen[msgLenWriteCtr++]); green = SetPixelChannel(currPixel.G, dataLen[msgLenWriteCtr++]); blue = SetPixelChannel(currPixel.B, dataLen[msgLenWriteCtr++]); } // copy the hidden image into LSB of base else if (dataWriteCtr < data.Length) { alpha = SetPixelChannel(currPixel.A, data[dataWriteCtr++]); red = SetPixelChannel(currPixel.R, data[dataWriteCtr++]); green = SetPixelChannel(currPixel.G, data[dataWriteCtr++]); blue = SetPixelChannel(currPixel.B, data[dataWriteCtr++]); } img.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); // set the new base image with the hidden image } } if (savefile.ShowDialog() == DialogResult.OK) { img.Save(savefile.FileName); Img_in_an_Img.Image = new Bitmap(savefile.FileName); } Recover_btn.Enabled = true; } private static int SetPixelChannel(byte currPixelChannel, char data) { int newPixelChannel = 0; // Base image LSB is odd if (currPixelChannel % 2 == 1) { if (data == '1') { newPixelChannel = currPixelChannel; } else { newPixelChannel = currPixelChannel - 1; } } // base image LSB is even else { if (data == '1') { newPixelChannel = currPixelChannel + 1; } else { newPixelChannel = currPixelChannel; } } return newPixelChannel; } #endregion #region Recover Image private void Recover_Image_btn_click(object sender, EventArgs e) { //if (Base_Image.Image == null) // return; //if (Image_to_Hide.Image == null) // return; Bitmap img = (Bitmap)Img_in_an_Img.Image; // img holds the base img // The length of the hidden image is stored in the last 6 pixels // last 6 pixels = (width - 6 x height - 1). Store the hidden image // length in string gatherBits for (int x = img.Width - 6; x < img.Width; x++) { int y = img.Height - 1; Color currPixel = img.GetPixel(x, y); gatherBits = SaveLastBitFromBaseImg(currPixel, gatherBits); } string path1 = @"c:\Users\Public\temp\MyTest4.txt"; File.WriteAllText(path1, gatherBits); int dataLen = Convert.ToInt32(gatherBits, 2); // Convert the string holding the length of hidden image in binary to decimal // MessageBox.Show(Convert.ToString(dataLen)); int dataCtr = 0; // used to check if we are done gathering bits from base img gatherBits = ""; // clear out gatherBits // Now, get hidden image bits stored inside base image for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { Color currPixel = img.GetPixel(x, y); gatherBits = SaveLastBitFromBaseImg(currPixel, gatherBits); dataCtr++; int pixelsWithBits = (dataLen / 4) - 1; // the number of pixels in base img hiding a bit if (dataCtr > pixelsWithBits) // we have captured all of the bits { x = img.Width; // so exit the outer for loops y = img.Height; } } } //MessageBox.Show(Convert.ToString(gatherBits.Length)); //string path = @"c:\Users\Public\temp\MyTest3.txt"; //File.WriteAllText(path, gatherBits); byte[] hiddenImage = BinaryToByteArray(gatherBits); // convert string of binary to a byte array // Create a new file, write the contents of recovered // bits to it, and ask user to save the new file if (savefile.ShowDialog() == DialogResult.OK) { File.WriteAllBytes(savefile.FileName, hiddenImage); Unhidden_Image.Image = new Bitmap(savefile.FileName); } } // we cleared out the 1's position of the A/R/G/B value so if the alpha value is // even, the hidden bit = 0 concatenate 0 onto string gatherBits // else the A/R/G/B value is odd concatenate 1 onto gatherBits // The order in which we retrieve the LSB from each pixel matters so must stay // consistent ie in the order alpha, red, green, blue. private static string SaveLastBitFromBaseImg(Color currPixel, string gatherBits) { gatherBits += currPixel.A % 2; gatherBits += currPixel.R % 2; gatherBits += currPixel.G % 2; gatherBits += currPixel.B % 2; return gatherBits; } #endregion #region Binary String to Byte Array Conversion // Grabs 8 characters from string holding hidden image // in binary, and stores them as 8 bits in each element // of a byte array public static byte[] BinaryToByteArray(string data) { Byte[] bytes = new byte[data.Length / 8]; int idx = 0; string eightBits = ""; for (int i = 0; i < data.Length; i += 8) { eightBits = data.Substring(i, 8); bytes[idx++] = Convert.ToByte(data.Substring(i, 8), 2); } return bytes; } #endregion #region Byte Array to Binary String Conversion // http://stackoverflow.com/questions/5882428/convert-a-byte-to-its-string-representation-in-binary private static string ByteArrayToBinaryString(byte[] data) { var result = string.Concat(data.Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))); return result.ToString(); } #endregion #region Cropping Image private void StartCroppingImg_mouseDown(object sender, MouseEventArgs e) { if (flag == false) return; startCropPoint = e.Location; // store the start point of crop selection window into point startCropPoint startCropPointNonRel = Cursor.Position; // keep track of where the cursor currently is selectarea.Location = startCropPointNonRel; // open a selection window where user's cursor is selectarea.Show(); // show user their selected area resizerTimer.Enabled = true; } private void StopCroppingImg_mouseUp(object sender, MouseEventArgs e) { if (flag == false) return; Image_to_Hide.Image = cropImage(Image_to_Hide.Image, new Rectangle(startCropPoint, new Size(e.X - startCropPoint.X, e.Y - startCropPoint.Y))); if (savefile.ShowDialog() == DialogResult.OK) { Image_to_Hide.Image.Save(savefile.FileName); binStr = ByteArrayToBinaryString(File.ReadAllBytes(savefile.FileName)); } resizerTimer.Enabled = false; selectarea.Close(); selectarea = new selectionWindow(); flag = false; } private void resizerTimer_Tick(object sender, EventArgs e) { if (flag == false) return; selectarea.Width = Cursor.Position.X - startCropPointNonRel.X; // finding the difference gives us new width/height selectarea.Height = Cursor.Position.Y - startCropPointNonRel.Y; // if cord 1 is (0,5) and cord 2 (8,5), the distance between them is 8 (8-0) } private Image cropImage(Image img, Rectangle cropArea) { Bitmap bmpImage = new Bitmap(img); try { return bmpImage.Clone(cropArea, bmpImage.PixelFormat); } catch { return img; } } #endregion private void BrowseImginImgBtnClick(object sender, EventArgs e) { openfile.Filter = "Image Files (*.png) | *.png"; if (openfile.ShowDialog() == DialogResult.OK) { Img_in_an_Img.Image = new Bitmap(openfile.FileName); } } } }