我正在处理一个.NET 3.5项目,需要一个32位的哈希值。在.NET加密类中似乎没有返回32位哈希值的方法(MD5是128位,SHA1是160位等)。我实现了一个CRC32类,但是我发现已经存在的SHA1和MD5哈希函数更快。
如果我使用SHA1哈希函数并仅截取前32位作为我的哈希值存储,是否会有任何问题(即增加碰撞的可能性)?
如果我使用SHA1哈希函数并仅截取前32位作为我的哈希值存储,是否会有任何问题(即增加碰撞的可能性)?
除非你需要CRC32的额外功能(作为线性码),否则将输出截断为32位应该就可以了。
对于一些密码哈希函数来说,截取其输出是否会影响其冲突抗性安全性仍然是一个开放的研究问题(如果我没记错的话,有一些“不自然”的构造例子)。但是NIST(可能得到了NSA的批准)还是使用了这种截取技术来从SHA-256中获取SHA-224(参见维基百科上关于SHA的文章)。
编辑:CRC32允许检测(或者可能纠正)单个比特错误,而密码哈希函数应该具有这样的属性:不能找到两个输入具有相同的哈希值。
你知道“生日悖论”吗(再次参见维基百科)?如果你有大约2^16个输入并且想要哈希更多的输入,则使用32位校验和时,你预计会出现冲突(即具有相同哈希值的两个输入)。 (重新阅读您的评论后,这可能对您没有问题。)
假设哈希函数在其值域内均匀分布,那么它在任何子集上也应该是均匀分布的。然而,使用“本地”32位哈希函数可能仍然是更好的选择。也许比我更了解这个问题的人可以给我们提供比我的直觉更好的理由 :)
CRC32 可能是您需要的。这个问题已经在这个问题中讨论过。
关于截断哈希原语,唯一广泛使用的应用是SSL/TLS伪随机函数(PRF),它用于生成密钥。它使用HMAC、种子和标签多次哈希生成所需的字节数,然后截断到所需的字节数。
至于您的具体问题,如果您很谨慎,您可以将哈希的输出读入Int32中,然后将它们异或在一起:
static void Main()
{
int xorCrc = GetHashedCrc(new SHA1Cng(), new byte[] {0xDE, 0xAD, 0xBE, 0xEF});
}
private static int GetHashedCrc(HashAlgorithm algorithm, byte[] bytesToHash)
{
byte[] hash = algorithm.ComputeHash(bytesToHash);
int totalInt32s = hash.Length/sizeof(int);
int result = 0;
for(int i = 0; i < totalInt32s; i++)
{
int currentInt = BitConverter.ToInt32(hash, sizeof(int)*i);
result = result ^ currentInt;
}
return result;
}
如果您不打算将32位用于加密目的,那么应该没问题。否则,我不会依赖于前32位具有与整个哈希相同的分布。
为什么不能使用可用的更宽的哈希呢?