hmac.go

  1package jwt
  2
  3import (
  4	"crypto"
  5	"crypto/hmac"
  6	"errors"
  7)
  8
  9// SigningMethodHMAC implements the HMAC-SHA family of signing methods.
 10// Expects key type of []byte for both signing and validation
 11type SigningMethodHMAC struct {
 12	Name string
 13	Hash crypto.Hash
 14}
 15
 16// Specific instances for HS256 and company
 17var (
 18	SigningMethodHS256  *SigningMethodHMAC
 19	SigningMethodHS384  *SigningMethodHMAC
 20	SigningMethodHS512  *SigningMethodHMAC
 21	ErrSignatureInvalid = errors.New("signature is invalid")
 22)
 23
 24func init() {
 25	// HS256
 26	SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
 27	RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
 28		return SigningMethodHS256
 29	})
 30
 31	// HS384
 32	SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
 33	RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
 34		return SigningMethodHS384
 35	})
 36
 37	// HS512
 38	SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
 39	RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
 40		return SigningMethodHS512
 41	})
 42}
 43
 44func (m *SigningMethodHMAC) Alg() string {
 45	return m.Name
 46}
 47
 48// Verify implements token verification for the SigningMethod. Returns nil if
 49// the signature is valid. Key must be []byte.
 50//
 51// Note it is not advised to provide a []byte which was converted from a 'human
 52// readable' string using a subset of ASCII characters. To maximize entropy, you
 53// should ideally be providing a []byte key which was produced from a
 54// cryptographically random source, e.g. crypto/rand. Additional information
 55// about this, and why we intentionally are not supporting string as a key can
 56// be found on our usage guide
 57// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types.
 58func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interface{}) error {
 59	// Verify the key is the right type
 60	keyBytes, ok := key.([]byte)
 61	if !ok {
 62		return newError("HMAC verify expects []byte", ErrInvalidKeyType)
 63	}
 64
 65	// Can we use the specified hashing method?
 66	if !m.Hash.Available() {
 67		return ErrHashUnavailable
 68	}
 69
 70	// This signing method is symmetric, so we validate the signature
 71	// by reproducing the signature from the signing string and key, then
 72	// comparing that against the provided signature.
 73	hasher := hmac.New(m.Hash.New, keyBytes)
 74	hasher.Write([]byte(signingString))
 75	if !hmac.Equal(sig, hasher.Sum(nil)) {
 76		return ErrSignatureInvalid
 77	}
 78
 79	// No validation errors.  Signature is good.
 80	return nil
 81}
 82
 83// Sign implements token signing for the SigningMethod. Key must be []byte.
 84//
 85// Note it is not advised to provide a []byte which was converted from a 'human
 86// readable' string using a subset of ASCII characters. To maximize entropy, you
 87// should ideally be providing a []byte key which was produced from a
 88// cryptographically random source, e.g. crypto/rand. Additional information
 89// about this, and why we intentionally are not supporting string as a key can
 90// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/.
 91func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) {
 92	if keyBytes, ok := key.([]byte); ok {
 93		if !m.Hash.Available() {
 94			return nil, ErrHashUnavailable
 95		}
 96
 97		hasher := hmac.New(m.Hash.New, keyBytes)
 98		hasher.Write([]byte(signingString))
 99
100		return hasher.Sum(nil), nil
101	}
102
103	return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType)
104}