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

Yod*_*oda -3 java string hash md5 go

我正在用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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我想在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)
}
Run Code Online (Sandbox Code Playgroud)

我在两个代码示例中都添加了print语句.由于我是Go的新手,我不知道是否有其他库或方法可以这样做.我只是按照我在网上找到的.如果有人能帮忙解决这个问题真的很棒.

icz*_*cza 5

1.不同的循环

你的内环是不同的.

在Java中:

for (int j = 0; j < digest.length; j += 4) {
    System.out.print(digest[j]);
    output[i] ^= digest[i + j];
}
Run Code Online (Sandbox Code Playgroud)

在Go:

for j:=0; j < len(data); j++ {
    output[i] ^= data[i + j]
    fmt.Print(output[i])
}
Run Code Online (Sandbox Code Playgroud)

请注意,在Java中,您将循环变量增加4,并在Go中仅增加1.使用:

for j:=0; j < len(data); j += 4 {
    output[i] ^= data[i + j]
    fmt.Print(output[i])
}
Run Code Online (Sandbox Code Playgroud)

2.不同的返回数据

更新: Asker澄清说这只是发布代码中的一个拼写错误,从那时起被删除(已删除).

您的Java解决方案也会返回输出的十六进制表示:

return getHexString(output);
Run Code Online (Sandbox Code Playgroud)

但在Go中,您返回(完整)MD5摘要的十六进制表示:

return getHexString(md.Sum(nil))
Run Code Online (Sandbox Code Playgroud)

所以在Go中也做:

return getHexString(output)
Run Code Online (Sandbox Code Playgroud)

3.输入字符串=>字节序列转换

最后一点.在Java中,您使用US-ASCII编码将输入字符串转换为字节序列,而在Go中,您使用UTF-8输入字符串的编码序列,因为这是Go自然存储字符串的方式(因此,当您执行时,您将获得UTF-8字节序列[]byte("some text")).

这将导致仅使用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)
}
Run Code Online (Sandbox Code Playgroud)

字节表示差异

你说结果数组的内容是不同的.这是因为byteJava 中的类型是有符号的,它有一个范围-128..127,而在Go中byte是一个别名,uint8有一个范围0..255.因此,如果要比较结果,则必须将负Java值移动256(添加256).

如果将字节数组(或切片)转换为十六进制表示,则它将是相同的(十六进制表示没有"符号"属性).

你可以在这里阅读更多相关信息:用于HOTP的Java与Golang(rfc-4226)