Java MD5编码器与C#MD5CryptoServiceProvider不匹配

时间:2015-01-29 13:50:23

标签: java c# md5 encode

我正在尝试生成C# MD5CryptoServiceProvider来编码字符串和Java MessageDigest.getInstance("MD5")来编码字符串,但两个输出都不同。 stackoverlflow上已经有很多样本可用,但仍然停留在某些地方。

以下是我的C#代码:

MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
    Byte[] hashedDataBytes = null;
    UTF8Encoding encoder = new UTF8Encoding();

    hashedDataBytes = md5Hasher.ComputeHash(encoder.GetBytes("NSI#1234@"));
    string strPassword = string.Empty;
    foreach (byte b in hashedDataBytes)
    {
        strPassword = strPassword + b.ToString();
    }
    return strPassword;

C#代码是冻结代码,我无权更改此代码。

以下是我的Java代码:

MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] digest = messageDigest.digest("NSI#1234@".getBytes("UTF-8"));
String hash = new BigInteger(1, digest).toString();
System.out.println(hash);

C#代码输出:158163028351382321031971922721528189209213

Java代码输出:210864369951346339831795420458152481237

C#生成42个数字,java生成39个数字。如果我更改new BigInteger(1, digest).toString(8)的值,则会生成43个数字,如果我更改new BigInteger(1, digest).toString(9),则会生成41个数字。

2 个答案:

答案 0 :(得分:3)

您的C#代码您的Java代码都不是将哈希转换为字符串的好方法。我强烈怀疑你在两种情况下都有相同的字节,但是你将它们转换为不同的字符串。

您的C#代码只是将每个字节转换为十进制表示。 (它也是通过重复的字符串连接来实现的.Ick。)你的Java代码将忽略前导0并且当前正在使用小数。您可以调用toString(16)来生成十六进制,但它仍然会忽略前导零。

如果您确实需要十六进制,可以使用BitConverter.ToString(byte[])在.NET中获取十六进制表示,尽管您可能希望删除它将放在每个字节之间的-;在Java中,有各种可用的库,例如Apache Commons CodecHex)或GuavaBaseEncoding.base16())。或者在Stack Overflow上使用Java中的许多答案中的一些代码来编写十六进制编码such as this one

或者,您可以使用Base64 - 再次,有多个选项可用,例如.NET中的BitConverter.ToBase64String和Java的iharder public domain library

如果您的C#代码真正被冻结(运行到山上!)那么等效的(好的,稍微清晰的)Java代码将是这样的:

StringBuilder builder = new StringBuilder();
for (byte b : digest) {
    builder.append(b & 0xff); // Convert signed to unsigned
}

如果您使用的是Java 7 +,我还建议您使用StandardCharsets.UTF_8

但是如果可能可以,我会强烈建议修复C#代码。即使你处于“代码冻结”状态,大概也不会禁止你修复重要的错误 - 如果你存储这些值,那么现在解决这个问题要容易得多。它会在以后这样做。

答案 1 :(得分:2)

正确的哈希

我在控制台上检查了正确的值:

$ export LC_ALL=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ export LANGUAGE=en_US.UTF-8
$ echo -n "NSI#1234@" | md5sum.exe
9ea3001c238ae867c5c01bd71cbdd1d5 *-

因此,您的Java代码的结果是正确的,它没有正确显示(见下文)。

Java代码中的问题

您的Java代码没问题,它只是将结果格式错误:它将结果显示为十进制数,而不是通常用于哈希的十六进制表示。

您应该在显示之前将数字转换为十六进制:

// [your code from above]

String hex=new BigInteger(1, digest).toString(16); // Hex, but without leading zeros
String fill=String.format("%0" + 32 + "d", 0) // This is ugly...
String hash=(fill+hex).substring(hex.length()) // ... and this is a hack to add leading zeros

C#代码中的问题

您的C#代码连接了每个字节的十进制表示。虽然这适用于十六进制数字(只要在每一步中添加前导零!),它根本不适用于十进制数字。所以C#代码是错误的,你必须修复它。

更好地使用.NET提供的转换器,它更快,并且可以正常工作:

// [your code from above]

string hex = BitConverter.ToString(hashedDataBytes).Replace("-", string.Empty);