Java MD5哈希与.NET哈希不匹配

Java MD5哈希与.NET哈希不匹配,java,hash,md5,Java,Hash,Md5,我有一个用C语言编写的Web服务,它处理一些值的验证。在其中,我需要检查在调用Java客户机中生成的MD5哈希 Java客户机以这种方式生成散列 Charset utf8Charset = Charset.forName("UTF-8"); byte[] bytesOfPhrase = phrase.getBytes(utf8Charset); MessageDigest md = MessageDigest.getInstance("MD5"); byte[] thedigest = md

我有一个用C语言编写的Web服务,它处理一些值的验证。在其中,我需要检查在调用Java客户机中生成的MD5哈希

Java客户机以这种方式生成散列

Charset utf8Charset = Charset.forName("UTF-8");

byte[] bytesOfPhrase = phrase.getBytes(utf8Charset);
MessageDigest md = MessageDigest.getInstance("MD5");

byte[] thedigest = md.digest(bytesOfPhrase);
this._AuthenticationToken = new String(thedigest, utf8Charset);
C#webservice以以下方式生成其has:

private static string HashString(string toHash)
{
    MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();

    byte[] hashedBytes = md5Provider.ComputeHash(_StringEncoding.GetBytes(toHash));
    return Convert.ToBase64String(hashedBytes);
}
我在Java代码中尝试了几个字符集,但没有一个生成的字符串与Java生成的字符串类似。在每次调用中使用相同的硬编码值(这意味着我已经硬编码了参数,所以散列应该匹配)仍然会产生一个奇怪的Java字符串

C#散列值示例:

6WM7MCDDLBJDFJ3RU6/g==

我会发布Java生成的字符串示例,但它有一些非常奇怪的字符,我认为我不能粘贴到这里

我做错了什么?

您的C#摘要在Base64中,但您的Java摘要不是。将最基本的也转换为Base64。

在C#中,使用Base64对字节进行编码。在Java中,您将字节解释为UTF-8字符串。

这是一段根本不正确的代码:

永远不要试图通过将任意二进制数据传递给字符串构造函数来对其进行编码。始终使用base64、hex或类似的东西。有一个Base64编码器,或者这有一个稍微好一点的API

等效的C#为:

// Equally broken
byte[] hashedBytes = md5Provider.ComputeHash(Encoding.UTF8.GetBytes(toHash));
return Encoding.UTF8.GetString(hashedBytes);
MD5摘要生成的二进制数据实际上是有效的UTF-8字节序列的可能性有多大

还有两件事需要注意:

  • 您可以使用
    MD5
    类在.NET中更简单地获得MD5哈希:

    byte[] hash;
    using (MD5 md5 = MD5.Create())
    {
        hash = md5.ComputeHash(bytes);
    }
    // Use hash
    
    请注意使用
    using
    语句在以后处理实例。我的主要偏好是,它比
    MD5CryptoServiceProvider
    更容易记忆、阅读和键入
    MD5

  • 您还没有明确说明什么是
    \u StringEncoding
    ,但是代码实际上应该使用
    Encoding.UTF8
    来匹配Java

您的C#代码将MD5哈希输出为BASE64编码,但java代码不会。
比较两个MD5哈希的一般方法是比较其十六进制表示形式(16字节->32位)。

您能更深入地解释一下吗?我正在尝试执行以下操作:this.\u AuthenticationToken=new sun.misc.BASE64Encoder().encode(thedigest);但是我得到了一个错误:访问限制:由于对所需库C:\Program Files\Java\jre6\lib\rt.jar的限制,无法访问CharacterEncoder类型中的方法encode(字节[]),我是否仍然缺少一些内容?@Mike G:是的,您不打算使用sun.*类。有关Java中base64编码的另外两个选项,请参见我答案中的链接。您还应该在MD5上调用
Dispose
(或者使用
)调用
)。这会带来一些安全隐患,如果您使用的是
*CryptoServiceProvider
实现,则会释放一些非托管解析。\u StringEncoding实际上是UTF8。对不起,我的示例顶部没有包含它。我需要在校对方面做得更好。快速提问,因为我有点困惑。在您的C代码中,它似乎不再是base64字符串,因此它将与上面的java代码匹配,对吗?在这种情况下,我不需要在Java客户机中使用base64字符串,同样正确吗?@Mike G:我给出的唯一C#代码是显式断开的代码,并替换执行哈希本身的位。如果您需要使用文本进行通信,base64是在两个客户端中都可以使用的方法。@Jon嗯,我认为这是一个很好的解决方案,但当它在Cognos中运行时,我无法以某种方式引用Apache Commons编解码器。不将这些值转换为base64有什么坏处吗?@Mike:你还没有告诉我们你在用这些散列值做什么。你需要把它们当作弦吗?如果是这样,您必须找到一些安全的转换,base64或hex是显而易见的选择。你也尝试过我链接的公共域代码吗?
byte[] hash;
using (MD5 md5 = MD5.Create())
{
    hash = md5.ComputeHash(bytes);
}
// Use hash