【问题标题】:Is there a hash algorithm that produces a hash size of 64 bits in C#?是否有在 C# 中产生 64 位散列大小的散列算法?
【发布时间】:2010-12-02 22:05:43
【问题描述】:

我需要基于可变长度字符串生成一个哈希值,我可以将其存储在不超过 16 个字段中(由于供应商的要求)。

我将通过 C# 脚本转换传递的几个字符串连接在一起以计算哈希。我受到供应商文件规范的限制,因为哈希的输出不能超过 16。

有人有什么建议吗?以MD5算法的字符串转换为例,长度为32。

【问题讨论】:

  • 16 什么?是二进制还是文本?
  • 最好是文本,因为它将被写入平面文件。
  • 平面文件不一定是文本。
  • 我必须生成的文件要求是制表符分隔的 ASCII 平面文件。

标签: c# hash ssis


【解决方案1】:

加密函数的设计使您可以将输出截断到某个大小,并且截断的哈希函数仍然是安全的加密哈希函数。例如,如果您将 SHA-512 输出的前 128 位(16 字节)应用于某个输入,则前 128 位是与任何其他 128 位加密散列一样强的加密散列。

解决方案是选择一些加密哈希函数 - SHA-256、SHA-384 和 SHA-512 是不错的选择 - 而truncate the output 则为 128 位(16 字节)。

--编辑--

基于哈希值在编码为 ASCII 时必须适合 16 个 ASCI 字符的注释,解决方案是

  • 首先,选择一些加密哈希函数(SHA-2 系列包括 SHA-256、SHA-384 和 SHA-512)
  • 然后,将所选哈希函数的输出截断为 96 位(12 个字节) - 即保留哈希函数输出的前 12 个字节并丢弃剩余字节
  • 然后,将截断的输出以 base-64 编码为 16 个 ASCII 字符(128 位)
  • 有效地产生 96 位强加密哈希。

【讨论】:

  • 16 字节转换为 HEX 仍然是 32 个字符。您是否还可以提供一个链接来支持您关于截断部分计算哈希的断言是安全的,因为使用较低版本的哈希?这对于 SHA 可能是正确的(我不知道任何一种方式),但我认为您不能做出一个适用于所有哈希值的声明。
  • @Matthew Whited:我认为@Justice 的说法通常被认为是正确的。很难想象除了暴力破解之外,对截断的哈希值但对完整哈希值无效的攻击。
  • 您是说不能简单地将哈希字节存储为字节序列吗?您是否需要将字节编码为例如十六进制编码或 base64 编码?如果可以存储原始字节,则应存储原始字节,并占用所有 16 个字节的空间。
  • 我添加了一个指向另一个 SO 问题的链接,其标题是“是否可以将 SHA256 哈希截断为 128 位?”
  • 截断的散列明显弱于原始散列。您可以更轻松地破解截断的哈希,而无需对完整哈希进行攻击:csrc.nist.gov/groups/ST/hash/documents/Kelsey_Truncation.pdf
【解决方案2】:

您可以轻松地为此使用 MD5 哈希,但您必须更改它的存储方式。 MD5 为 128 位,通常显示为 32 个 4 位(十六进制)值。然而,一个标准的 char 是 8 位,因此 16 个字符正好足以存储 MD5 哈希的值。

要转换它,请尝试以下操作:

String hash32 = "d41d8cd98f00b204e9800998ecf8427e"
String hash16 = ""

for(int i = 0; i < 32; i+=2)
{
  uint high = Convert.ToUInt32(hash32[i], 16);
  uint low = Convert.ToUInt32(hash32[i+1], 16);
  char c = (char) ((high << 4) | low);

  hash16 += c;
}

【讨论】:

  • 使用 OR、XOR 或任何其他二进制函数会增加冲突的机会。如果您只是将其用于校验和,这可能会起作用,但使用 XOR 可能会更安全。否则,您不妨只使用奇偶校验。
  • 如果您注意到,我将一个始终为 4 个字节或更少的数字向左 4 个字节移动,因此低位和高位永远不会冲突。
【解决方案3】:

我注意到这个问题比较老,但我相信有人会发现这个答案很有价值。

我的建议是使用能够使用 8 位到 512 位的 Blake2b。如果不使用密钥大小,则在这种情况下使用默认值“512”。 Blake2s 默认值 256 位。

        // BLAKE2b
        // using System.Data.HashFunction;
        //
        // String message to use.
        string str = "The quick brown fox jumps over the lazy dog";
        // Initialize
        System.Data.HashFunction.Blake2B Blake2B = new System.Data.HashFunction.Blake2B();
        // Get string hash bytes; create 64 bit hash.
        var HashBytes = Blake2B.ComputeHash(str, 64);
        // Convert bytes to string and remove the dashes.
        string hexString = BitConverter.ToString(HashBytes).Replace("-", string.Empty);
        // Display results.
        MessageBox.Show(hexString);
        /*
         * "The quick brown fox jumps over the lazy dog" produces a hash value of
         * "A8ADD4BDDDFD93E4877D2746E62817B116364A1FA7BC148D95090BC7333B3673F82401CF7AA2E4CB1ECD90296E3F14CB5413F8ED77BE73045B13914CDCD6A918"
         * and "2FD0F3FB3BD58455" hash for 64 bits.
         */

希望这会有所帮助!

【讨论】:

    【解决方案4】:

    如果您有 16 个字节存储 128 位数字,则不是问题。将 128 位值存储为 16 字节值,而不是将 16 字节值存储为 HEX 的 32 个字符串。

    作为说明,我在数据库中使用了 GUID/UUID 字段来存储 MD5 哈希值。虽然不再具有加密安全性,但 128 位 MD5 散列适用于校验和(并且比 64 位要好得多。)

    var result = MD5.Create().ComputeHash(new byte[] { 0 });
    
    Console.WriteLine(result.Length);
    Console.WriteLine(Convert.ToBase64String(result));
    Console.WriteLine(result.Aggregate(new StringBuilder(),
                                        (sb, v) => sb.Append(v.ToString("x2"))));
    
    //16
    //k7iFrf4NoInN9jSQT9WfcQ==
    //93b885adfe0da089cdf634904fd59f71
    
    File.WriteAllBytes("tempfile.dat", result);
    
    var input = File.ReadAllBytes("tempfile.dat");
    
    Console.WriteLine(input.Length);
    Console.WriteLine(Convert.ToBase64String(input));
    Console.WriteLine(input.Aggregate(new StringBuilder(), 
                                        (sb, v) => sb.Append(v.ToString("x2"))));
    
    //16
    //k7iFrf4NoInN9jSQT9WfcQ==
    //93b885adfe0da089cdf634904fd59f71
    

    请注意,我没有显示文件内容,因为它很可能包含“不可打印”字符。

    【讨论】:

      【解决方案5】:

      有关于此代码的任何信息吗?看起来效果不错...

      var p = new MD5CryptoServiceProvider();
      var dic = new Dictionary<long, string>();
      
      for (var i = 0; i < 10000000; i++)
      {
          if (i%25000 == 0)
              Console.WriteLine("{0:n0}", i);
      
          var h = p.ComputeHash(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
          var b = BitConverter.ToInt64(h, 0);
      
          // "b" is hashed Int64
      
          if (!dic.ContainsKey(b))
              dic.Add(i, null);
          else
              throw new Exception("Oops!");
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-13
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 2012-09-03
        • 2012-02-25
        • 2012-08-09
        相关资源
        最近更新 更多