102 lines
2.1 KiB
Go
102 lines
2.1 KiB
Go
package sm
|
|
|
|
import (
|
|
"crypto"
|
|
"hash"
|
|
)
|
|
|
|
// Hash identifies a cryptographic hash function that is implemented in another
|
|
// package.
|
|
// I try to keep it consistent with the standard library
|
|
type Hash struct {
|
|
crypto.Hash
|
|
}
|
|
|
|
// HashFunc simply returns the value of h so that Hash implements SignerOpts.
|
|
func (h Hash) HashFunc() crypto.Hash {
|
|
return h.Hash
|
|
}
|
|
|
|
func (h Hash) String() string {
|
|
switch h {
|
|
case SM3:
|
|
return "SM3"
|
|
case SM3WithID:
|
|
return "SM3WithID"
|
|
default:
|
|
// return ""
|
|
return h.Hash.String()
|
|
}
|
|
}
|
|
|
|
var (
|
|
SM3 Hash
|
|
SM3WithID Hash
|
|
maxHash Hash
|
|
)
|
|
var SHA1 = Hash{crypto.SHA1}
|
|
var SHA256 = Hash{crypto.SHA256}
|
|
|
|
func init() {
|
|
// A hack to get the maxHash in crypto.
|
|
i := new(crypto.Hash)
|
|
*i = 1
|
|
defer func() {
|
|
_ = recover()
|
|
SM3 = Hash{Hash: *i}
|
|
SM3WithID = Hash{Hash: *i + 1}
|
|
maxHash = Hash{Hash: *i + 2}
|
|
}()
|
|
for {
|
|
(*i).Size()
|
|
*i++
|
|
}
|
|
}
|
|
|
|
// Size returns the length, in bytes, of a digest resulting from the given hash
|
|
// function. It doesn't require that the hash function in question be linked
|
|
// into the program.
|
|
func (h Hash) Size() int {
|
|
switch h {
|
|
case SM3, SM3WithID:
|
|
return 32
|
|
default:
|
|
return h.Hash.Size()
|
|
}
|
|
}
|
|
|
|
var hashes = make(map[Hash]func() hash.Hash)
|
|
|
|
// 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.Hash >= SM3.Hash && h.Hash < maxHash.Hash {
|
|
f := hashes[h]
|
|
if f != nil {
|
|
return f()
|
|
}
|
|
}
|
|
return h.Hash.New()
|
|
}
|
|
|
|
// Available reports whether the given hash function is linked into the binary.
|
|
func (h Hash) Available() bool {
|
|
if h.Hash >= SM3.Hash && h.Hash < maxHash.Hash {
|
|
return true
|
|
}
|
|
return h.Hash.Available()
|
|
}
|
|
|
|
// 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.Hash >= maxHash.Hash {
|
|
panic("crypto: RegisterHash of unknown hash function")
|
|
}
|
|
// if h.Hash < SM3.Hash {
|
|
// crypto.RegisterHash(h.Hash, f)
|
|
// }
|
|
hashes[h] = f
|
|
}
|