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  }