1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package ed25519
17
18 import (
19 "crypto"
20 "crypto/internal/fips140/ed25519"
21 "crypto/internal/fips140cache"
22 "crypto/internal/fips140only"
23 "crypto/internal/rand"
24 cryptorand "crypto/rand"
25 "crypto/subtle"
26 "errors"
27 "internal/godebug"
28 "io"
29 "strconv"
30 )
31
32 const (
33
34 PublicKeySize = 32
35
36 PrivateKeySize = 64
37
38 SignatureSize = 64
39
40 SeedSize = 32
41 )
42
43
44 type PublicKey []byte
45
46
47
48
49
50 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
51 xx, ok := x.(PublicKey)
52 if !ok {
53 return false
54 }
55 return subtle.ConstantTimeCompare(pub, xx) == 1
56 }
57
58
59 type PrivateKey []byte
60
61
62 func (priv PrivateKey) Public() crypto.PublicKey {
63 publicKey := make([]byte, PublicKeySize)
64 copy(publicKey, priv[32:])
65 return PublicKey(publicKey)
66 }
67
68
69 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
70 xx, ok := x.(PrivateKey)
71 if !ok {
72 return false
73 }
74 return subtle.ConstantTimeCompare(priv, xx) == 1
75 }
76
77
78
79
80 func (priv PrivateKey) Seed() []byte {
81 return append(make([]byte, 0, SeedSize), priv[:SeedSize]...)
82 }
83
84
85
86 var privateKeyCache fips140cache.Cache[byte, ed25519.PrivateKey]
87
88
89
90
91
92
93
94
95
96
97 func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
98 k, err := privateKeyCache.Get(&priv[0], func() (*ed25519.PrivateKey, error) {
99 return ed25519.NewPrivateKey(priv)
100 }, func(k *ed25519.PrivateKey) bool {
101 return subtle.ConstantTimeCompare(priv, k.Bytes()) == 1
102 })
103 if err != nil {
104 return nil, err
105 }
106 hash := opts.HashFunc()
107 context := ""
108 if opts, ok := opts.(*Options); ok {
109 context = opts.Context
110 }
111 switch {
112 case hash == crypto.SHA512:
113 return ed25519.SignPH(k, message, context)
114 case hash == crypto.Hash(0) && context != "":
115 if fips140only.Enforced() {
116 return nil, errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
117 }
118 return ed25519.SignCtx(k, message, context)
119 case hash == crypto.Hash(0):
120 return ed25519.Sign(k, message), nil
121 default:
122 return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
123 }
124 }
125
126
127
128 type Options struct {
129
130 Hash crypto.Hash
131
132
133
134 Context string
135 }
136
137
138 func (o *Options) HashFunc() crypto.Hash { return o.Hash }
139
140 var cryptocustomrand = godebug.New("cryptocustomrand")
141
142
143
144
145
146
147
148
149
150
151 func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) {
152 if random == nil {
153 if cryptocustomrand.Value() == "1" {
154 random = cryptorand.Reader
155 if !rand.IsDefaultReader(random) {
156 cryptocustomrand.IncNonDefault()
157 }
158 } else {
159 random = rand.Reader
160 }
161 }
162
163 if fips140only.Enforced() && !fips140only.ApprovedRandomReader(random) {
164 return nil, nil, errors.New("crypto/ed25519: only crypto/rand.Reader is allowed in FIPS 140-only mode")
165 }
166
167 if rand.IsDefaultReader(random) {
168 privateKey, err := ed25519.GenerateKey()
169 if err != nil {
170 return nil, nil, err
171 }
172 publicKey := PublicKey(privateKey.PublicKey())
173 return publicKey, PrivateKey(privateKey.Bytes()), nil
174 }
175
176 seed := make([]byte, SeedSize)
177 if _, err := io.ReadFull(random, seed); err != nil {
178 return nil, nil, err
179 }
180
181 privateKey := NewKeyFromSeed(seed)
182 publicKey := privateKey.Public().(PublicKey)
183 return publicKey, privateKey, nil
184 }
185
186
187
188
189
190 func NewKeyFromSeed(seed []byte) PrivateKey {
191
192 privateKey := make([]byte, PrivateKeySize)
193 newKeyFromSeed(privateKey, seed)
194 return privateKey
195 }
196
197 func newKeyFromSeed(privateKey, seed []byte) {
198 k, err := ed25519.NewPrivateKeyFromSeed(seed)
199 if err != nil {
200
201 panic("ed25519: bad seed length: " + strconv.Itoa(len(seed)))
202 }
203 copy(privateKey, k.Bytes())
204 }
205
206
207
208 func Sign(privateKey PrivateKey, message []byte) []byte {
209
210
211 signature := make([]byte, SignatureSize)
212 sign(signature, privateKey, message)
213 return signature
214 }
215
216 func sign(signature []byte, privateKey PrivateKey, message []byte) {
217 k, err := privateKeyCache.Get(&privateKey[0], func() (*ed25519.PrivateKey, error) {
218 return ed25519.NewPrivateKey(privateKey)
219 }, func(k *ed25519.PrivateKey) bool {
220 return subtle.ConstantTimeCompare(privateKey, k.Bytes()) == 1
221 })
222 if err != nil {
223 panic("ed25519: bad private key: " + err.Error())
224 }
225 sig := ed25519.Sign(k, message)
226 copy(signature, sig)
227 }
228
229
230
231
232
233
234 func Verify(publicKey PublicKey, message, sig []byte) bool {
235 return VerifyWithOptions(publicKey, message, sig, &Options{Hash: crypto.Hash(0)}) == nil
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249 func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
250 if l := len(publicKey); l != PublicKeySize {
251 panic("ed25519: bad public key length: " + strconv.Itoa(l))
252 }
253 k, err := ed25519.NewPublicKey(publicKey)
254 if err != nil {
255 return err
256 }
257 switch {
258 case opts.Hash == crypto.SHA512:
259 return ed25519.VerifyPH(k, message, sig, opts.Context)
260 case opts.Hash == crypto.Hash(0) && opts.Context != "":
261 if fips140only.Enforced() {
262 return errors.New("crypto/ed25519: use of Ed25519ctx is not allowed in FIPS 140-only mode")
263 }
264 return ed25519.VerifyCtx(k, message, sig, opts.Context)
265 case opts.Hash == crypto.Hash(0):
266 return ed25519.Verify(k, message, sig)
267 default:
268 return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
269 }
270 }
271
View as plain text