...
1 package jws
2
3 import (
4 "crypto/hmac"
5 "crypto/sha256"
6 "crypto/sha512"
7 "hash"
8
9 "github.com/lestrrat-go/jwx/internal/keyconv"
10 "github.com/lestrrat-go/jwx/jwa"
11 "github.com/pkg/errors"
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],
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, errors.Wrap(err, "failed to write payload using hmac")
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, errors.Wrapf(err, `invalid key type %T. []byte is required`, key)
53 }
54
55 if len(hmackey) == 0 {
56 return nil, errors.New(`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 errors.Wrap(err, `failed to generated signature`)
71 }
72
73 if !hmac.Equal(signature, expected) {
74 return errors.New(`failed to match hmac signature`)
75 }
76 return nil
77 }
78
View as plain text