1
2
3
4
5 package ecdsa
6
7 import (
8 "bufio"
9 "bytes"
10 "compress/bzip2"
11 "crypto/elliptic"
12 "crypto/rand"
13 "crypto/sha1"
14 "crypto/sha256"
15 "crypto/sha512"
16 "encoding/hex"
17 "hash"
18 "io"
19 "math/big"
20 "os"
21 "strings"
22 "testing"
23 )
24
25 func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) {
26 tests := []struct {
27 name string
28 curve elliptic.Curve
29 }{
30 {"P256", elliptic.P256()},
31 {"P224", elliptic.P224()},
32 {"P384", elliptic.P384()},
33 {"P521", elliptic.P521()},
34 {"P256/Generic", genericParamsForCurve(elliptic.P256())},
35 }
36 if testing.Short() {
37 tests = tests[:1]
38 }
39 for _, test := range tests {
40 curve := test.curve
41 t.Run(test.name, func(t *testing.T) {
42 t.Parallel()
43 f(t, curve)
44 })
45 }
46 }
47
48
49
50
51
52 func genericParamsForCurve(c elliptic.Curve) *elliptic.CurveParams {
53 d := *(c.Params())
54 return &d
55 }
56
57 func TestKeyGeneration(t *testing.T) {
58 testAllCurves(t, testKeyGeneration)
59 }
60
61 func testKeyGeneration(t *testing.T, c elliptic.Curve) {
62 priv, err := GenerateKey(c, rand.Reader)
63 if err != nil {
64 t.Fatal(err)
65 }
66 if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
67 t.Errorf("public key invalid: %s", err)
68 }
69 }
70
71 func TestSignAndVerify(t *testing.T) {
72 testAllCurves(t, testSignAndVerify)
73 }
74
75 func testSignAndVerify(t *testing.T, c elliptic.Curve) {
76 priv, _ := GenerateKey(c, rand.Reader)
77
78 hashed := []byte("testing")
79 r, s, err := Sign(rand.Reader, priv, hashed)
80 if err != nil {
81 t.Errorf("error signing: %s", err)
82 return
83 }
84
85 if !Verify(&priv.PublicKey, hashed, r, s) {
86 t.Errorf("Verify failed")
87 }
88
89 hashed[0] ^= 0xff
90 if Verify(&priv.PublicKey, hashed, r, s) {
91 t.Errorf("Verify always works!")
92 }
93 }
94
95 func TestSignAndVerifyASN1(t *testing.T) {
96 testAllCurves(t, testSignAndVerifyASN1)
97 }
98
99 func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve) {
100 priv, _ := GenerateKey(c, rand.Reader)
101
102 hashed := []byte("testing")
103 sig, err := SignASN1(rand.Reader, priv, hashed)
104 if err != nil {
105 t.Errorf("error signing: %s", err)
106 return
107 }
108
109 if !VerifyASN1(&priv.PublicKey, hashed, sig) {
110 t.Errorf("VerifyASN1 failed")
111 }
112
113 hashed[0] ^= 0xff
114 if VerifyASN1(&priv.PublicKey, hashed, sig) {
115 t.Errorf("VerifyASN1 always works!")
116 }
117 }
118
119 func TestNonceSafety(t *testing.T) {
120 testAllCurves(t, testNonceSafety)
121 }
122
123 func testNonceSafety(t *testing.T, c elliptic.Curve) {
124 priv, _ := GenerateKey(c, rand.Reader)
125
126 hashed := []byte("testing")
127 r0, s0, err := Sign(zeroReader, priv, hashed)
128 if err != nil {
129 t.Errorf("error signing: %s", err)
130 return
131 }
132
133 hashed = []byte("testing...")
134 r1, s1, err := Sign(zeroReader, priv, hashed)
135 if err != nil {
136 t.Errorf("error signing: %s", err)
137 return
138 }
139
140 if s0.Cmp(s1) == 0 {
141
142 t.Errorf("the signatures on two different messages were the same")
143 }
144
145 if r0.Cmp(r1) == 0 {
146 t.Errorf("the nonce used for two different messages was the same")
147 }
148 }
149
150 func TestINDCCA(t *testing.T) {
151 testAllCurves(t, testINDCCA)
152 }
153
154 func testINDCCA(t *testing.T, c elliptic.Curve) {
155 priv, _ := GenerateKey(c, rand.Reader)
156
157 hashed := []byte("testing")
158 r0, s0, err := Sign(rand.Reader, priv, hashed)
159 if err != nil {
160 t.Errorf("error signing: %s", err)
161 return
162 }
163
164 r1, s1, err := Sign(rand.Reader, priv, hashed)
165 if err != nil {
166 t.Errorf("error signing: %s", err)
167 return
168 }
169
170 if s0.Cmp(s1) == 0 {
171 t.Errorf("two signatures of the same message produced the same result")
172 }
173
174 if r0.Cmp(r1) == 0 {
175 t.Errorf("two signatures of the same message produced the same nonce")
176 }
177 }
178
179 func fromHex(s string) *big.Int {
180 r, ok := new(big.Int).SetString(s, 16)
181 if !ok {
182 panic("bad hex")
183 }
184 return r
185 }
186
187 func TestVectors(t *testing.T) {
188
189
190
191
192
193
194 if testing.Short() {
195 return
196 }
197
198 f, err := os.Open("testdata/SigVer.rsp.bz2")
199 if err != nil {
200 t.Fatal(err)
201 }
202
203 buf := bufio.NewReader(bzip2.NewReader(f))
204
205 lineNo := 1
206 var h hash.Hash
207 var msg []byte
208 var hashed []byte
209 var r, s *big.Int
210 pub := new(PublicKey)
211
212 for {
213 line, err := buf.ReadString('\n')
214 if len(line) == 0 {
215 if err == io.EOF {
216 break
217 }
218 t.Fatalf("error reading from input: %s", err)
219 }
220 lineNo++
221
222 if !strings.HasSuffix(line, "\r\n") {
223 t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
224 }
225 line = line[:len(line)-2]
226
227 if len(line) == 0 || line[0] == '#' {
228 continue
229 }
230
231 if line[0] == '[' {
232 line = line[1 : len(line)-1]
233 curve, hash, _ := strings.Cut(line, ",")
234
235 switch curve {
236 case "P-224":
237 pub.Curve = elliptic.P224()
238 case "P-256":
239 pub.Curve = elliptic.P256()
240 case "P-384":
241 pub.Curve = elliptic.P384()
242 case "P-521":
243 pub.Curve = elliptic.P521()
244 default:
245 pub.Curve = nil
246 }
247
248 switch hash {
249 case "SHA-1":
250 h = sha1.New()
251 case "SHA-224":
252 h = sha256.New224()
253 case "SHA-256":
254 h = sha256.New()
255 case "SHA-384":
256 h = sha512.New384()
257 case "SHA-512":
258 h = sha512.New()
259 default:
260 h = nil
261 }
262
263 continue
264 }
265
266 if h == nil || pub.Curve == nil {
267 continue
268 }
269
270 switch {
271 case strings.HasPrefix(line, "Msg = "):
272 if msg, err = hex.DecodeString(line[6:]); err != nil {
273 t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
274 }
275 case strings.HasPrefix(line, "Qx = "):
276 pub.X = fromHex(line[5:])
277 case strings.HasPrefix(line, "Qy = "):
278 pub.Y = fromHex(line[5:])
279 case strings.HasPrefix(line, "R = "):
280 r = fromHex(line[4:])
281 case strings.HasPrefix(line, "S = "):
282 s = fromHex(line[4:])
283 case strings.HasPrefix(line, "Result = "):
284 expected := line[9] == 'P'
285 h.Reset()
286 h.Write(msg)
287 hashed := h.Sum(hashed[:0])
288 if Verify(pub, hashed, r, s) != expected {
289 t.Fatalf("incorrect result on line %d", lineNo)
290 }
291 default:
292 t.Fatalf("unknown variable on line %d: %s", lineNo, line)
293 }
294 }
295 }
296
297 func TestNegativeInputs(t *testing.T) {
298 testAllCurves(t, testNegativeInputs)
299 }
300
301 func testNegativeInputs(t *testing.T, curve elliptic.Curve) {
302 key, err := GenerateKey(curve, rand.Reader)
303 if err != nil {
304 t.Errorf("failed to generate key")
305 }
306
307 var hash [32]byte
308 r := new(big.Int).SetInt64(1)
309 r.Lsh(r, 550 )
310 r.Neg(r)
311
312 if Verify(&key.PublicKey, hash[:], r, r) {
313 t.Errorf("bogus signature accepted")
314 }
315 }
316
317 func TestZeroHashSignature(t *testing.T) {
318 testAllCurves(t, testZeroHashSignature)
319 }
320
321 func testZeroHashSignature(t *testing.T, curve elliptic.Curve) {
322 zeroHash := make([]byte, 64)
323
324 privKey, err := GenerateKey(curve, rand.Reader)
325 if err != nil {
326 panic(err)
327 }
328
329
330 r, s, err := Sign(rand.Reader, privKey, zeroHash)
331 if err != nil {
332 panic(err)
333 }
334
335
336 if !Verify(&privKey.PublicKey, zeroHash, r, s) {
337 t.Errorf("zero hash signature verify failed for %T", curve)
338 }
339 }
340
341 func TestRandomPoint(t *testing.T) {
342 t.Run("P-224", func(t *testing.T) { testRandomPoint(t, p224()) })
343 t.Run("P-256", func(t *testing.T) { testRandomPoint(t, p256()) })
344 t.Run("P-384", func(t *testing.T) { testRandomPoint(t, p384()) })
345 t.Run("P-521", func(t *testing.T) { testRandomPoint(t, p521()) })
346 }
347
348 func testRandomPoint[Point nistPoint[Point]](t *testing.T, c *nistCurve[Point]) {
349 t.Cleanup(func() { testingOnlyRejectionSamplingLooped = nil })
350 var loopCount int
351 testingOnlyRejectionSamplingLooped = func() { loopCount++ }
352
353
354
355 r := io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0xff}, 100)), rand.Reader)
356 if k, p, err := randomPoint(c, r); err != nil {
357 t.Fatal(err)
358 } else if k.IsZero() == 1 {
359 t.Error("k is zero")
360 } else if p.Bytes()[0] != 4 {
361 t.Error("p is infinity")
362 }
363 if loopCount == 0 {
364 t.Error("overflow was not rejected")
365 }
366 loopCount = 0
367
368
369 r = io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0}, 100)), rand.Reader)
370 if k, p, err := randomPoint(c, r); err != nil {
371 t.Fatal(err)
372 } else if k.IsZero() == 1 {
373 t.Error("k is zero")
374 } else if p.Bytes()[0] != 4 {
375 t.Error("p is infinity")
376 }
377 if loopCount == 0 {
378 t.Error("zero was not rejected")
379 }
380 loopCount = 0
381
382
383
384
385
386 if c.curve == elliptic.P256() {
387 return
388 }
389 if k, p, err := randomPoint(c, rand.Reader); err != nil {
390 t.Fatal(err)
391 } else if k.IsZero() == 1 {
392 t.Error("k is zero")
393 } else if p.Bytes()[0] != 4 {
394 t.Error("p is infinity")
395 }
396 if loopCount > 0 {
397 t.Error("unexpected rejection")
398 }
399 }
400
401 func TestZeroSignature(t *testing.T) {
402 testAllCurves(t, testZeroSignature)
403 }
404
405 func testZeroSignature(t *testing.T, curve elliptic.Curve) {
406 privKey, err := GenerateKey(curve, rand.Reader)
407 if err != nil {
408 panic(err)
409 }
410
411 if Verify(&privKey.PublicKey, make([]byte, 64), big.NewInt(0), big.NewInt(0)) {
412 t.Errorf("Verify with r,s=0 succeeded: %T", curve)
413 }
414 }
415
416 func TestNegtativeSignature(t *testing.T) {
417 testAllCurves(t, testNegativeSignature)
418 }
419
420 func testNegativeSignature(t *testing.T, curve elliptic.Curve) {
421 zeroHash := make([]byte, 64)
422
423 privKey, err := GenerateKey(curve, rand.Reader)
424 if err != nil {
425 panic(err)
426 }
427 r, s, err := Sign(rand.Reader, privKey, zeroHash)
428 if err != nil {
429 panic(err)
430 }
431
432 r = r.Neg(r)
433 if Verify(&privKey.PublicKey, zeroHash, r, s) {
434 t.Errorf("Verify with r=-r succeeded: %T", curve)
435 }
436 }
437
438 func TestRPlusNSignature(t *testing.T) {
439 testAllCurves(t, testRPlusNSignature)
440 }
441
442 func testRPlusNSignature(t *testing.T, curve elliptic.Curve) {
443 zeroHash := make([]byte, 64)
444
445 privKey, err := GenerateKey(curve, rand.Reader)
446 if err != nil {
447 panic(err)
448 }
449 r, s, err := Sign(rand.Reader, privKey, zeroHash)
450 if err != nil {
451 panic(err)
452 }
453
454 r = r.Add(r, curve.Params().N)
455 if Verify(&privKey.PublicKey, zeroHash, r, s) {
456 t.Errorf("Verify with r=r+n succeeded: %T", curve)
457 }
458 }
459
460 func TestRMinusNSignature(t *testing.T) {
461 testAllCurves(t, testRMinusNSignature)
462 }
463
464 func testRMinusNSignature(t *testing.T, curve elliptic.Curve) {
465 zeroHash := make([]byte, 64)
466
467 privKey, err := GenerateKey(curve, rand.Reader)
468 if err != nil {
469 panic(err)
470 }
471 r, s, err := Sign(rand.Reader, privKey, zeroHash)
472 if err != nil {
473 panic(err)
474 }
475
476 r = r.Sub(r, curve.Params().N)
477 if Verify(&privKey.PublicKey, zeroHash, r, s) {
478 t.Errorf("Verify with r=r-n succeeded: %T", curve)
479 }
480 }
481
482 func randomPointForCurve(curve elliptic.Curve, rand io.Reader) error {
483 switch curve.Params() {
484 case elliptic.P224().Params():
485 _, _, err := randomPoint(p224(), rand)
486 return err
487 case elliptic.P256().Params():
488 _, _, err := randomPoint(p256(), rand)
489 return err
490 case elliptic.P384().Params():
491 _, _, err := randomPoint(p384(), rand)
492 return err
493 case elliptic.P521().Params():
494 _, _, err := randomPoint(p521(), rand)
495 return err
496 default:
497 panic("unknown curve")
498 }
499 }
500
501 func benchmarkAllCurves(b *testing.B, f func(*testing.B, elliptic.Curve)) {
502 tests := []struct {
503 name string
504 curve elliptic.Curve
505 }{
506 {"P256", elliptic.P256()},
507 {"P384", elliptic.P384()},
508 {"P521", elliptic.P521()},
509 }
510 for _, test := range tests {
511 curve := test.curve
512 b.Run(test.name, func(b *testing.B) {
513 f(b, curve)
514 })
515 }
516 }
517
518 func BenchmarkSign(b *testing.B) {
519 benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
520 r := bufio.NewReaderSize(rand.Reader, 1<<15)
521 priv, err := GenerateKey(curve, r)
522 if err != nil {
523 b.Fatal(err)
524 }
525 hashed := []byte("testing")
526
527 b.ReportAllocs()
528 b.ResetTimer()
529 for i := 0; i < b.N; i++ {
530 sig, err := SignASN1(r, priv, hashed)
531 if err != nil {
532 b.Fatal(err)
533 }
534
535 hashed[0] = sig[0]
536 }
537 })
538 }
539
540 func BenchmarkVerify(b *testing.B) {
541 benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
542 r := bufio.NewReaderSize(rand.Reader, 1<<15)
543 priv, err := GenerateKey(curve, r)
544 if err != nil {
545 b.Fatal(err)
546 }
547 hashed := []byte("testing")
548 sig, err := SignASN1(r, priv, hashed)
549 if err != nil {
550 b.Fatal(err)
551 }
552
553 b.ReportAllocs()
554 b.ResetTimer()
555 for i := 0; i < b.N; i++ {
556 if !VerifyASN1(&priv.PublicKey, hashed, sig) {
557 b.Fatal("verify failed")
558 }
559 }
560 })
561 }
562
563 func BenchmarkGenerateKey(b *testing.B) {
564 benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
565 r := bufio.NewReaderSize(rand.Reader, 1<<15)
566 b.ReportAllocs()
567 b.ResetTimer()
568 for i := 0; i < b.N; i++ {
569 if _, err := GenerateKey(curve, r); err != nil {
570 b.Fatal(err)
571 }
572 }
573 })
574 }
575
View as plain text