我有一个用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以这种方式生成它:
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#散列值示例:
6wM7McddLBjofdFJ3rU6 /克==
我发布了Java产生的字符串示例,但它有一些非常奇怪的字符,我认为我不能在这里粘贴。
我做错了什么?
答案 0 :(得分:7)
这基本上是已损坏的代码:
// Badly broken
byte[] thedigest = md.digest(bytesOfPhrase);
this._AuthenticationToken = new String(thedigest, utf8Charset);
永远不要尝试通过将任意二进制数据传递给String构造函数来对其进行编码。 始终使用base64,或hex,或类似的东西。 Apache Commons Codec有一个Base64编码器,或者这个public domain version有一个更令人愉快的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
语句处理实例。我对此的主要偏好是,它比MD5
更容易记住,阅读和输入MD5CryptoServiceProvider
:)
您尚未明确_StringEncoding
是什么,但代码应该只使用Encoding.UTF8
来匹配Java。
答案 1 :(得分:3)
您的C#摘要位于Base64中,但您的Java摘要不是。将thedigest
转换为Base64。
答案 2 :(得分:0)
在C#中,您使用Base64对字节进行编码。在Java中,您将字节解释为UTF-8字符串。
答案 3 :(得分:0)
您的C#代码将MD5哈希输出为BASE64编码,但java代码不会。 比较两个MD5哈希值的通用方法是比较其十六进制表示(16bytes - > 32digits)。