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