1
2
3
4
5 package ed25519
6
7 import (
8 "bufio"
9 "bytes"
10 "compress/gzip"
11 "crypto"
12 "crypto/internal/boring"
13 "crypto/rand"
14 "crypto/sha512"
15 "encoding/hex"
16 "internal/testenv"
17 "log"
18 "os"
19 "strings"
20 "testing"
21 )
22
23 func Example_ed25519ctx() {
24 pub, priv, err := GenerateKey(nil)
25 if err != nil {
26 log.Fatal(err)
27 }
28
29 msg := []byte("The quick brown fox jumps over the lazy dog")
30
31 sig, err := priv.Sign(nil, msg, &Options{
32 Context: "Example_ed25519ctx",
33 })
34 if err != nil {
35 log.Fatal(err)
36 }
37
38 if err := VerifyWithOptions(pub, msg, sig, &Options{
39 Context: "Example_ed25519ctx",
40 }); err != nil {
41 log.Fatal("invalid signature")
42 }
43 }
44
45 type zeroReader struct{}
46
47 func (zeroReader) Read(buf []byte) (int, error) {
48 clear(buf)
49 return len(buf), nil
50 }
51
52 func TestSignVerify(t *testing.T) {
53 var zero zeroReader
54 public, private, _ := GenerateKey(zero)
55
56 message := []byte("test message")
57 sig := Sign(private, message)
58 if !Verify(public, message, sig) {
59 t.Errorf("valid signature rejected")
60 }
61
62 wrongMessage := []byte("wrong message")
63 if Verify(public, wrongMessage, sig) {
64 t.Errorf("signature of different message accepted")
65 }
66 }
67
68 func TestSignVerifyHashed(t *testing.T) {
69
70 key, _ := hex.DecodeString("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf")
71 expectedSig, _ := hex.DecodeString("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406")
72 message, _ := hex.DecodeString("616263")
73
74 private := PrivateKey(key)
75 public := private.Public().(PublicKey)
76 hash := sha512.Sum512(message)
77 sig, err := private.Sign(nil, hash[:], crypto.SHA512)
78 if err != nil {
79 t.Fatal(err)
80 }
81 if !bytes.Equal(sig, expectedSig) {
82 t.Error("signature doesn't match test vector")
83 }
84 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512})
85 if err != nil {
86 t.Fatal(err)
87 }
88 if !bytes.Equal(sig, expectedSig) {
89 t.Error("signature doesn't match test vector")
90 }
91 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}); err != nil {
92 t.Errorf("valid signature rejected: %v", err)
93 }
94
95 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256}); err == nil {
96 t.Errorf("expected error for wrong hash")
97 }
98
99 wrongHash := sha512.Sum512([]byte("wrong message"))
100 if VerifyWithOptions(public, wrongHash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
101 t.Errorf("signature of different message accepted")
102 }
103
104 sig[0] ^= 0xff
105 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
106 t.Errorf("invalid signature accepted")
107 }
108 sig[0] ^= 0xff
109 sig[SignatureSize-1] ^= 0xff
110 if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
111 t.Errorf("invalid signature accepted")
112 }
113
114
115
116 sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512, Context: "123"})
117 if err != nil {
118 t.Fatal(err)
119 }
120 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "123"}); err != nil {
121 t.Errorf("valid signature rejected: %v", err)
122 }
123 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "321"}); err == nil {
124 t.Errorf("expected error for wrong context")
125 }
126 if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256, Context: "123"}); err == nil {
127 t.Errorf("expected error for wrong hash")
128 }
129 }
130
131 func TestSignVerifyContext(t *testing.T) {
132
133 key, _ := hex.DecodeString("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292")
134 expectedSig, _ := hex.DecodeString("55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d")
135 message, _ := hex.DecodeString("f726936d19c800494e3fdaff20b276a8")
136 context := "foo"
137
138 private := PrivateKey(key)
139 public := private.Public().(PublicKey)
140 sig, err := private.Sign(nil, message, &Options{Context: context})
141 if err != nil {
142 t.Fatal(err)
143 }
144 if !bytes.Equal(sig, expectedSig) {
145 t.Error("signature doesn't match test vector")
146 }
147 if err := VerifyWithOptions(public, message, sig, &Options{Context: context}); err != nil {
148 t.Errorf("valid signature rejected: %v", err)
149 }
150
151 if VerifyWithOptions(public, []byte("bar"), sig, &Options{Context: context}) == nil {
152 t.Errorf("signature of different message accepted")
153 }
154 if VerifyWithOptions(public, message, sig, &Options{Context: "bar"}) == nil {
155 t.Errorf("signature with different context accepted")
156 }
157
158 sig[0] ^= 0xff
159 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
160 t.Errorf("invalid signature accepted")
161 }
162 sig[0] ^= 0xff
163 sig[SignatureSize-1] ^= 0xff
164 if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
165 t.Errorf("invalid signature accepted")
166 }
167 }
168
169 func TestCryptoSigner(t *testing.T) {
170 var zero zeroReader
171 public, private, _ := GenerateKey(zero)
172
173 signer := crypto.Signer(private)
174
175 publicInterface := signer.Public()
176 public2, ok := publicInterface.(PublicKey)
177 if !ok {
178 t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
179 }
180
181 if !bytes.Equal(public, public2) {
182 t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
183 }
184
185 message := []byte("message")
186 var noHash crypto.Hash
187 signature, err := signer.Sign(zero, message, noHash)
188 if err != nil {
189 t.Fatalf("error from Sign(): %s", err)
190 }
191
192 signature2, err := signer.Sign(zero, message, &Options{Hash: noHash})
193 if err != nil {
194 t.Fatalf("error from Sign(): %s", err)
195 }
196 if !bytes.Equal(signature, signature2) {
197 t.Errorf("signatures keys do not match")
198 }
199
200 if !Verify(public, message, signature) {
201 t.Errorf("Verify failed on signature from Sign()")
202 }
203 }
204
205 func TestEqual(t *testing.T) {
206 public, private, _ := GenerateKey(rand.Reader)
207
208 if !public.Equal(public) {
209 t.Errorf("public key is not equal to itself: %q", public)
210 }
211 if !public.Equal(crypto.Signer(private).Public()) {
212 t.Errorf("private.Public() is not Equal to public: %q", public)
213 }
214 if !private.Equal(private) {
215 t.Errorf("private key is not equal to itself: %q", private)
216 }
217
218 otherPub, otherPriv, _ := GenerateKey(rand.Reader)
219 if public.Equal(otherPub) {
220 t.Errorf("different public keys are Equal")
221 }
222 if private.Equal(otherPriv) {
223 t.Errorf("different private keys are Equal")
224 }
225 }
226
227 func TestGolden(t *testing.T) {
228
229
230 testDataZ, err := os.Open("testdata/sign.input.gz")
231 if err != nil {
232 t.Fatal(err)
233 }
234 defer testDataZ.Close()
235 testData, err := gzip.NewReader(testDataZ)
236 if err != nil {
237 t.Fatal(err)
238 }
239 defer testData.Close()
240
241 scanner := bufio.NewScanner(testData)
242 lineNo := 0
243
244 for scanner.Scan() {
245 lineNo++
246
247 line := scanner.Text()
248 parts := strings.Split(line, ":")
249 if len(parts) != 5 {
250 t.Fatalf("bad number of parts on line %d", lineNo)
251 }
252
253 privBytes, _ := hex.DecodeString(parts[0])
254 pubKey, _ := hex.DecodeString(parts[1])
255 msg, _ := hex.DecodeString(parts[2])
256 sig, _ := hex.DecodeString(parts[3])
257
258
259 sig = sig[:SignatureSize]
260
261 if l := len(pubKey); l != PublicKeySize {
262 t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
263 }
264
265 var priv [PrivateKeySize]byte
266 copy(priv[:], privBytes)
267 copy(priv[32:], pubKey)
268
269 sig2 := Sign(priv[:], msg)
270 if !bytes.Equal(sig, sig2[:]) {
271 t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
272 }
273
274 if !Verify(pubKey, msg, sig2) {
275 t.Errorf("signature failed to verify on line %d", lineNo)
276 }
277
278 priv2 := NewKeyFromSeed(priv[:32])
279 if !bytes.Equal(priv[:], priv2) {
280 t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
281 }
282
283 if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
284 t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
285 }
286
287 if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
288 t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
289 }
290 }
291
292 if err := scanner.Err(); err != nil {
293 t.Fatalf("error reading test data: %s", err)
294 }
295 }
296
297 func TestMalleability(t *testing.T) {
298
299
300
301 msg := []byte{0x54, 0x65, 0x73, 0x74}
302 sig := []byte{
303 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
304 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
305 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
306 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
307 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
308 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
309 }
310 publicKey := []byte{
311 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
312 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
313 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
314 }
315
316 if Verify(publicKey, msg, sig) {
317 t.Fatal("non-canonical signature accepted")
318 }
319 }
320
321 func TestAllocations(t *testing.T) {
322 if boring.Enabled {
323 t.Skip("skipping allocations test with BoringCrypto")
324 }
325 testenv.SkipIfOptimizationOff(t)
326
327 if allocs := testing.AllocsPerRun(100, func() {
328 seed := make([]byte, SeedSize)
329 message := []byte("Hello, world!")
330 priv := NewKeyFromSeed(seed)
331 pub := priv.Public().(PublicKey)
332 signature := Sign(priv, message)
333 if !Verify(pub, message, signature) {
334 t.Fatal("signature didn't verify")
335 }
336 }); allocs > 0 {
337 t.Errorf("expected zero allocations, got %0.1f", allocs)
338 }
339 }
340
341 func BenchmarkKeyGeneration(b *testing.B) {
342 var zero zeroReader
343 for i := 0; i < b.N; i++ {
344 if _, _, err := GenerateKey(zero); err != nil {
345 b.Fatal(err)
346 }
347 }
348 }
349
350 func BenchmarkNewKeyFromSeed(b *testing.B) {
351 seed := make([]byte, SeedSize)
352 for i := 0; i < b.N; i++ {
353 _ = NewKeyFromSeed(seed)
354 }
355 }
356
357 func BenchmarkSigning(b *testing.B) {
358 var zero zeroReader
359 _, priv, err := GenerateKey(zero)
360 if err != nil {
361 b.Fatal(err)
362 }
363 message := []byte("Hello, world!")
364 b.ResetTimer()
365 for i := 0; i < b.N; i++ {
366 Sign(priv, message)
367 }
368 }
369
370 func BenchmarkVerification(b *testing.B) {
371 var zero zeroReader
372 pub, priv, err := GenerateKey(zero)
373 if err != nil {
374 b.Fatal(err)
375 }
376 message := []byte("Hello, world!")
377 signature := Sign(priv, message)
378 b.ResetTimer()
379 for i := 0; i < b.N; i++ {
380 Verify(pub, message, signature)
381 }
382 }
383
View as plain text