ed25519.go raw

   1  package jwt
   2  
   3  import (
   4  	"errors"
   5  
   6  	"crypto"
   7  	"crypto/ed25519"
   8  	"crypto/rand"
   9  )
  10  
  11  var (
  12  	ErrEd25519Verification = errors.New("ed25519: verification error")
  13  )
  14  
  15  // SigningMethodEd25519 implements the EdDSA family.
  16  // Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
  17  type SigningMethodEd25519 struct{}
  18  
  19  // Specific instance for EdDSA
  20  var (
  21  	SigningMethodEdDSA *SigningMethodEd25519
  22  )
  23  
  24  func init() {
  25  	SigningMethodEdDSA = &SigningMethodEd25519{}
  26  	RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() SigningMethod {
  27  		return SigningMethodEdDSA
  28  	})
  29  }
  30  
  31  func (m *SigningMethodEd25519) Alg() string {
  32  	return "EdDSA"
  33  }
  34  
  35  // Verify implements token verification for the SigningMethod.
  36  // For this verify method, key must be an ed25519.PublicKey
  37  func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error {
  38  	var err error
  39  	var ed25519Key ed25519.PublicKey
  40  	var ok bool
  41  
  42  	if ed25519Key, ok = key.(ed25519.PublicKey); !ok {
  43  		return ErrInvalidKeyType
  44  	}
  45  
  46  	if len(ed25519Key) != ed25519.PublicKeySize {
  47  		return ErrInvalidKey
  48  	}
  49  
  50  	// Decode the signature
  51  	var sig []byte
  52  	if sig, err = DecodeSegment(signature); err != nil {
  53  		return err
  54  	}
  55  
  56  	// Verify the signature
  57  	if !ed25519.Verify(ed25519Key, []byte(signingString), sig) {
  58  		return ErrEd25519Verification
  59  	}
  60  
  61  	return nil
  62  }
  63  
  64  // Sign implements token signing for the SigningMethod.
  65  // For this signing method, key must be an ed25519.PrivateKey
  66  func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) {
  67  	var ed25519Key crypto.Signer
  68  	var ok bool
  69  
  70  	if ed25519Key, ok = key.(crypto.Signer); !ok {
  71  		return "", ErrInvalidKeyType
  72  	}
  73  
  74  	if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {
  75  		return "", ErrInvalidKey
  76  	}
  77  
  78  	// Sign the string and return the encoded result
  79  	// ed25519 performs a two-pass hash as part of its algorithm. Therefore, we need to pass a non-prehashed message into the Sign function, as indicated by crypto.Hash(0)
  80  	sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0))
  81  	if err != nil {
  82  		return "", err
  83  	}
  84  	return EncodeSegment(sig), nil
  85  }
  86