我正在用 Java 创建 MD5 摘要,这是计算输入字符串的 4 字节十六进制散列所必需的。以下是 Java 中的代码:
public static String hashString(String s) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(s.getBytes("US-ASCII"));
byte[] output = new byte[digest.length / 4];
for (int i = 0; i < output.length; i++) {
for (int j = 0; j < digest.length; j += 4) {
System.out.print(digest[j]);
output[i] ^= digest[i + j];
}
}
return getHexString(output);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
return null;
}
}
我想在 Golang 中使用相同的代码,但是,MD5 输出与我在 Java 中得到的不同。下面是 Go 中的代码:
func hashString(s string) string {
md := md5.New()
md.Write([]byte(s))
data := md.Sum(nil)
fmt.Println(data)
output := make([]byte, len(data)/4)
for i := 0; i < len(output); i++ {
for j:=0 ;j < len(data); j++ {
output[i] ^= data[i + j]
fmt.Print(output[i])
}
}
return getHexString(output)
}
我在两个代码示例中都添加了打印语句。由于我是 Go 的新手,我不知道是否有任何其他库或方法可以这样做。我只是按照我在互联网上找到的内容进行操作。如果有人可以提供帮助,那就太好了。
最佳答案
1。不同的循环
您的内部循环不同。
在 Java 中:
for (int j = 0; j < digest.length; j += 4) {
System.out.print(digest[j]);
output[i] ^= digest[i + j];
}
在围棋中:
for j:=0; j < len(data); j++ {
output[i] ^= data[i + j]
fmt.Print(output[i])
}
请注意,在 Java 中您将循环变量递增 4,而在 Go 中仅递增 1。使用:
for j:=0; j < len(data); j += 4 {
output[i] ^= data[i + j]
fmt.Print(output[i])
}
2。返回数据不同
更新:Asker 澄清说这只是发布代码中的错别字,此后已被删除(编辑掉)。
您的 Java 解决方案还返回输出的十六进制表示形式:
return getHexString(output);
但在 Go 中,您返回(完整)MD5 摘要的十六进制表示:
return getHexString(md.Sum(nil))
所以在 Go 中也这样做:
return getHexString(output)
3。输入字符串=>字节序列转换
最后一点。在 Java 中,您使用 US-ASCII
编码将输入字符串转换为字节序列,而在 Go 中,您使用输入字符串的 UTF-8
编码序列,因为这就是 Go 自然地存储字符串的方式(所以当你执行 []byte("some text")
时你会得到 UTF-8 字节序列)。
对于仅使用 ASCII 表字符(其代码小于 128)的文本,这将导致相同的输入数据,但对于包含高于该字符的文本(因为它们将转换为多字符),将导致不同的数据UTF-8 中的字节序列)。有一点要记住!
简化
另请注意,要计算某些数据的 MD5 摘要,您可以简单地使用 md5.Sum()
功能,因为您要丢弃创建的 hash.Hash
无论如何:
func hashString(s string) string {
dataArr := md5.Sum([]byte(s))
data := dataArr[:]
fmt.Println(data)
output := make([]byte, len(data)/4)
for i := 0; i < len(output); i += 4 {
for j := 0; j < len(data); j++ {
output[i] ^= data[i+j]
fmt.Print(output[i])
}
}
return getHexString(output)
}
字节表示差异
你说结果数组的内容不同。这是因为 Java 中的 byte
类型是有符号的,它的范围是 -128..127
,而 Go 中的 byte
是 uint8
的别名,范围是 0..255
。所以如果你想比较结果,你必须将负的 Java 值移动 256(加 256)。
如果将字节数组(或 slice )转换为十六进制表示,它将是相同的(十六进制表示没有“符号”属性)。
您可以在这里阅读更多相关信息:Java vs. Golang for HOTP (rfc-4226)
关于java - Go 中 String 的 MD5 摘要与 Java 不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51840459/