160位SHA1哈希的前32位是否可以替代CRC32哈希?

6
我正在处理一个.NET 3.5项目,需要一个32位的哈希值。在.NET加密类中似乎没有返回32位哈希值的方法(MD5是128位,SHA1是160位等)。我实现了一个CRC32类,但是我发现已经存在的SHA1和MD5哈希函数更快。
如果我使用SHA1哈希函数并仅截取前32位作为我的哈希值存储,是否会有任何问题(即增加碰撞的可能性)?

2
你为什么不能存储整个20个字符的SHA-1哈希值?此外,CRC32不是哈希,它是一种传输错误检测机制,因此如果你需要错误检测,哈希并不是实现这一目的的最佳方式。 - jmucchiello
为了节省空间,选择了4字节哈希。该哈希用于校验来自监控设备的数据块,可能会有数千万个。我们将看到,也许存储整个东西不是问题。你说了一些有趣的东西。“传输错误检测机制”和哈希之间究竟有什么区别?(这个特定的应用程序不需要加密强度) - raven
不要介意我自吹自擂:cmdhashgen支持CRC32,它是从HashAlgorithm派生的,因此可以像其他工具一样使用,检查Crc32.cs: http://cmdtools.codeplex.com/ - Michael Stum
类似的问题:https://dev59.com/SnRA5IYBdhLWcg3wsgLq - Jeff Moser
我想说这正是我一直在寻找但却没有找到的问题。我在SO搜索中从来没有什么好运气。我更喜欢输入标题,切换到问题区域,看看会出现什么建议。如果我找到了需要的内容,我就取消搜索。 - raven
5个回答

8

除非你需要CRC32的额外功能(作为线性码),否则将输出截断为32位应该就可以了。

对于一些密码哈希函数来说,截取其输出是否会影响其冲突抗性安全性仍然是一个开放的研究问题(如果我没记错的话,有一些“不自然”的构造例子)。但是NIST(可能得到了NSA的批准)还是使用了这种截取技术来从SHA-256中获取SHA-224(参见维基百科上关于SHA的文章)。

编辑:CRC32允许检测(或者可能纠正)单个比特错误,而密码哈希函数应该具有这样的属性:不能找到两个输入具有相同的哈希值。

你知道“生日悖论”吗(再次参见维基百科)?如果你有大约2^16个输入并且想要哈希更多的输入,则使用32位校验和时,你预计会出现冲突(即具有相同哈希值的两个输入)。 (重新阅读您的评论后,这可能对您没有问题。)


2

假设哈希函数在其值域内均匀分布,那么它在任何子集上也应该是均匀分布的。然而,使用“本地”32位哈希函数可能仍然是更好的选择。也许比我更了解这个问题的人可以给我们提供比我的直觉更好的理由 :)


1
为什么不直接使用 string.GetHashCode() 呢?它被设计用来计算 32 位哈希值并在现实数据中产生很少的冲突。当然,它并不安全,但你的问题中并没有包括这个要求。

String.GetHashCode存在一个缺点,即在32位和64位模式下会产生不同的结果。当Microsoft发布新的.NET版本时,它也会不时地发生变化。当您持久化哈希或甚至将其发送到网络上时,这将成为一个问题。 - Constantin

0

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;
}

1
不好的想法。这只会增加复杂性,没有任何好处。如果您使用SHA1、HMAC等,则结果已经足够“随机”了。截取结果就可以了。这是例如NIST建议获取较短哈希(例如SHA-224或SHA-384)或较短HMACS的方法。 - Accipitridae
同意。我只是想找一个使用所有位的方法,但你说得对,这不会增加安全性,反而会增加额外的指令成本。 - Jeff Moser

0

如果您不打算将32位用于加密目的,那么应该没问题。否则,我不会依赖于前32位具有与整个哈希相同的分布。

为什么不能使用可用的更宽的哈希呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接