Python与Go散列的区别

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
", 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?

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.