【问题标题】:Are the first 32 bits of a 160-bit SHA1 hash an acceptable substitute for a CRC32 hash?160 位 SHA1 散列的前 32 位是否可以替代 CRC32 散列?
【发布时间】:2010-10-29 06:50:44
【问题描述】:

我正在处理一个 .NET 3.5 项目,我需要一个 32 位哈希值。 .NET Cryptography 类中似乎没有任何方法返回 32 位散列(MD5 是 128 位,SHA1 是 160 位等)。我实现了一个 CRC32 类,但我发现已经存在的 SHA1 和 MD5 哈希函数要快得多。

如果我使用 SHA1 散列函数并只是断开前 32 位存储为我的散列值,会不会有任何问题(即增加冲突的机会)?

【问题讨论】:

  • 你在做什么不能存储整个 20 个字符的 SHA-1 哈希?此外,CRC32 不是哈希,它是一种传输错误检测机制,所以如果您需要错误检测,哈希并不是真正的方法。
  • 选择 4 字节散列是为了节省空间。哈希将用于对来自监控设备的数据块进行校验和,可能有数十亿个。我们会看到,也许存储整个东西不会成为问题。你说了一些有趣的话。 “传输错误检测机制”和哈希之间究竟有什么区别?加密强度(这个特定的应用程序不需要它)?
  • 无耻自插:cmdhashgen支持CRC32,是从HashAlgorithm派生出来的,所以可以和其他的一样使用,查看Crc32.cs:cmdtools.codeplex.com
  • 我想说这只是我一直在寻找的问题,但没有找到。我对 SO 搜索从来没有任何运气。我有更好的运气输入标题,标签到问题区域,并查看弹出的建议。如果我找到我需要的,我会取消。

标签: .net hash cryptography


【解决方案1】:

为什么不直接使用 string.GetHashCode()。它旨在计算 32 位哈希值,并在给定真实数据的情况下产生很少的冲突。当然,这并不安全,但您的问题并未将其列为要求。

【讨论】:

  • String.GetHashCode 的缺点是在 32 位和 64 位模式下产生不同的结果。当 Microsoft 发布新的 .NET 版本时,它也会时不时地发生变化。当你持久化你的哈希,甚至通过网络发送它时,这就会成为一个问题。
【解决方案2】:

除非您想要 CRC32 的额外功能(作为线性代码),否则您应该可以将输出切割为 32 位。

削减某些加密哈希函数的输出是否会损害其在抗碰撞方面的安全性是一个开放的研究问题(如果我没记错的话,存在“不自然”的构造示例)。但是 NIST(可能得到了 NSA 的批准)使用切割技术从 SHA-256 中获取 SHA-224(参见 article about SHA in wikipedia)。

编辑:CRC32 允许检测(并且可能纠正)单个位错误,而加密哈希函数应该具有您无法找到具有相同哈希值的两个输入的属性。

您是否知道“生日悖论”(再次参见维基百科)?使用 32 位校验和,当您有大约 2^16 个输入并且您想要对更多输入进行哈希处理时,您预计会发生冲突(即具有相同哈希值的两个输入)。 (重读您的评论,这对您来说可能不是问题。)

【讨论】:

    【解决方案3】:

    CRC32 可能适合您的需求。这已在this question 中讨论过。

    在截断散列原语方面,唯一大量使用的应用是用于生成密钥的SSL/TLS Pseudo Random Function (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;
    }
    

    【讨论】:

    • 坏主意。这只会增加复杂性,根本没有任何好处。如果您使用 SHA1、HMAC 等,那么结果已经足够“随机”了。切割结果就是找到。例如,NIST 建议使用这种方法来获得更短的哈希值(例如 SHA-224 或 SHA-384)或更短的 HMACS。
    • 同意。我只是在寻找一种使用所有位的方法,但你是对的,它不会产生安全差异并且需要额外的说明。
    【解决方案4】:

    假设哈希函数在其 codomain 上平均分配其输入,假设它也将在其任何子集上平均分配似乎是合乎逻辑的。 但是,使用“本机”32 位散列函数可能仍然是更好的选择。也许比我的直觉更深入的人可以为我们提供更好的理由:)

    【讨论】:

      【解决方案5】:

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

      为什么不能只使用可用的更广泛的哈希?

      【讨论】:

        猜你喜欢
        • 2011-07-30
        • 2021-06-03
        • 2012-06-12
        • 1970-01-01
        • 2013-02-19
        • 2021-12-11
        • 2017-05-01
        • 1970-01-01
        • 2012-07-13
        相关资源
        最近更新 更多