如果我替换MD5哈希中的字符,是否会增加冲突的可能性?

时间:2014-06-11 15:54:24

标签: c# hash md5 ravendb

我们正在生成哈希值,以便为存储在RavenDB中的文档提供标识符。我们这样做是因为如果你想像这样使用BulkInsert,DocumentID的长度有限制(127个字符 - ESent limitation):

 _documentStore.BulkInsert(options: new BulkInsertOptions { CheckForUpdates = true }))

为了使BulkInsert工作,DocumentID需要匹配被插入的行;所以我们想要一个可以从相同的源字符串一致地重新生成的DocumentID。

MD5哈希将为我们提供一个具有较低冲突概率的固定长度值,其代码用于生成下面的哈希值:

public static string GetMD5Hash(string inputString)
{
    HashAlgorithm algorithm = MD5.Create();

    var hashBytes = algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));

    return Encoding.UTF8.GetString(hashBytes);
}

然而; RavenDB不支持DocumentID中的“\”;所以我想用“/”替换它。然而,我担心这样做会增加散列冲突的可能性。

我想改为代码:

public static string GetMD5Hash(string inputString)
{
    HashAlgorithm algorithm = MD5.Create();

    var hashBytes = algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));

    return Encoding.UTF8.GetString(hashBytes).Replace('\\', '"');
}

这是否会增加哈希冲突的可能性,并将我们依赖DocumentID的能力视为“唯一”?

3 个答案:

答案 0 :(得分:2)

X-Y problem - 而不是将字节数组转换为已知使用UTF8作为编码正确处理为Base64(或类似字符串)字符串的版本。

将随机字节数组作为UTF8字符串读取将具有不可打印和0字符以及由于错误的UTF8序列导致的随机失败。

使用Base64(如果需要不区分大小写的字符串,则使用base32)。如果仍然不支持某些字符 - 请替换为其他字符。即URL-friendly base64使用-_并且没有填充来简化编码作为查询参数。

原始问题:

  • 任何类型的哈希都不能被视为"唯一ID"由于可能发生碰撞而导致的文件。
  • 是将一个字符替换为已经可以在字符串中使用的另一个字符将减少可能的组合数量并增加碰撞的可能性。我无法正确估算 - 如果您真的需要精确答案,可能需要数学或统计特定问题。

答案 1 :(得分:2)

你增加了碰撞的概率,但只是略有增加。所有" /"在输出哈希中就像是'通配符'哪个匹配" /"或" \"在原始哈希中。如果哈希中没有这些,则没有任何变化。如果您在散列中有其中一个,那么现在有两倍的文档可以匹配该散列。如果你有两个哈希值,那么就有四倍。考虑到字母表和MD5哈希的长度,有更多的东西是不可能的。

碰撞的可能性仍然很小(除非你有大量的文件等)。

但是,您应该执行注释中建议的操作,并使用Base64或HEX字符串来存储MD5。

当你自己推出自己的密码时,加密会发生不好的事情。并尝试修改您从未对内部了解的协议。你应该始终坚持做标准的事情,这些事情在理论上和实践中经过了测试,并且被认为是合理的。 Bruce Schneier在 Practical Cryptography 和其他地方详细阐述了这一原则。

答案 2 :(得分:1)

使用Base64代替UTF8,您将解决您的问题(不再需要/).

查看Convert.ToBase64String