我正在使用SHA-256算法来检测数据库中的相同图像。因为我们使用了很多不同的图像格式,所以我不想直接在文件上计算哈希值。相反,我想提取像素数据并计算其上的哈希值。
不幸的是,我得到了很多随机碰撞:在6000个图像中使用相同像素提取(下图)的68个图像没有相同的字节哈希到相同的值。我觉得这是一次疯狂的碰撞。另外,我将我计算的字节从像素数据转储到文件中,然后尝试:
echo -n [byteDumpFile] | sha256sum
导致转储图像的哈希值不同,这让我相信当我使用MessageDigest时我做错了什么。
以下是我获取像素数据的方法:
imageBytes = new byte[4 * width * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// grab color information
int argb = image.getRGB(x, y);
// a,r,g,b ordered bytes per this pixel. the values are always 0-255 so the byte cast is safe
int offset = y * width;
int pushX = x * 4;
imageBytes[pushX + offset] = (byte) ((argb >> 24) & 0xff);
imageBytes[pushX + 1 + offset] = (byte) ((argb >> 16) & 0xff);
imageBytes[pushX + 2 + offset] = (byte) ((argb >> 8) & 0xff);
imageBytes[pushX + 3 + offset] = (byte) (argb & 0xff);
}
}
然后我使用MessageDigest类计算哈希:
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.reset();
for (int i = 0; i < imageBytes.length; i++)
{
digest.update(imageBytes[i]);
}
String hashString = new String(encodeHex(digest.digest()));
其中encodeHex只是:
private static String encodeHex(byte data[])
{
StringBuilder hex = new StringBuilder(2 * data.length);
for (byte b : data)
{
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
答案 0 :(得分:2)
我认为offset
计算错误。它应该是:
int offset = y * width * 4;
创建imageBytes
的更好方法可能是ByteBuffer
;它允许您按顺序简单地put
每个字节而不计算索引。此外,它可以直接与MessageDigest一起使用。
答案 1 :(得分:1)
尝试
digest.update(imageBytes);
答案 2 :(得分:0)
我想出了这个。根据上述评论:
private String calculateHash(BufferedImage img) throws NoSuchAlgorithmException {
final int width = img.getWidth();
final int height = img.getHeight();
final ByteBuffer byteBuffer = ByteBuffer.allocate(4 * width * height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// grab color information
int argb = img.getRGB(x, y);
// a,r,g,b ordered bytes per this pixel. the values are always 0-255 so the byte cast is safe
byteBuffer.put((byte) ((argb >> 24) & 0xff));
byteBuffer.put((byte) ((argb >> 16) & 0xff));
byteBuffer.put((byte) ((argb >> 8) & 0xff));
byteBuffer.put((byte) (argb & 0xff));
}
}
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.reset();
byte[] hashBytes = digest.digest(byteBuffer.array());
return Base64Utils.encodeToString(hashBytes);
}