我有一个关于图像隐写术的项目(用于无损图像)。我正在努力学习它背后的过程。但是,当我运行它来提取消息时,会为错误密码以及空图像(无数据编码)生成异常 。它随机选择像素并使用哈希集。但我不明白中间的一些步骤。我怀疑这些步骤中的任何错误是否会导致异常。此外,在某些情况下,项目即使是错误的密码也会提取隐藏信息。我该如何解决这些问题?
为这个长代码道歉,但希望有一个解决方案.. 谢谢你的帮助。
代码如下所示:
//encoding data in image
private void EncodeByte(Bitmap bm, Bitmap visible_bm, Random rand,
byte value, HashSet<string> used_positions)
{
for (int i = 0; i < 8; i++)
{
// Pick a position for the ith bit.
int row, col, pix;
PickPosition(bm, rand, used_positions, out row, out col, out pix);
// Get the color's pixel components.
Color clr = bm.GetPixel(row, col);
byte r = clr.R;
byte g = clr.G;
byte b = clr.B;
怀疑:下一个要存储的位是如何在下面显示的“下两行”中进行的?
// Get the next bit to store.
int bit = 0;
if ((value & 1) == 1) bit = 1; //’value’ is the byte to be encoded
// Update the color.
switch (pix)
{
case 0:
r = (byte)((r & 0xFE) | bit);
break;
case 1:
g = (byte)((g & 0xFE) | bit);
break;
case 2:
b = (byte)((b & 0xFE) | bit);
break;
}
clr = Color.FromArgb(clr.A, r, g, b);
bm.SetPixel(row, col, clr);
// Move to the next bit in the value.
value >>= 1;
}
}
//decoding image
private string DecodeMessageInImage(Bitmap bm, string password)
{
// Initialize a random number generator.
Random rand = new Random(obj.NumericPassword(password));
// Create a new HashSet.
HashSet<string> used_positions = new HashSet<string>();
// Make a byte array big enough to hold the message length.
int len = 0;
byte[] bytes = BitConverter.GetBytes(len);
// Decode the message length.
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = DecodeByte(bm, rand, used_positions);
}
len = BitConverter.ToInt32(bytes, 0);
怀疑:以下检查(如果len> 10000)是否合适?
// Sanity check.
if(len>10000)
{
throw new InvalidDataException(
"Message length " + len.ToString() +
" is too big to make sense. Invalid password.");
}
// Decode the message bytes.
char[] chars = new char[len];
for (int i = 0; i < chars.Length; i++)
{
chars[i] = (char)DecodeByte(bm, rand, used_positions);
}
return new string(chars);
}
// Decode a byte.
private byte DecodeByte(Bitmap bm, Random rand, HashSet<string> used_positions)
{
byte value = 0;
byte value_mask = 1;
for (int i = 0; i < 8; i++)
{
// Find the position for the ith bit.
int row, col, pix;
obj.PickPosition(bm, rand, used_positions, out row, out col, out pix);
// Get the color component value.
byte color_value = 0;
switch (pix)
{
case 0:
color_value = bm.GetPixel(row, col).R;
break;
case 1:
color_value = bm.GetPixel(row, col).G;
break;
case 2:
color_value = bm.GetPixel(row, col).B;
break;
}
怀疑:你能告诉我以下是如何运作的:
// Set the next bit if appropriate.
if ((color_value & 1) == 1)
{
// Set the bit.
value = (byte)(value | value_mask);
}
// Move to the next bit.
value_mask <<= 1;
}
return value;
}
怀疑:这个无限循环是异常吗?这是正确的条件吗?
// Pick an unused (r, c, pixel) combination.
public void PickPosition(Bitmap bm, Random rand,
HashSet<string> used_positions,
out int row, out int col, out int pix)
{
for (; ; )
{
// Pick random r, c, and pix.
row = rand.Next(0, bm.Width);
col = rand.Next(0, bm.Height);
pix = rand.Next(0, 3);
// See if this location is available.
string key =
row.ToString() + "/" +
col.ToString() + "/" +
pix.ToString();
if (!used_positions.Contains(key))
{
used_positions.Add(key);
return;
}
}
}
// Convert a string password into a numeric value.
public int NumericPassword(string password)
{
// Initialize the shift values to different non-zero values.
int shift1 = 3;
int shift2 = 17;
// Process the message.
char[] chars = password.ToCharArray();
int value = 0;
for (int i = 1; i < password.Length; i++)
{
// Add the next letter.
int ch_value = (int)chars[i];
value ^= (ch_value << shift1);
value ^= (ch_value << shift2);
// Change the shifts.
shift1 = (shift1 + 7) % 19;
shift2 = (shift2 + 13) % 23;
}
return value;
}
答案 0 :(得分:1)
NumericPassword
可能会为两个不同的密码(“hash collission”)返回相同的值。 NumericPassword
基本上是一个哈希函数,因此很容易受到攻击攻击。您可以通过为哈希使用更多字节来改善这种情况,尽管这需要一个不同的算法和一个能够处理更大种子的随机数生成器。
在这种情况下,随机数生成器会为不同的密码生成相同的数字序列,如果它们产生相同的散列,即导致隐写内容的“解密”。
人们可以通过使用密码作为密钥的加密算法加密数据本身来规避这种情况。
有关如何将值打包/解压缩到图像中的问题,请查看Bitwise Operators。
例如:
if ((value & 1) == 1) bit = 1; //’value’ is the byte to be encoded
将取最低有效位并将其与1进行比较。如果为1,则将bit
设置为1.这就是将字节值分解为单个位的方式,然后将其写入最低有效位除了您所显示的情况外,图像中颜色值的位数。
bitwise and
(&
)运算符的示例:拥有二进制值00101010
,我们可以bitwise and
使用00010111
,这会给我们{ {1}}。
还使用了bitshift运算符(00000010
)。在你的情况下(<<
),它将整数左边的位(即其重要性中的位)向上移动一位。那里的掩码用于掩盖当前读取位必须放入值的位置。
基本上,在编码和解码功能中,迭代遍历字节中从低到高的所有位。然后通过将其打包到像素的最低有效位中,分别在图像之后写入或读取一个比特。
长度检查是明智的,但我会选择不同的条件(即依赖于图像大小的条件,即容器的实际大小)。通过检查图像中编码的数据是否可以使用给定的密码进行解码(健全性检查)来检测可能错误的密码是必要的。
对于错误的密码,提取的长度可能会非常高。这不是检测错误密码的安全检查(错误的密码也可能产生较低的长度)。
PickPosition中的“无限”循环。该循环可能确实是无限的,即如果图像中没有剩余位置。就个人而言,我会选择一种算法,该算法在获取新的随机值之前首先通过“坏”(即已经使用过的)像素的邻域。
这样可能需要很长时间才能找到下一个有效位置。此外,它还没有检查是否存在任何有效位置,但这可能发生在您未显示的部分代码中。
根据算法,可以很容易地计算出可以存储在图像中的比特数。该算法将信息存储在每个颜色通道的最低有效位中,因此我们得到每像素三位。因此,图像中的总位数为:
<<= 1