github.com/lestrrat-go/jwx/v2@v2.0.21/jws/hmac.go (about) 1 package jws 2 3 import ( 4 "crypto/hmac" 5 "crypto/sha256" 6 "crypto/sha512" 7 "fmt" 8 "hash" 9 10 "github.com/lestrrat-go/jwx/v2/internal/keyconv" 11 "github.com/lestrrat-go/jwx/v2/jwa" 12 ) 13 14 var hmacSignFuncs = map[jwa.SignatureAlgorithm]hmacSignFunc{} 15 16 func init() { 17 algs := map[jwa.SignatureAlgorithm]func() hash.Hash{ 18 jwa.HS256: sha256.New, 19 jwa.HS384: sha512.New384, 20 jwa.HS512: sha512.New, 21 } 22 23 for alg, h := range algs { 24 hmacSignFuncs[alg] = makeHMACSignFunc(h) 25 } 26 } 27 28 func newHMACSigner(alg jwa.SignatureAlgorithm) Signer { 29 return &HMACSigner{ 30 alg: alg, 31 sign: hmacSignFuncs[alg], // we know this will succeed 32 } 33 } 34 35 func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc { 36 return func(payload []byte, key []byte) ([]byte, error) { 37 h := hmac.New(hfunc, key) 38 if _, err := h.Write(payload); err != nil { 39 return nil, fmt.Errorf(`failed to write payload using hmac: %w`, err) 40 } 41 return h.Sum(nil), nil 42 } 43 } 44 45 func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm { 46 return s.alg 47 } 48 49 func (s HMACSigner) Sign(payload []byte, key interface{}) ([]byte, error) { 50 var hmackey []byte 51 if err := keyconv.ByteSliceKey(&hmackey, key); err != nil { 52 return nil, fmt.Errorf(`invalid key type %T. []byte is required: %w`, key, err) 53 } 54 55 if len(hmackey) == 0 { 56 return nil, fmt.Errorf(`missing key while signing payload`) 57 } 58 59 return s.sign(payload, hmackey) 60 } 61 62 func newHMACVerifier(alg jwa.SignatureAlgorithm) Verifier { 63 s := newHMACSigner(alg) 64 return &HMACVerifier{signer: s} 65 } 66 67 func (v HMACVerifier) Verify(payload, signature []byte, key interface{}) (err error) { 68 expected, err := v.signer.Sign(payload, key) 69 if err != nil { 70 return fmt.Errorf(`failed to generated signature: %w`, err) 71 } 72 73 if !hmac.Equal(signature, expected) { 74 return fmt.Errorf(`failed to match hmac signature`) 75 } 76 return nil 77 }