该C#程序可将文本文件藏于位图中,也可导出之!
2024-07-21 02:19:05
供稿:网友
 
//使用方法:
// bmpsafe.exe /file2bmp (input bmp) (input file to hide) [output file]
//bmpsafe.exe /bmp2file (data bmp) [output file]
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;
 }
}