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 }