Golang的md5 Sum()函数

huangapple go评论72阅读模式
英文:

Golang md5 Sum() function

问题

这段代码使用了MD5哈希算法对字符串"test"进行处理,并输出了两个不同的结果。

首先,代码创建了一个MD5哈希对象hash := md5.New()。

然后,将字符串"test"转换为字节数组b := []byte("test")。

接下来,通过hash.Sum(b)计算了哈希值,并使用fmt.Printf("%x\n", hash.Sum(b))将结果以十六进制格式打印出来。这里的输出是*md5.digest74657374d41d8cd98f00b204e9800998ecf8427e。

然后,代码调用hash.Write(b)将字节数组b写入到哈希对象中。

最后,通过hash.Sum(nil)计算了哈希值,并使用fmt.Printf("%x\n", hash.Sum(nil))将结果以十六进制格式打印出来。这里的输出是098f6bcd4621d373cade4e832627b4f6。

两次计算的结果不同是因为在第一次计算后,哈希对象hash已经被修改了,包含了字节数组b的哈希值。所以在第二次计算时,需要重新调用hash.Sum(nil)来计算新的哈希值。

希望能帮到你!如果还有其他问题,请随时提问。

英文:
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 ?

答案1

得分: 13

我正在构建已有的好答案。我不确定Sum是否是你想要的函数。根据hash.Hash的文档:

// Sum将当前哈希附加到b并返回结果切片。
// 它不会更改底层哈希状态。
Sum(b []byte) []byte

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

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

如果你只是想计算某个东西的哈希值,可以使用md5.Sum(data)或者

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

根据上面文档的摘录,这段代码会将data的校验和附加到nil上,得到data的校验和。

如果你想链接多个哈希块,也就是hash.Sum的第二种用法,可以这样做:

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

这样会将每次迭代的哈希值附加到已计算的哈希值上。可能不是你想要的。

所以,现在你应该能看到你的代码为什么失败了。如果还不清楚,可以参考你代码的注释版本(在play中查看):

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

fmt.Printf("%x\n", hash.Sum(b))             // 输出 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // 输出 414141<hash> (41 = 'A')
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil))           // 输出完全不同的哈希值,因为内部字节由于Write()而改变
英文:

I'm building up on the already good answers. I'm not sure if Sum is actually the function you want. From the hash.Hash documentation:

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

This function has a dual use-case, which you seem to mix in an unfortunate way. The use-cases are:

  1. Computing the hash of a single run
  2. Chaining the output of several runs

In case you simply want to compute the hash of something, either use md5.Sum(data) or

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

This code will, according to the excerpt of the documentation above, append the checksum of data to nil, resulting in the checksum of data.

If you want to chain several blocks of hashes, the second use-case of hash.Sum, you can do it like this:

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

This will append each iteration's hash to the already computed hashes. Probably not what you want.

So, now you should be able to see why your code is failing. If not, take this commented version of your code (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()

答案2

得分: 2

你有两种方法可以获取一个字节切片的md5.Sum的实际值:

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

根据http://golang.org/src/pkg/crypto/md5/md5.go#L88,你的hash.Sum(b)就像调用append(b, 空md5哈希的实际哈希值)

Sum的定义如下:

func (d0 *digest) Sum(in []byte) []byte {
    // 复制d0,以便调用者可以继续写入和求和。
    d := *d0
    hash := d.checkSum()
    return append(in, hash[:]...)
}

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

英文:

You have 2 ways to actually get a md5.Sum of a byte slice :

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))
}

According to http://golang.org/src/pkg/crypto/md5/md5.go#L88, your hash.Sum(b) is like calling append(b, actual-hash-of-an-empty-md5-hash).

The definition of 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[:]...)
}

When you call Sum(nil) it returns d.checkSum() directly as a byte slice, however if you call Sum([]byte) it appends d.checkSum() to your input.

答案3

得分: 1

从文档中可以看到:

// Sum将当前哈希附加到b并返回结果切片。
// 它不会更改底层哈希状态。
Sum(b []byte) []byte

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

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

的结果是"74657374"!

所以基本上hash.Sum(b)并不是你认为的那样。第二个语句才是正确的哈希。

英文:

From the docs:

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

so "74657374d41d8cd98f00b204e9800998ecf8427e" is actually a hex representation of "test", plus the initial state of the hash.

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

will result in... "74657374"!

So basically hash.Sum(b) is not doing what you think it does. The second statement is the right hash.

答案4

得分: 0

我想简要告诉你:

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

答案:

hash := md5.New()

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

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

这就是你得到这些输出的原因。

供你参考,查看Sum API:

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	}
英文:

I would like to tell you to the point:

> why/how do I get different result for the two print ?

Ans:

hash := md5.New()

As you are creating a new instance of md5 hash once you call hash.Sum(b) it actually md5 hash for b as hash itself is empty, hence you got 74657374d41d8cd98f00b204e9800998ecf8427e as output.

Now in next statement hash.Write(b) you are writing b to the hash instance then calling hash.Sum(nil) it will calculate md5 for b that you just written and sum it to previous value i.e 74657374d41d8cd98f00b204e9800998ecf8427e

This is the reason you are getting these outputs.

For your reference look at the Sum API:

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	}

huangapple
  • 本文由 发表于 2014年6月16日 05:33:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/24234322.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定