using System; using System.IO; using System.Drawing; public class Bitmap24Writer { protected Bitmap bmp; protected int curX, curY, iRGB; protected uint bitsLeft, bitsTotal; protected byte r, g, b; public Bitmap24Writer(Bitmap bmp) { if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb) throw new ArgumentException(); // assign vars curX = curY = iRGB = 0; this.bmp = bmp; bitsLeft = bitsTotal = (uint)bmp.Height * (uint)bmp.Width * 3; } public uint GetUnusedBitCount() { return bitsLeft; } public uint GetMaxBitStorageCount() { return bitsTotal; } public Bitmap GetBitmap() { return bmp; } public bool WriteByte(byte by) { if (bitsLeft < 8) return false; uint bits2Do = 8; for (; curX < bmp.Width; curX++) { if (curY >= bmp.Height) curY = 0; for (; curY < bmp.Height; curY++) { if (bits2Do == 0) return true; Color col = bmp.GetPixel(curX, curY); r = col.R; g = col.G; b = col.B; for ( ; ; ) { byte curBit = (byte)(by & 1); switch( iRGB ) { case 0: r = (byte)(r & 0xFE); r |= curBit; break; case 1: g = (byte)(g & 0xFE); g |= curBit; break; case 2: b = (byte)(b & 0xFE); b |= curBit; break; } --bits2Do; --bitsLeft; by >>= 1; bmp.SetPixel(curX, curY, Color.FromArgb(r, g, b)); if (iRGB == 2) { iRGB = 0; break; } iRGB++; if (bits2Do == 0) return true; } } } return true; } } public class Bitmap24Reader { protected Bitmap bmp; protected int curX, curY, iRGB; protected uint bitsLeft, bitsTotal; public Bitmap24Reader(Bitmap bmp) { if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb) throw new ArgumentException(); curX = curY = iRGB = 0; this.bmp = bmp; bitsLeft = bitsTotal = (uint)bmp.Height * (uint)bmp.Width * 3; } public uint GetUnusedBitCount() { return bitsLeft; } public uint GetMaxBitStorageCount() { return bitsTotal; } public Bitmap GetBitmap() { return bmp; } public bool ReadByte(out byte by) { by = 0; if (bitsLeft < 8) return false; byte bit = 0; uint bits2Do = 8; for (; curX < bmp.Width; curX++) { if (curY >= bmp.Height) curY = 0; for (; curY < bmp.Height; curY++) { if (bits2Do == 0) return true; Color col = bmp.GetPixel(curX, curY); for ( ; ; ) { switch( iRGB ) { case 0: bit = (byte)(col.R & 1); break; case 1: bit = (byte)(col.G & 1); break; case 2: bit = (byte)(col.B & 1); break; } --bits2Do; --bitsLeft; by |= (byte)(bit << 7); if (bits2Do != 0) by >>= 1; if (iRGB == 2) { iRGB = 0; break; } iRGB++; if (bits2Do == 0) return true; } } } return true; } } public class BitmapWorks { public static bool Data2Bmp(FileStream dataStream, FileStream bmpStream, string outFName, out string error) { error = ""; Bitmap bmp; try { bmp = new Bitmap(bmpStream); } catch { error = "Are you sure the specified bitmap is a valid bitmap ?"; return false; } if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb) { error = "Please drop only 24bit bitmaps,thanks !"; return false; } error += "-> Bitmap info: height=" + bmp.Height + " width=" + bmp.Width + "...\n"; if (dataStream.Length == 0) { error = "Input data has a not supported size of 0 !"; return false; } uint maxByteStorage = ((uint)bmp.Height * (uint)bmp.Width * 3) / 8; error += "-> Up to " + (maxByteStorage-4) + " bytes could be stored in this bitmap...\n"; if (maxByteStorage < dataStream.Length + 4) { error = "Not enough pixel in target bitmap to hide the input data block !"; return false; } Bitmap24Writer bmpWriter = new Bitmap24Writer(bmp); uint dataSize = (uint)dataStream.Length; try { for (uint u = 0; u < 4; u++) { bmpWriter.WriteByte( (byte)dataSize ); dataSize >>= 8; } for (uint u = 0; u < dataStream.Length; u++) bmpWriter.WriteByte( (byte)dataStream.ReadByte() ); } catch { error = "Error while modifing the bitmap's pixels !"; return false; } double maxBitStorage = bmpWriter.GetMaxBitStorageCount(); double spaceUsed = (100 * (maxBitStorage - bmpWriter.GetUnusedBitCount())) / maxBitStorage; error += "-> Space used: " + Convert.ToUInt32(spaceUsed) + "%...\n"; try { if ( File.Exists( outFName ) ) File.Delete( outFName ); bmpWriter.GetBitmap().Save(outFName); } catch { error = "Couldn't save output to " + outFName + " !"; return false; } error += "-> Output saved to: " + outFName + "...\n"; return true; } public static bool Bmp2Data(FileStream bmpStream, string outFName, out string error) { error = ""; Bitmap bmp; try { bmp = new Bitmap(bmpStream); } catch { error = "Are you sure the specified bitmap is a valid bitmap ?"; return false; } Bitmap24Reader bmpReader; try { bmpReader = new Bitmap24Reader(bmp); } catch (ArgumentException) { error = "This isn't a 24bit bitmap !"; return false; } FileStream outStream; try { outStream = File.Create( outFName ); } catch { error = "Couldn't create output file: " + outFName + " !"; return false; } uint dataSize = 0; byte outByte; try { for (uint u = 0; u < 4; u++) { if ( !bmpReader.ReadByte( out outByte ) ) throw new Exception(); dataSize |= (uint)( outByte << 8*3 ); if (u != 3) dataSize >>= 8; } error += "-> Size of hidden data: " + dataSize + " bytes...\n"; for (uint u = 0; u < dataSize; u++) { if ( !bmpReader.ReadByte( out outByte ) ) throw new Exception(); outStream.WriteByte( outByte ); } } catch { error = "Exception caught while reading the hidden data !"; return false; } finally { outStream.Close(); } error += "-> Output saved to: " + outFName + "...\n"; return true; } } class BmpSafe { public static string cmdLine = "Command line:\n" + " BmpSafe.exe /file2bmp (input BMP) (input file to hide) [output file]\n" + " BmpSafe.exe /bmp2file (data BMP) [output file]"; private static string serviceOne = "/file2bmp"; private static string serviceTwo = "/bmp2file"; [STAThread] static void Main(string[] args) { Console.WriteLine( "BmpSafe - hide files in 24bit bitmaps\n" + " a little steganografie implementation\n" + " by yoda\n" + "-------------------------------------------------------------------------------\n"); string inFile = "", inBmp, outFile; bool bFile2Bmp; if (args.Length < 2) { Console.WriteLine("!! Invalid number of arguments :("); Console.WriteLine(cmdLine); return; // ERR } if ( String.Compare(args[0], serviceOne, true) == 0 ) bFile2Bmp = true; else if ( String.Compare(args[0], serviceTwo, true) == 0) bFile2Bmp = false; else { Console.WriteLine("!! First parameters must be either \"/file2bmp\" or \"/bmp2file\" !"); return; } inBmp = args[1]; if (bFile2Bmp) { if (args.Length < 3) { Console.WriteLine("!! Invalid number of arguments :("); Console.WriteLine(cmdLine); return; } inFile = args[2]; if (args.Length > 3) outFile = args[3]; else outFile = "Secret.BMP"; } else { if (args.Length > 2) outFile = args[2]; else outFile = "Secret.bin"; } Console.WriteLine("-> Processing input..."); try { string err; bool ret; if (bFile2Bmp) ret = BitmapWorks.Data2Bmp( File.OpenRead(inFile), File.OpenRead(inBmp), outFile, out err ); else ret = BitmapWorks.Bmp2Data( File.OpenRead(inBmp), outFile, out err); if (!ret) { Console.WriteLine("!! " + err); return; } else Console.Write( err ); } catch(FileNotFoundException) { Console.WriteLine("!! At least one file could not be found :("); return; } catch { Console.WriteLine("!! An exception occurred :("); return; } Console.WriteLine("-> Job done..."); return; } } </pre>
关键字词: