73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package hmac
|
|
|
|
// llgo:skipall
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"hash"
|
|
"unsafe"
|
|
|
|
"github.com/goplus/llgo/c"
|
|
"github.com/goplus/llgo/c/openssl"
|
|
)
|
|
|
|
type eface struct {
|
|
_type unsafe.Pointer
|
|
funcPtr *unsafe.Pointer
|
|
}
|
|
|
|
func funcOf(a any) unsafe.Pointer {
|
|
e := (*eface)(unsafe.Pointer(&a))
|
|
return *e.funcPtr
|
|
}
|
|
|
|
type digest openssl.HMAC_CTX
|
|
|
|
func (d *digest) Size() int { panic("todo: hmac.(*digest).Size") }
|
|
|
|
func (d *digest) BlockSize() int { panic("todo: hmac.(*digest).BlockSize") }
|
|
|
|
func (d *digest) Reset() {
|
|
(*openssl.HMAC_CTX)(d).Reset()
|
|
}
|
|
|
|
func (d *digest) Write(p []byte) (nn int, err error) {
|
|
(*openssl.HMAC_CTX)(d).UpdateBytes(p)
|
|
return len(p), nil
|
|
}
|
|
|
|
func (d *digest) Sum(in []byte) []byte {
|
|
const Size = openssl.EVP_MAX_MD_SIZE
|
|
var digestLen c.Uint
|
|
hash := (*[Size]byte)(c.Alloca(Size))
|
|
(*openssl.HMAC_CTX)(d).Final(&hash[0], &digestLen)
|
|
return append(in, hash[:digestLen]...)
|
|
}
|
|
|
|
// New returns a new HMAC hash using the given [hash.Hash] type and key.
|
|
// New functions like sha256.New from [crypto/sha256] can be used as h.
|
|
// h must return a new Hash every time it is called.
|
|
// Note that unlike other hash implementations in the standard library,
|
|
// the returned Hash does not implement [encoding.BinaryMarshaler]
|
|
// or [encoding.BinaryUnmarshaler].
|
|
func New(h func() hash.Hash, key []byte) hash.Hash {
|
|
var md *openssl.EVP_MD
|
|
switch funcOf(h) {
|
|
case c.Func(sha256.New):
|
|
md = openssl.EVP_sha256()
|
|
default:
|
|
panic("todo: hmac.New: unsupported hash function")
|
|
}
|
|
ctx := openssl.NewHMAC_CTX()
|
|
ctx.InitBytes(key, md)
|
|
return (*digest)(ctx)
|
|
}
|
|
|
|
// Equal compares two MACs for equality without leaking timing information.
|
|
func Equal(mac1, mac2 []byte) bool {
|
|
// We don't have to be constant time if the lengths of the MACs are
|
|
// different as that suggests that a completely different hash function
|
|
// was used.
|
|
return subtle.ConstantTimeCompare(mac1, mac2) == 1
|
|
}
|