public static Bitmap embedFileIntoImage(Bitmap bitmapImage, List<byte[]> filedata, int capacity = -1, string password = "", ToolStripStatusLabel toolStripStatusLabel = null, bool stealthy = true, Stealthiness stealthValue = Stealthiness.Maximum) { try { int imagewidth = bitmapImage.Width - 1; int imageheight = bitmapImage.Height - 1; byte[] filebytes = filedata[1]; string filehash = ""; writeOut(toolStripStatusLabel, "Encoding file into image - Please wait..."); // Calculate pre-encoded SHA1 Hash of File Data using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) filehash = Convert.ToBase64String(sha1.ComputeHash(filebytes)); // Encrypt File Data (bytes) if (!String.IsNullOrEmpty(password)) filebytes = encryptData(filebytes, password); // Encrypt Filename (bytes) byte[] filenamebytes = filedata[0]; if (!String.IsNullOrEmpty(password)) filenamebytes = encryptData(filenamebytes, password); // Convert Filename to binary string filename = string.Empty; foreach (byte b in filenamebytes) filename += Convert.ToString(b, 2).PadLeft(8, '0'); // Convert length of filename (in bytes) into binary string filenamelength = Convert.ToString(filename.Length / 8, 2).PadLeft(8, '0'); // Convert length of File Data (in bytes) into binary string filelength = Convert.ToString(filebytes.Length, 2).PadLeft(24, '0'); // Build binary string StringBuilder sfinal = new StringBuilder(); sfinal.Append(filenamelength); sfinal.Append(filelength); sfinal.Append(filename); foreach (byte b in filebytes) sfinal.Append(Convert.ToString(b, 2).PadLeft(8, '0')); sfinal.Append("000");//buffer // Check binary data will fit int msgLen = (sfinal.Length + 16) / 8; int pixCnt = capacity; if(capacity < 0) pixCnt = (int)Math.Floor((double)((GetImageCapacity(bitmapImage, stealthy, stealthValue) * 3) / 8)); // Calculate bit distribution throughout image (jump value) //if(pixCnt) int jmp = 0; if (pixCnt > msgLen) jmp = (int)Math.Floor((double)(pixCnt / msgLen)); if (jmp > 500) jmp = 500; if (jmp == 0) jmp = 1; string jump = Convert.ToString(jmp, 2).PadLeft(9, '0'); // Insert 'jump' value into first three pixels for (int x = 0; x < 9; x+=3) { Color pixel = bitmapImage.GetPixel(x, 0); string r = Convert.ToString(pixel.R, 2).PadLeft(8, '0').Substring(0, 7) + jump[x]; string g = Convert.ToString(pixel.G, 2).PadLeft(8, '0').Substring(0, 7) + jump[x+1]; string b = Convert.ToString(pixel.B, 2).PadLeft(8, '0').Substring(0, 7) + jump[x+2]; bitmapImage.SetPixel(x, 0, Color.FromArgb(Convert.ToInt32(r, 2), Convert.ToInt32(g, 2), Convert.ToInt32(b, 2))); } int streamPos = 0; int pixelPos = 0; // Insert all binary data into image if (pixCnt > msgLen) { for (int y = 1; y < imageheight - 1; y++) { for (int x = 1; x < imagewidth - 1; x ++) { if (streamPos < sfinal.Length - 3) { if (IsValidPixel(bitmapImage, x, y, stealthy, stealthValue)) { if (pixelPos % jmp == 0) { Color pixel = bitmapImage.GetPixel(x, y); string r = Convert.ToString(pixel.R, 2).PadLeft(8, '0').Substring(0, 7) + sfinal[streamPos]; string g = Convert.ToString(pixel.G, 2).PadLeft(8, '0').Substring(0, 7) + sfinal[streamPos + 1]; string b = Convert.ToString(pixel.B, 2).PadLeft(8, '0').Substring(0, 7) + sfinal[streamPos + 2]; bitmapImage.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(r, 2), Convert.ToInt32(g, 2), Convert.ToInt32(b, 2))); streamPos += 3; } pixelPos++; } } } Application.DoEvents(); } writeOut(toolStripStatusLabel, "Encoding Complete."); } else { writeOut(toolStripStatusLabel, "Image is too small to hold the specified file!"); throw new SteganoException("Image is too small to hold the specified file!"); } writeOut(toolStripStatusLabel, "Checking integrity of embedded file - Please wait..."); // Extract data from image (and decrypt if necessary) List<byte[]> checkdata = extractFileFromImage(bitmapImage, password, toolStripStatusLabel, stealthy, stealthValue); string checkhash = ""; // Calculate SHA1 hash of extracted data if (checkdata != null && checkdata.Count == 2) using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) checkhash = Convert.ToBase64String(sha1.ComputeHash(checkdata[1])); // Check extracted SHA1 hash with pre-encoded SHA1 hash if (checkhash == filehash && checkhash != "" && filehash != "") { writeOut(toolStripStatusLabel, "Integrity check PASSED."); return bitmapImage; } else { writeOut(toolStripStatusLabel, "Integrity check FAILED!"); throw new SteganoException("Failed integrity check!"); } } catch (SteganoException ex) { throw new Exception(ex.Message); } catch (Exception ex) { throw new SteganoException("Stegano: " + ex.Message); } }
public static int GetImageCapacity(Bitmap bitmap, bool stealthy = true, Stealthiness stealthValue = Stealthiness.Maximum) { int cnt = -1; try { for (int y = 1; y < bitmap.Height - 1; y++) { for (int x = 1; x < bitmap.Width - 1; x++) if (IsValidPixel(bitmap, x, y, stealthy, stealthValue)) cnt++; Application.DoEvents(); } } catch { } return cnt; }
private static bool IsValidPixel(Bitmap bitmap, int x, int y, bool stealthy = true, Stealthiness stealthValue = Stealthiness.Maximum) { Application.DoEvents(); if (stealthy) { // looks above, below, left & right of current pixel and returns false if 5 msb's of all 5 pixels match (ie all virtually the same color) int msb = (int)stealthValue; Color cpixel = Color.FromArgb((int)(bitmap.GetPixel(x, y).R & msb), (int)(bitmap.GetPixel(x, y).G & msb), (int)(bitmap.GetPixel(x, y).B & msb)); Color upixel = Color.FromArgb((int)(bitmap.GetPixel(x, y - 1).R & msb), (int)(bitmap.GetPixel(x, y - 1).G & msb), (int)(bitmap.GetPixel(x, y - 1).B & msb)); Color dpixel = Color.FromArgb((int)(bitmap.GetPixel(x, y + 1).R & msb), (int)(bitmap.GetPixel(x, y + 1).G & msb), (int)(bitmap.GetPixel(x, y + 1).B & msb)); Color lpixel = Color.FromArgb((int)(bitmap.GetPixel(x - 1, y).R & msb), (int)(bitmap.GetPixel(x - 1, y).G & msb), (int)(bitmap.GetPixel(x - 1, y).B & msb)); Color rpixel = Color.FromArgb((int)(bitmap.GetPixel(x + 1, y).R & msb), (int)(bitmap.GetPixel(x + 1, y).G & msb), (int)(bitmap.GetPixel(x + 1, y).B & msb)); //return !((cpixel.GetHue() == upixel.GetHue()) && (cpixel.GetHue() == dpixel.GetHue()) && (cpixel.GetHue() == lpixel.GetHue()) && (cpixel.GetHue() == rpixel.GetHue())); return !(cpixel.Equals(upixel) && cpixel.Equals(dpixel) && cpixel.Equals(lpixel) && cpixel.Equals(rpixel)); } else { return true; } }
public static List<byte[]> extractFileFromImage(Bitmap sourceImage, string password = "", ToolStripStatusLabel toolStripStatusLabel = null, bool stealthy = true, Stealthiness stealthValue = Stealthiness.Maximum) { try { // Extract jump value from first 3 pixels StringBuilder sb = new StringBuilder(); for (int x = 0; x < 9; x += 3) { Color pixel = sourceImage.GetPixel(x, 0); string r = Convert.ToString(pixel.R, 2).PadLeft(8, '0').Substring(7, 1); string g = Convert.ToString(pixel.G, 2).PadLeft(8, '0').Substring(7, 1); string b = Convert.ToString(pixel.B, 2).PadLeft(8, '0').Substring(7, 1); sb.Append(r + g + b); } int jump = Convert.ToInt32(sb.ToString(0, 9), 2); int imagewidth = sourceImage.Width - 1; int imageheight = sourceImage.Height - 1; StringBuilder sbfinal = new StringBuilder(); int pixelPos = 0; // Extract ALL lsb's from image using jump value for (int y = 1; y < imageheight - 1; y++) { for (int x = 1; x < imagewidth - 1; x++) { if (IsValidPixel(sourceImage, x, y, stealthy, stealthValue)) { if (pixelPos % jump == 0) { Color pixel = sourceImage.GetPixel(x, y); string r = Convert.ToString(pixel.R, 2).PadLeft(8, '0').Substring(7, 1); string g = Convert.ToString(pixel.G, 2).PadLeft(8, '0').Substring(7, 1); string b = Convert.ToString(pixel.B, 2).PadLeft(8, '0').Substring(7, 1); sbfinal.Append(r + g + b); } pixelPos++; } } } // Get filename length (in bytes) value from first 8 bits int filenamelength = Convert.ToInt32(sbfinal.ToString(0, 8), 2); // Get file data length (in bytes) value from next 24 bits int filesize = Convert.ToInt32(sbfinal.ToString(8, 24), 2); // Get filename byte[] filenamebytes = GetBytesFromBinaryString(sbfinal.ToString(32, filenamelength * 8)); // Decrypt filename (if necessary) if (!String.IsNullOrEmpty(password)) filenamebytes = decryptData(filenamebytes, password); // Check for valid filename if (!IsASCII(filenamebytes)) throw new SteganoException("Bad Decrypt"); // Extract remaining file data byte[] filebytes = GetBytesFromBinaryString(sbfinal.ToString(32 + (filenamelength * 8), filesize * 8)); // Decrypt file data (if necessary) if (!String.IsNullOrEmpty(password)) filebytes = decryptData(filebytes, password); List<byte[]> data = new List<byte[]>(); data.Add(filenamebytes); data.Add(filebytes); return data; } catch (SteganoException ex) { toolStripStatusLabel.Text = "Bad Decrypt. Wrong Password???"; throw new Exception(ex.Message); } catch { toolStripStatusLabel.Text = "Bad Decrypt. Wrong Password???"; throw new SteganoException("Bad Decrypt"); } }