hmac.go 1.8 KB

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