ed25519.go raw

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