英文:
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在这里也相当优雅
假设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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论