Java MD5哈希与C# MD5哈希不匹配

4

我知道很少关于加密和哈希。

我需要对一个加密密钥进行哈希。Java中的示例如下:

String encryptionKey = "test";

    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    messageDigest.update(encryptionKey.getBytes("UTF-8"), 0, encryptionKey.length());
    byte[] encryptionKeyBytes = messageDigest.digest();

请纠正我如果我错了,上述代码使用MD5算法对字符串进行哈希。

当我在C#中使用相同的字符串进行哈希时,我想得到相同的结果。

我的当前C#代码如下...

string encryptionKey = "test";

        var md5 = MD5.Create();
        var keyBytes = Encoding.UTF8.GetBytes(encryptionKey);
        byte[] encryptionKeyBytes = md5.ComputeHash(keyBytes);

但是最终的字节结果不匹配。

Java得到的...

[0] 9   
[1] -113    
[2] 107 
[3] -51 
[4] 70  
[5] 33  
[6] -45 
[7] 115 
[8] -54 
[9] -34 
[10]    78  
[11]    -125    
[12]    38  
[13]    39  
[14]    -76 
[15]    -10 

C# 获取...

    [0] 9   byte
    [1] 143 byte
    [2] 107 byte
    [3] 205 byte
    [4] 70  byte
    [5] 33  byte
    [6] 211 byte
    [7] 115 byte
    [8] 202 byte
    [9] 222 byte
    [10]    78  byte
    [11]    131 byte
    [12]    38  byte
    [13]    39  byte
    [14]    180 byte
    [15]    246 byte

我需要我的C#代码得到与Java代码相同的结果(不是反过来),有什么建议吗?

谢谢。


3
Java的字节是有符号的,而C#的字节则没有。需要注意的是,只有在Java字节为负数的情况下才会出现问题。 - vcsjones
除了相同的结果外,您在Java代码中有一个非常严重的错误:encryptionKey.getBytes("UTF-8"), 0, encryptionKey.length()。我留给您自己去找出错误是什么。最后,直接比较字符串表示(toString)总是一个不好的主意。 - bestsss
@bestsss 我正在使用断点来检查值。我认为断点值是由 toString 表示产生的(可能是错误的)。你会如何比较字节值? - Theo
无符号十六进制通常是将byte[]表示为规范,因为您可以轻松地查看两个nibbles。顺便问一下,您找到错误在哪里了吗? - bestsss
@bestsss,它使用byte[]数组来存储数据,而长度是从字符串中获取的(而不是从byte[]中获取)。这是你指出的问题吗?如果不是,我就不知道了。那段Java代码是一个加密/解密演示,发给我的。我需要编写相应的C#代码以获得相同的结果。 - Theo
是的,utf8 byte[] 的长度可以比源字符串更长。 - bestsss
1个回答

11

实际上,结果是相同的。和其他整数类型一样,byte值可以被解释为有符号或无符号。例如,如果将10001111解释为无符号类型,则对应于143(您的第二个C#值)。但是,如果解释为有符号类型(使用二进制补码),其值将为-113(您的第二个Java值)。

因此,差异似乎是由于在Java中使用有符号格式而在C#中使用无符号格式导致的。如果您想在C#中获得带符号的字节,请使用以下代码:

sbyte[] encryptionKeyBytesSigned = 
    encryptionKeyBytes.Select(b => (sbyte)b).ToArray();

然而,请注意这不仅仅是一个格式问题,只有在显示值时才会出现。当保存到文件时,两个结果应该是相同的。


谢谢你的回答...如果我理解正确,最后那句话似乎有矛盾之处。如果你将两者都保存到文件中并且它们是相同的,那么当你显示这些值时,它只是一个格式问题。你能澄清一下吗?我将使用这个哈希值(在byte[]中)作为加密密钥。所以如果这只是一个显示问题,我认为它不需要转换就可以正常工作。我不认为加密函数会接受sbyte[]而不是byte[]。 - Theo
没事。你只是提醒我检查并确保一下。我明白了。 - Theo
@Theo: 是的,我认为这是一个格式问题,当保存到文件时,即使不将C#值转换为有符号字节,生成的文件也应该是相同的。然而,说实话,我对Java并不是那么熟悉(我只能为你的C#代码担保),所以我会进行一些测试来确保。 - Douglas
你关于格式问题是正确的。当写入文件时,两者都显示相同的乱码字符。谢谢你的帮助。 - Theo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接