java - Go 中 String 的 MD5 摘要与 Java 不同

标签 java string go hash md5

我正在用 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 中的 byteuint8 的别名,范围是 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/

相关文章:

json - 从结构中删除字段或将其隐藏在JSON响应中

string - 查找列表中最长项目长度的最有效方法是什么?

c++ - 有没有办法对从字符串 cpp 转换而来的整数执行算术

java - 加密字节数组到图像

Java 和 FTP 服务器

c - 使用替代终止字符执行 strcmp 的标准方法?

go - 我应该如何在 Go 中定义一个空 slice ?

xml - 有没有办法只在 go xml 包中编码 XML 开始标记?

java - spring boot使用哪个 'slice'来测试服务组件

java - JAVA中从字符串中获取特定子字符串