golang: panic: crypto: requested hash function #2 is unavailable

golang: panic: crypto: requested hash function #2 is unavailable

Code:

package main

import (
	"crypto"
	"fmt"
	"io"
)

func main() {
	h := crypto.MD5.New()
	io.WriteString(h, "test1280")
	fmt.Printf("%x\n", h.Sum(nil))
}

運行報錯:

C:\Users\EB\Desktop\test1280>go run main.go
panic: crypto: requested hash function #2 is unavailable

goroutine 1 [running]:
crypto.Hash.New(0x2, 0xc0000441e0, 0xc000089f20)
        D:/app2/go1.13.6/src/crypto/crypto.go:89 +0x109
main.main()
        C:/Users/EB/Desktop/test1280/main.go:10 +0x35
exit status 2

解決:

import "crypto/md5"

最後代碼:

package main

import (
	"crypto"
	_ "crypto/md5"
	"fmt"
	"io"
)

func main() {
	h := crypto.MD5.New()
	io.WriteString(h, "test1280")
	fmt.Printf("%x\n", h.Sum(nil))
}

原因說明

仔細看下 crypto.go 源碼就能知道原因:https://golang.org/src/crypto/crypto.go。

在調用 crypto.MD5.New 時,調用:

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
	if h > 0 && h < maxHash {
		f := hashes[h]
		if f != nil {
			return f()
		}
	}
	panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
}

這裏 Hash 其實是一個 int 類型,MD5即 int 中的 2。

調用 New 時,會從 hashes 表中查找 MD5 的工廠函數,並調用工廠函數創建 MD5 句柄對象(return f())。

但是明顯,在查 MD5 工廠函數時沒查到(if f != nil,實際上 f == nil),因此panic。

再看看什麼時候註冊的 MD5 工廠函數?

// RegisterHash registers a function that returns a new instance of the given
// hash function. This is intended to be called from the init function in
// packages that implement hash functions.
func RegisterHash(h Hash, f func() hash.Hash) {
	if h >= maxHash {
		panic("crypto: RegisterHash of unknown hash function")
	}
	hashes[h] = f
}

This is intended to be called from the init function in packages that implement hash functions.

在 Linux 下可以用 grep 查一下哪裏調用了此函數:

[test1280@localhost crypto]$ pwd
/home/test1280/go/src/crypto
[test1280@localhost crypto]$ grep "RegisterHash" ./* -nr
./crypto.go:97:// RegisterHash registers a function that returns a new instance of the given
./crypto.go:100:func RegisterHash(h Hash, f func() hash.Hash) {
./crypto.go:102:		panic("crypto: RegisterHash of unknown hash function")
./md5/md5.go:21:	crypto.RegisterHash(crypto.MD5, New)
./sha1/sha1.go:19:	crypto.RegisterHash(crypto.SHA1, New)
./sha256/sha256.go:17:	crypto.RegisterHash(crypto.SHA224, New224)
./sha256/sha256.go:18:	crypto.RegisterHash(crypto.SHA256, New)
./sha512/sha512.go:21:	crypto.RegisterHash(crypto.SHA384, New384)
./sha512/sha512.go:22:	crypto.RegisterHash(crypto.SHA512, New)
./sha512/sha512.go:23:	crypto.RegisterHash(crypto.SHA512_224, New512_224)
./sha512/sha512.go:24:	crypto.RegisterHash(crypto.SHA512_256, New512_256)

都是各個不同算法包,在其init函數中註冊自己的工廠函數到crypto包中的。

因此,只需要讓 crypto/md5 包加載,執行其 init 函數即可:

通過 import _ “crypto/md5” 即可實現。

參考:

1.https://stackoverflow.com/questions/17986762/openpgp-in-go-error-crypto-requested-hash-function-is-unavailable
2.https://github.com/Kong/go-srp/issues/1
3.https://stackoverflow.com/questions/17986762/openpgp-in-go-error-crypto-requested-hash-function-is-unavailable
4.https://www.cnblogs.com/yxdz-hit/p/8666464.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章