我正在使用每个像素的LSB实现图像隐写。如果秘密文本的大小很低(< 10),它可以正常工作,但是对于较长的文本它会失败。
我的代码:
private void processButtonLSB_Click(object sender, EventArgs e)
{
String dest = destLSBText.Text;
Bitmap img = (Bitmap)Bitmap.FromFile(dest); // bitmap of the given image
byte[] temp = GetBytes(this.secretText.Text);
byte[] secretText = new byte[temp.Length + 1];
temp.CopyTo(secretText, 0);
secretText[temp.Length] = 0x0; // adding last 0 byte
BitArray bits = new BitArray(secretText); // parsing bytes to bits of secret text
StringBuilder sb = new StringBuilder(); // debug feature
for (int i = 0; i < bits.Length; i++)
{
bool bit = bits.Get(i); // getting i bit of secret text
int x = i / img.Width;
int y = i % img.Height;
int argb = img.GetPixel(x, y).ToArgb(); // getting argb of the original image
bool argbBit = argb % 2 != 0; // getting last bit of the pixel
if (bit && !argbBit || !bit && argbBit) // ensure if we need to make changes
{
setBit(ref argb, 0, !argbBit); // changing last bit
img.SetPixel(x, y, Color.FromArgb(argb)); // changing bitmap
}
if (sb.Length > 0)
sb.Append(",");
sb.Append("0x" + argb.ToString("X4")); // adding modified pixel to debug #2
}
MessageBox.Show(sb.ToString()); // showing all pixels with payload
saveImage(img, ImageFormat.Png);
}
private void retrieveButtonLSB_Click(object sender, EventArgs e)
{
String dest = destLSBText.Text;
Bitmap img = (Bitmap) Bitmap.FromFile(dest); // bitmap with payload
List<bool> bits = new List<bool>();
byte[] foundBytes = null;
StringBuilder sb = new StringBuilder(); // debug feature
for (int i = 0; i < img.Width * img.Height; i++) // iterating thru all pixels until zero byte is met
{
int x = i / img.Width;
int y = i % img.Height;
int argb = img.GetPixel(x, y).ToArgb(); // getting argb
bool bit = argb % 2 != 0; // last bit
bits.Add(bit);
if (sb.Length > 0)
sb.Append(",");
sb.Append("0x" + argb.ToString("X4")); // adding argb to debug #3
if (bits.Count % 8 == 0) // checking if last byte is 0x0
{
foundBytes = new byte[bits.Count / 8];
BitArray bitArray = new BitArray(bits.ToArray());
bitArray.CopyTo(foundBytes, 0);
if (foundBytes[foundBytes.Length - 1] == 0x0)
break;
}
}
MessageBox.Show(sb.ToString()); // showing all pixels with payload
if (foundBytes != null)
secretText.Text = GetString(foundBytes);
}
processButtonLSB_Click
使用给定的隐藏文字创建图像,retrieveButtonLSB_Click
从图像中检索隐藏文字。
我添加了消息框以检测每一步的像素,并得到以下结果
原始图像(第一个像素)
0xFF0C6128,0xFF0C6128,0xFF0B6027,0xFF0B6027,0xFF0A5F26,0xFF0A5F26,0xFF0A5D25,0xFF0A5D25,...
更改图像(来自#1)
0xFF0C6128,0xFF0C6128,0xFF0B6026,0xFF0B6027,0xFF0A5F26,0xFF0A5F27,0xFF0A5D25,0xFF0A5D24,...
已保存的图片(来自#2)
0xFF0C6128,0xFF0C6129,0xFF0B6027,0xFF0B6027,0xFF0A5F27,0xFF0A5F26,0xFF0A5D24,0xFF0A5D24,...
但为什么呢?也许我犯了一个错误?我检查了两次,没有找到任何东西。
保存图片的代码:
private String saveImage(Image img, ImageFormat format)
{
String path = getSavePath(format);
if(path != null)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/png")
ici = codec;
}
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
img.Save(path, ici, ep);
return path;
}
return null;
}
其他依赖(我确定它是正确的)
private bool getBit(int b, int bitNumber)
{
return (b & (1 << bitNumber)) != 0;
}
private void setBit(ref int b, int bitNumber, bool value)
{
int mask = 1 << bitNumber;
if(value)
b |= mask;
else
b &= ~mask;
}
private byte[] GetBytes(string str)
{
return Encoding.UTF8.GetBytes(str);
}
private string GetString(byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}