Python与Go的哈希差异

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

Python vs Go Hashing Differences

问题

我有一个Go程序:

package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"fmt"
)

func main() {
	val := []byte("nJ1m4Cc3")
	hasher := hmac.New(sha1.New, val)
	fmt.Printf("%x\n", hasher.Sum(nil))
	// f7c0aebfb7db2c15f1945a6b7b5286d173df894d
}

还有一个Python(2.7)程序,试图使用crypto/hmac库来复现Go代码:

import hashlib
val = u'nJ1m4Cc3'
hasher = hashlib.new("sha1", val)
print hasher.hexdigest()
# d67c1f445987c52bceb8d6475c30a8b0e9a3365d

使用hmac模块给出了一个不同的结果,但仍然与Go代码不同:

import hmac
val = 'nJ1m4Cc3'
h = hmac.new("sha1", val)
print h.hexdigest()
# d34435851209e463deeeb40cba7b75ef

为什么它们在相同的输入上使用相同的哈希算法时打印出不同的值呢?

英文:

I have a Go program

package main
 
import (
	"crypto/hmac"
	"crypto/sha1"
	"fmt"
)
 
func main() {
	val := []byte("nJ1m4Cc3")
	hasher := hmac.New(sha1.New, val)
	fmt.Printf("%x\n", hasher.Sum(nil))
	// f7c0aebfb7db2c15f1945a6b7b5286d173df894d
}

And a Python (2.7) program that is attempting to reproduce the Go code (using crypto/hmac)

import hashlib
val =  u'nJ1m4Cc3'
hasher = hashlib.new("sha1", val)
print hasher.hexdigest()
# d67c1f445987c52bceb8d6475c30a8b0e9a3365d

Using the hmac module gives me a different result but still not the same as the Go code.

import hmac
val = 'nJ1m4Cc3'
h = hmac.new("sha1", val)
print h.hexdigest()
# d34435851209e463deeeb40cba7b75ef

Why do these print different values when they use the same hash on the same input?

答案1

得分: 6

你必须确保:

  • 两种情况下的输入是等价的,并且
  • 两种情况下的处理方法是等价的。

在这两种情况下,输入应该是相同的二进制数据块。在你的Python程序中,你定义了一个Unicode对象,并且没有控制其二进制表示。将u前缀替换为b,问题就解决了(这是在Python 2.7和3中定义字节序列的显式方式)。这并不是实际的问题,但在这里最好明确一下。

问题在于你在Go和Python的实现中应用了不同的方法。

假设Python是参考实现

在Go中,根本不需要导入"crypto/hmac",在Python中,你只需构建数据的SHA1哈希。在Go中,等价的代码如下:

package main

import (
    "crypto/sha1"
    "fmt"
)

func main() {
    data := []byte("nJ1m4Cc3")
    fmt.Printf("%x", sha1.Sum(data))
}

测试和输出:

go run hashit.go
d67c1f445987c52bceb8d6475c30a8b0e9a3365d

这与你的第一个Python代码片段创建的结果相同。

编辑:我稍微简化了一下Go代码,以免让Python看起来更优雅。Go在这里也相当优雅 Python与Go的哈希差异

假设Go是参考实现

import hmac
import hashlib

data = b'nJ1m4Cc3'
h = hmac.new(key=data, digestmod=hashlib.sha1)
print h.hexdigest()

测试和输出:

python hashit.py
f7c0aebfb7db2c15f1945a6b7b5286d173df894d

这与你的Go代码片段创建的结果相同。然而,我不确定在使用空消息时HMAC的加密意义如何。

英文:

You have to make sure that

  • the input in both scenarios is equivalent and that
  • the processing method in both scenarios is equivalent.

In both cases, the input should be the same binary blob. In your Python program you define a unicode object, and you do not take control of its binary representation. Replace the u prefix with a b, and you are fine (this is the explicit way to define a byte sequence in Python 2.7 and 3). This is not the actual problem, but better be explicit here.

The problem is that you apply different methods in your Go and Python implementations.

Given that Python is the reference

In Go, no need to import "crypto/hmac" at all, in Python you just build a SHA1 hash of your data. In Go, the equivalent would be:

package main

import (
    "crypto/sha1"
    "fmt"
)

func main() {
    data := []byte("nJ1m4Cc3")
    fmt.Printf("%x", sha1.Sum(data))
}

Test and output:

go run hashit.go
d67c1f445987c52bceb8d6475c30a8b0e9a3365d

This reproduces what your first Python snippet creates.

Edit: I have simplified the Go code a bit, to not make Python look more elegant. Go is quite elegant here, too :-).

Given that Go is the reference

import hmac
import hashlib

data = b'nJ1m4Cc3'
h = hmac.new(key=data, digestmod=hashlib.sha1)
print h.hexdigest()

Test & output:

python hashit.py
f7c0aebfb7db2c15f1945a6b7b5286d173df894d

This reproduces what your Go snippet creates. I am, however, not sure about the cryptographic significance of an HMAC when one does use an empty message.

huangapple
  • 本文由 发表于 2015年1月23日 01:09:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/28094673.html
匿名

发表评论

匿名网友

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

确定