using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Windows.Forms; namespace Steganography { public partial class Form1 : Form { private const int encodingBitMask = ~3; private const int decodingBitMask = 3; private const int bitMaskA = 3; private const int bitMaskB = 3 << 2; private const int bitMaskG = 3 << 4; private const int bitMaskR = 3 << 6; private string imagePath = ""; private string textToHide = ""; private Bitmap image; private Bitmap encodedImage; private bool fileHideSet; // False by default private bool fileEncodeSet; public Form1() { InitializeComponent(); // Add event handlers btnFileHide.Click += btnFileHide_Click; btnFileEncode.Click += btnFileEncode_Click; ofdFileEncode.Filter = @"Image Files (PNG)|*.PNG"; } private static bool isValidPath(string path) { if (path == "") { MessageBox.Show(@"Please provide an image path."); return false; } if (!File.Exists(path)) { MessageBox.Show(@"Couldn't find the file"); return false; } string ext = Path.GetExtension(path); if (ext == null || ext.ToLower() != ".png") { MessageBox.Show(@"Sorry, this only works with images with alpha channels. I.e. PNGs"); return false; } return true; } private static Color encode(Color pixel, char c) { int r = (c & bitMaskR) >> 6; int g = (c & bitMaskG) >> 4; int b = (c & bitMaskB) >> 2; int a = (c & bitMaskA); int red = (pixel.R & encodingBitMask) | r; int green = (pixel.G & encodingBitMask) | g; int blue = (pixel.B & encodingBitMask) | b; int alpha = (pixel.A & encodingBitMask) | a; return Color.FromArgb(alpha, red, green, blue); } private static char decode(Color pixel) { int red = pixel.R & decodingBitMask; int green = pixel.G & decodingBitMask; int blue = pixel.B & decodingBitMask; int alpha = pixel.A & decodingBitMask; return (char)((red << 6) | (green << 4) | (blue << 2) | alpha); } private void btnHideText_Click(object sender, EventArgs e) { imagePath = tbImagePath.Text; textToHide = tbTextToAdd.Text; if (!isValidPath(imagePath)) return; // Open the image image = new Bitmap(imagePath); encodedImage = new Bitmap(image.Width, image.Height); int charCounter = 0; for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { // Store current character in least significant bits of current pixel's components Color currentPixel = image.GetPixel(x, y); encodedImage.SetPixel(x, y, encode(currentPixel, textToHide[charCounter])); charCounter = charCounter == textToHide.Length - 1 ? 0 : charCounter + 1; } } image.Dispose(); string saveName = Path.ChangeExtension(imagePath, null) + "_encoded.png"; encodedImage.Save(saveName, ImageFormat.Png); encodedImage.Dispose(); MessageBox.Show(@"Saved new image successfully"); } private void btnReadText_Click(object sender, EventArgs e) { imagePath = tbImagePath.Text; if (!isValidPath(imagePath)) return; // Open the image image = new Bitmap(imagePath); string str = ""; int maxChars = 16; for (int i = 0; i < maxChars; i++) { Color currentPixel = image.GetPixel(i / image.Width, i % image.Width); str += decode(currentPixel); } image.Dispose(); MessageBox.Show(@"This image contains the message: " + str + @" (first 16 characters)."); } // Select File To Hide Inside The Other File private void btnFileHide_Click(object sender, EventArgs e) { if (ofdFileToHide.ShowDialog() != DialogResult.OK) return; fileHideSet = true; } // Select File To Hide The Other File Inside Of // Or to read an already hidden file from private void btnFileEncode_Click(object sender, EventArgs e) { if (ofdFileEncode.ShowDialog() != DialogResult.OK) return; fileEncodeSet = true; } // TODO: Test this // TODO: Hide file type and length within encoded image private void btnEncode_Click(object sender, EventArgs e) { if (!fileHideSet) { MessageBox.Show(@"You must select a file to hide"); return; } if (!fileEncodeSet) { MessageBox.Show(@"You must select an image to hide the file in"); return; } if (Path.GetExtension(ofdFileEncode.FileName) != ".png") { MessageBox.Show(@"You must hide your file in a png image"); return; } var fileHideInfo = new FileInfo(ofdFileToHide.FileName); var fileEncodeInfo = new FileInfo(ofdFileEncode.FileName); if (fileHideInfo.Length > fileEncodeInfo.Length) { MessageBox.Show(@"The file you are trying to hide must be smaller than the one you are trying to hide it in"); return; } image = new Bitmap(ofdFileEncode.FileName); encodedImage = new Bitmap(image.Width, image.Height); StreamReader sr = new StreamReader(ofdFileToHide.FileName); int charCounter = 0; for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { Color currentPixel = image.GetPixel(x, y); char[] currentChar = new char[1]; sr.Read(currentChar, charCounter, 1); encodedImage.SetPixel(x, y, encode(currentPixel, currentChar[0])); charCounter = charCounter == fileHideInfo.Length - 1 ? 0 : charCounter + 1; } } sr.Close(); image.Dispose(); string saveName = Path.ChangeExtension(ofdFileEncode.FileName, null) + "_encoded.png"; encodedImage.Save(saveName, ImageFormat.Png); encodedImage.Dispose(); MessageBox.Show(@"Saved new image successfully"); } private void btnDecode_Click(object sender, EventArgs e) { } } }