78 lines
1.8 KiB
Go
78 lines
1.8 KiB
Go
|
package jws
|
||
|
|
||
|
import (
|
||
|
"crypto/hmac"
|
||
|
"crypto/sha256"
|
||
|
"crypto/sha512"
|
||
|
"hash"
|
||
|
|
||
|
"github.com/lestrrat-go/jwx/internal/keyconv"
|
||
|
"github.com/lestrrat-go/jwx/jwa"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
var hmacSignFuncs = map[jwa.SignatureAlgorithm]hmacSignFunc{}
|
||
|
|
||
|
func init() {
|
||
|
algs := map[jwa.SignatureAlgorithm]func() hash.Hash{
|
||
|
jwa.HS256: sha256.New,
|
||
|
jwa.HS384: sha512.New384,
|
||
|
jwa.HS512: sha512.New,
|
||
|
}
|
||
|
|
||
|
for alg, h := range algs {
|
||
|
hmacSignFuncs[alg] = makeHMACSignFunc(h)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func newHMACSigner(alg jwa.SignatureAlgorithm) Signer {
|
||
|
return &HMACSigner{
|
||
|
alg: alg,
|
||
|
sign: hmacSignFuncs[alg], // we know this will succeed
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func makeHMACSignFunc(hfunc func() hash.Hash) hmacSignFunc {
|
||
|
return func(payload []byte, key []byte) ([]byte, error) {
|
||
|
h := hmac.New(hfunc, key)
|
||
|
if _, err := h.Write(payload); err != nil {
|
||
|
return nil, errors.Wrap(err, "failed to write payload using hmac")
|
||
|
}
|
||
|
return h.Sum(nil), nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm {
|
||
|
return s.alg
|
||
|
}
|
||
|
|
||
|
func (s HMACSigner) Sign(payload []byte, key interface{}) ([]byte, error) {
|
||
|
var hmackey []byte
|
||
|
if err := keyconv.ByteSliceKey(&hmackey, key); err != nil {
|
||
|
return nil, errors.Wrapf(err, `invalid key type %T. []byte is required`, key)
|
||
|
}
|
||
|
|
||
|
if len(hmackey) == 0 {
|
||
|
return nil, errors.New(`missing key while signing payload`)
|
||
|
}
|
||
|
|
||
|
return s.sign(payload, hmackey)
|
||
|
}
|
||
|
|
||
|
func newHMACVerifier(alg jwa.SignatureAlgorithm) Verifier {
|
||
|
s := newHMACSigner(alg)
|
||
|
return &HMACVerifier{signer: s}
|
||
|
}
|
||
|
|
||
|
func (v HMACVerifier) Verify(payload, signature []byte, key interface{}) (err error) {
|
||
|
expected, err := v.signer.Sign(payload, key)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, `failed to generated signature`)
|
||
|
}
|
||
|
|
||
|
if !hmac.Equal(signature, expected) {
|
||
|
return errors.New(`failed to match hmac signature`)
|
||
|
}
|
||
|
return nil
|
||
|
}
|