C#和Kotlin(Java)中的MD5哈希码

Pav*_*vel 0 c# java md5 kotlin

我正在为Kotlin(Java)和C#中MD5结果消耗的差异而苦苦挣扎。我发现这篇文章建议解决方案:

如何在C#和Java中生成相同的MD5哈希码?

但我想了解其背后的逻辑。我已经做了几次测试。C#:

var data = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("123456"));
var s = Encoding.UTF8.GetString(data, 0, data.Length);
Run Code Online (Sandbox Code Playgroud)

产生以下字节序列(数据变量):

 225, 10, 220, 57, 73, 186, 89, 171, 190, 86, 224, 87, 242, 15, 136, 62
Run Code Online (Sandbox Code Playgroud)

如果我使用Kotlin(Java):

val md = MessageDigest.getInstance("MD5")
val data = md.digest("123456".toByteArray())

val s = String(data)

val ls2 = data.map { x-> x.toUByte() }
Run Code Online (Sandbox Code Playgroud)

因此,Java具有带符号的字节,而c#是无符号的(ls2-包含与c#示例相同的无符号字节)。精细。我想获取字符串值-我将两个字节数组都转换为字符串,并且得到了不同的字符串(s变量)。我想念什么?

谢谢。

can*_*on7 5

在C#中,您尝试使用UTF-8编码将字节转换为字符串。但是,这是一个非常糟糕的主意-有许多字节序列在UTF-8编码的字符串中无效,并且进一步的序列将导致无法打印的字符。如果编码器遇到的字节序列不构成有效的UTF-8编码字符(并且会这样做,因为您没有做任何事情来确保字节序列是有效的UTF-8编码的字符串),它将插入一个替换字符。

在Kotlin中,您可以使用new String(byte[])使用系统编码的方式。您在这里遇到了类似的问题:尽管大多数字节将产生一个有效字符,但其中某些字符将无法打印。

因此,您为C#和Kotlin使用两种不同的编码(因此结果不同),但是您正在做一些可能会给您带来无法打印的字符的操作,或者可能用替换字符替换字节序列(因此,不同的MD5散列看起来相同)。

(请注意,“无法打印的字符”可能只是看不见,但它们可能会做一些奇怪的事情,例如反转该页面上的文本方向,或开始将它们周围的字符连在一起!)

您最好将字节转换为base64字符串或十六进制字符序列。两者都确保以一种在不同语言之间保持一致的方式,将每个可能的字节序列转换为可打印的字符。

对于C#,可使用Convert.ToBase64String(data)获取base64编码的字符串,以及BitConverter.ToString(data).Replace("-","")获取十六进制编码的字符串(尽管有很多方法可以做到这一点)。

对于Kotlin,可使用Base64.getEncoder().encodeToString(data)来获取base64编码的字符串,并data.joinToString("") { "%02x".format(it) }获取十六进制编码的字符串。