7
package main

import (
    "crypto/md5"
    "fmt"
)

func main() {
    hash := md5.New()
    b := []byte("test")
    fmt.Printf("%x\n", hash.Sum(b))
    hash.Write(b)
    fmt.Printf("%x\n", hash.Sum(nil))
}

Output:

*md5.digest74657374d41d8cd98f00b204e9800998ecf8427e
098f6bcd4621d373cade4e832627b4f6

Could someone please explain to me why/how do I get different result for the two print ?

4

4 回答 4

12

我正在建立已经很好的答案。我不确定是否Sum真的是你想要的功能。从hash.Hash文档中:

// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte

这个函数有一个双重用例,你似乎以一种不幸的方式混合在一起。用例是:

  1. 计算单次运行的哈希
  2. 链接多次运行的输出

如果您只是想计算某物的哈希值,请使用md5.Sum(data)

digest := md5.New()
digest.Write(data)
hash := digest.Sum(nil)

根据上述文档的摘录,此代码将把 的校验和附加datanil,从而生成 的校验和data

如果你想链接几个哈希块,第二个用例hash.Sum,你可以这样做:

hashed := make([]byte, 0)
for hasData {
    digest.Write(data)
    hashed = digest.Sum(hashed)
}

这会将每个迭代的散列附加到已经计算的散列上。可能不是你想要的。

所以,现在您应该能够看到您的代码失败的原因。如果没有,请使用您的代码的此注释版本(On play):

hash := md5.New()
b := []byte("test")
fmt.Printf("%x\n", hash.Sum(b))             // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
fmt.Printf("%x\n", hash.Sum(nil))           // gives <hash> as append(nil, hash) == hash

fmt.Printf("%x\n", hash.Sum(b))             // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil))           // gives a completely different hash since internal bytes changed due to Write()
于 2014-06-15T23:57:47.943 回答
2

您有 2 种方法来实际获得md5.Sum一个字节切片:

func main() {
    hash := md5.New()
    b := []byte("test")
    hash.Write(b)
    fmt.Printf("way one : %x\n", hash.Sum(nil))
    fmt.Printf("way two : %x\n", md5.Sum(b))
}

根据http://golang.org/src/pkg/crypto/md5/md5.go#L88,你hash.Sum(b)就像打电话一样append(b, actual-hash-of-an-empty-md5-hash)

的定义Sum

func (d0 *digest) Sum(in []byte) []byte {
    // Make a copy of d0 so that caller can keep writing and summing.
    d := *d0
    hash := d.checkSum()
    return append(in, hash[:]...)
}

当您调用Sum(nil)它时,它d.checkSum()直接作为字节切片返回,但是如果您调用Sum([]byte)它,它会附加d.checkSum()到您的输入中。

于 2014-06-15T22:13:18.120 回答
1

从文档:

    // Sum appends the current hash to b and returns the resulting slice.
    // It does not change the underlying hash state.
    Sum(b []byte) []byte

所以“*74657374*d41d8cd98f00b204e9800998ecf8427e”实际上是“test”的十六进制表示,加上哈希的初始状态。

fmt.Printf("%x", []byte{"test"})

将导致...“74657374”!

所以基本上hash.Sum(b)没有做你认为它做的事情。第二个语句是正确的哈希。

于 2014-06-15T22:03:07.517 回答
0

我想直接告诉你:

为什么/如何获得两个打印的不同结果?

答:

hash := md5.New()

当你创建一个新的 md5 实例时,hash你调用hash.Sum(b)它实际上是 md5 哈希,b因为hash它本身是空的,因此你得到了74657374d41d8cd98f00b204e9800998ecf8427e输出。

现在在下一条语句中hash.Write(b),您正在写b入哈希实例,然后调用hash.Sum(nil)它将计算b您刚刚写入的 md5 并将其与前一个值相加,即74657374d41d8cd98f00b204e9800998ecf8427e

这就是您获得这些输出的原因。

供您参考,请查看SumAPI:

func (d0 *digest) Sum(in []byte) []byte {
85      // Make a copy of d0 so that caller can keep writing and summing.
86      d := *d0
87      hash := d.checkSum()
88      return append(in, hash[:]...)
89  }
于 2017-03-09T12:48:17.933 回答