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