【问题标题】:Generate Unique Hash code based on String基于String生成唯一哈希码
【发布时间】:2021-06-15 05:43:35
【问题描述】:

我有以下两个字符串:

var string1 = "MHH2016-05-20MASTECH HOLDINGS, INC. Financialshttp://finance.yahoo.com/q/is?s=mhhEDGAR Online FinancialsHeadlines";

var string2 = "CVEO2016-06-22Civeo upgraded by Scotia Howard Weilhttp://finance.yahoo.com/q/ud?s=CVEOBriefing.comHeadlines";

乍一看这两个字符串是不同的,但是它们的哈希码使用GetHashCode method是相同的。

var hash = 0;
var total = 0;
foreach (var x in string1) //string2
{
    //hash = x * 7;
    hash = x.GetHashCode();
    Console.WriteLine("Char: " +  x + " hash: " + hash + " hashed: " + (int) x);
    total += hash;
}

两个字符串的总计最终为 620438779。是否有另一种方法可以返回更独特的哈希码?我需要哈希码根据字符串中的字符是唯一的。尽管两个字符串不同并且代码可以正常工作,但这两个字符串恰好加起来是相同的。如何改进此代码以使其更加独特?

【问题讨论】:

  • 您确实意识到,不是吗,您不能保证所有可能的字符串都有唯一的哈希码?哈希码是 32 位,这意味着有 40 亿(和变化)可能的值。您的两个字符串中的每一个都超过 120 个字符。使用 96 个可打印 ASCII 字符的可能 120 个字符的字符串数量要多得多。碰撞是不可避免的。 一般情况下不存在唯一哈希码。使哈希码变大会减少碰撞的机会,但不会消除它。
  • 您的问题暗示您正在尝试使用哈希码作为唯一标识符。这是一个非常糟糕的主意,注定要失败。 @AlexD 的回答解释了原因。
  • @JimMischel 是的,我现在知道了,但谢谢
  • 老问题,我知道,看我3年前的问题和答案:stackoverflow.com/questions/15377161/…

标签: c#


【解决方案1】:

string.GetHashCode 确实不适合真正的散列:

警告

哈希码用于在基于哈希表的集合中进行高效插入和查找。哈希码不是永久值。出于这个原因:

  • 不要序列化哈希码值或将它们存储在数据库中。
  • 请勿使用哈希码作为键从键控集合中检索对象。
  • 不要使用散列码代替加密散列函数返回的值。对于加密哈希,请使用派生自 System.Security.Cryptography.HashAlgorithmSystem.Security.Cryptography.KeyedHashAlgorithm 类的类。
  • 不要测试哈希码的相等性以确定两个对象是否相等。 (不相等的对象可以有相同的哈希码。)要测试相等,请调用ReferenceEqualsEquals 方法。

并且很有可能是duplicates

考虑HashAlgorithm.ComputeHash。正如 @zaph 建议的那样,该示例稍作更改以使用 SHA256 而不是 MD5:

static string GetSha256Hash(SHA256 shaHash, string input)
{
    // Convert the input string to a byte array and compute the hash.
    byte[] data = shaHash.ComputeHash(Encoding.UTF8.GetBytes(input));

    // Create a new Stringbuilder to collect the bytes
    // and create a string.
    StringBuilder sBuilder = new StringBuilder();

    // Loop through each byte of the hashed data 
    // and format each one as a hexadecimal string.
    for (int i = 0; i < data.Length; i++)
    {
        sBuilder.Append(data[i].ToString("x2"));
    }

    // Return the hexadecimal string.
    return sBuilder.ToString();
}

【讨论】:

  • @lexx9999 我认为帖子中的链接已经指向相同的算法。
  • 当我阅读它时,它不包括 GetMd5Hash/VerifyMd5H​​ash
  • 这会导致性能下降,安全散列并不是用来避免冲突的。
  • @SirajMansour 加密哈希确实是为避免冲突而设计的。在我的 iPhone 上,我可以在 0.950 毫秒内计算 1MB 文件的 SHA-256 哈希值,速度够快吗?顺便说一句,SHA-256 在我的手机上比 MD5 略快。
【解决方案2】:
using System.Security.Cryptography;
string data="test";
byte[] hash;
using (MD5 md5 = MD5.Create())
{
    md5.Initialize();
    md5.ComputeHash(Encoding.UTF8.GetBytes(data));
    hash = md5.Hash;
}

hash 是一个 16 字节的数组,您可以将其转换为一些 hex-string 或 base64 编码的字符串进行存储。

编辑:

该哈希码的用途是什么?

hash(x) != hash(y) 你可以推导出x!=y,但是

hash(x) == hash(y)不能一般推导出x==y

【讨论】:

  • 这会导致性能下降,安全散列并不是用来避免冲突的。
  • @somerandomdude,与每个哈希函数一样,您必须比较原始数据,以防万一您想绝对确定,您可以尝试其他哈希算法,但您必须始终期待冲突。这就是from hash(x) == hash(y) you canNOT derive x==y in general! 的意思。
  • 不应使用 MD5,它不安全,请使用 SHA-2 哈希,例如 SHA-256。通常 SHA-256 比 MD5 慢一点。
  • @zaph 它们是为安全目的而设计的。虽然它可以达到避免碰撞的目标,但这并不意味着它是正确的工具。
  • @zaph 你认为请求路由到基于散列对象的分片数据存储会使用加密散列吗?你需要做一些阅读伙伴。我猜那些设计像 Murmur、FNV、SuperFastHash 这样的非加密哈希算法的人都错了,他们都应该相信你的话。
猜你喜欢
  • 1970-01-01
  • 2014-12-31
  • 2010-12-01
  • 2014-05-11
  • 2013-07-29
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多