我们正在生成哈希值,以便为存储在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的能力视为“唯一”?
答案 0 :(得分:2)
X-Y problem - 而不是将字节数组转换为已知使用UTF8作为编码正确处理为Base64(或类似字符串)字符串的版本。
将随机字节数组作为UTF8字符串读取将具有不可打印和0
字符以及由于错误的UTF8序列导致的随机失败。
使用Base64(如果需要不区分大小写的字符串,则使用base32)。如果仍然不支持某些字符 - 请替换为其他字符。即URL-friendly base64使用-
,_
并且没有填充来简化编码作为查询参数。
原始问题:
答案 1 :(得分:2)
你增加了碰撞的概率,但只是略有增加。所有" /"在输出哈希中就像是'通配符'哪个匹配" /"或" \"在原始哈希中。如果哈希中没有这些,则没有任何变化。如果您在散列中有其中一个,那么现在有两倍的文档可以匹配该散列。如果你有两个哈希值,那么就有四倍。考虑到字母表和MD5哈希的长度,有更多的东西是不可能的。
碰撞的可能性仍然很小(除非你有大量的文件等)。
但是,您应该执行注释中建议的操作,并使用Base64或HEX字符串来存储MD5。
当你自己推出自己的密码时,加密会发生不好的事情。并尝试修改您从未对内部了解的协议。你应该始终坚持做标准的事情,这些事情在理论上和实践中经过了测试,并且被认为是合理的。 Bruce Schneier在 Practical Cryptography 和其他地方详细阐述了这一原则。
答案 2 :(得分:1)
使用Base64代替UTF8,您将解决您的问题(不再需要/).