Black Lives Matter. Support the Equal Justice Initiative.

Source file src/crypto/ecdsa/ecdsa_test.go

Documentation: crypto/ecdsa

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ecdsa
     6  
     7  import (
     8  	"bufio"
     9  	"compress/bzip2"
    10  	"crypto/elliptic"
    11  	"crypto/rand"
    12  	"crypto/sha1"
    13  	"crypto/sha256"
    14  	"crypto/sha512"
    15  	"encoding/hex"
    16  	"hash"
    17  	"io"
    18  	"math/big"
    19  	"os"
    20  	"strings"
    21  	"testing"
    22  )
    23  
    24  func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) {
    25  	tests := []struct {
    26  		name  string
    27  		curve elliptic.Curve
    28  	}{
    29  		{"P256", elliptic.P256()},
    30  		{"P224", elliptic.P224()},
    31  		{"P384", elliptic.P384()},
    32  		{"P521", elliptic.P521()},
    33  	}
    34  	if testing.Short() {
    35  		tests = tests[:1]
    36  	}
    37  	for _, test := range tests {
    38  		curve := test.curve
    39  		t.Run(test.name, func(t *testing.T) {
    40  			t.Parallel()
    41  			f(t, curve)
    42  		})
    43  	}
    44  }
    45  
    46  func TestKeyGeneration(t *testing.T) {
    47  	testAllCurves(t, testKeyGeneration)
    48  }
    49  
    50  func testKeyGeneration(t *testing.T, c elliptic.Curve) {
    51  	priv, err := GenerateKey(c, rand.Reader)
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
    56  		t.Errorf("public key invalid: %s", err)
    57  	}
    58  }
    59  
    60  func TestSignAndVerify(t *testing.T) {
    61  	testAllCurves(t, testSignAndVerify)
    62  }
    63  
    64  func testSignAndVerify(t *testing.T, c elliptic.Curve) {
    65  	priv, _ := GenerateKey(c, rand.Reader)
    66  
    67  	hashed := []byte("testing")
    68  	r, s, err := Sign(rand.Reader, priv, hashed)
    69  	if err != nil {
    70  		t.Errorf("error signing: %s", err)
    71  		return
    72  	}
    73  
    74  	if !Verify(&priv.PublicKey, hashed, r, s) {
    75  		t.Errorf("Verify failed")
    76  	}
    77  
    78  	hashed[0] ^= 0xff
    79  	if Verify(&priv.PublicKey, hashed, r, s) {
    80  		t.Errorf("Verify always works!")
    81  	}
    82  }
    83  
    84  func TestSignAndVerifyASN1(t *testing.T) {
    85  	testAllCurves(t, testSignAndVerifyASN1)
    86  }
    87  
    88  func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve) {
    89  	priv, _ := GenerateKey(c, rand.Reader)
    90  
    91  	hashed := []byte("testing")
    92  	sig, err := SignASN1(rand.Reader, priv, hashed)
    93  	if err != nil {
    94  		t.Errorf("error signing: %s", err)
    95  		return
    96  	}
    97  
    98  	if !VerifyASN1(&priv.PublicKey, hashed, sig) {
    99  		t.Errorf("VerifyASN1 failed")
   100  	}
   101  
   102  	hashed[0] ^= 0xff
   103  	if VerifyASN1(&priv.PublicKey, hashed, sig) {
   104  		t.Errorf("VerifyASN1 always works!")
   105  	}
   106  }
   107  
   108  func TestNonceSafety(t *testing.T) {
   109  	testAllCurves(t, testNonceSafety)
   110  }
   111  
   112  func testNonceSafety(t *testing.T, c elliptic.Curve) {
   113  	priv, _ := GenerateKey(c, rand.Reader)
   114  
   115  	hashed := []byte("testing")
   116  	r0, s0, err := Sign(zeroReader, priv, hashed)
   117  	if err != nil {
   118  		t.Errorf("error signing: %s", err)
   119  		return
   120  	}
   121  
   122  	hashed = []byte("testing...")
   123  	r1, s1, err := Sign(zeroReader, priv, hashed)
   124  	if err != nil {
   125  		t.Errorf("error signing: %s", err)
   126  		return
   127  	}
   128  
   129  	if s0.Cmp(s1) == 0 {
   130  		// This should never happen.
   131  		t.Errorf("the signatures on two different messages were the same")
   132  	}
   133  
   134  	if r0.Cmp(r1) == 0 {
   135  		t.Errorf("the nonce used for two different messages was the same")
   136  	}
   137  }
   138  
   139  func TestINDCCA(t *testing.T) {
   140  	testAllCurves(t, testINDCCA)
   141  }
   142  
   143  func testINDCCA(t *testing.T, c elliptic.Curve) {
   144  	priv, _ := GenerateKey(c, rand.Reader)
   145  
   146  	hashed := []byte("testing")
   147  	r0, s0, err := Sign(rand.Reader, priv, hashed)
   148  	if err != nil {
   149  		t.Errorf("error signing: %s", err)
   150  		return
   151  	}
   152  
   153  	r1, s1, err := Sign(rand.Reader, priv, hashed)
   154  	if err != nil {
   155  		t.Errorf("error signing: %s", err)
   156  		return
   157  	}
   158  
   159  	if s0.Cmp(s1) == 0 {
   160  		t.Errorf("two signatures of the same message produced the same result")
   161  	}
   162  
   163  	if r0.Cmp(r1) == 0 {
   164  		t.Errorf("two signatures of the same message produced the same nonce")
   165  	}
   166  }
   167  
   168  func fromHex(s string) *big.Int {
   169  	r, ok := new(big.Int).SetString(s, 16)
   170  	if !ok {
   171  		panic("bad hex")
   172  	}
   173  	return r
   174  }
   175  
   176  func TestVectors(t *testing.T) {
   177  	// This test runs the full set of NIST test vectors from
   178  	// https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
   179  	//
   180  	// The SigVer.rsp file has been edited to remove test vectors for
   181  	// unsupported algorithms and has been compressed.
   182  
   183  	if testing.Short() {
   184  		return
   185  	}
   186  
   187  	f, err := os.Open("testdata/SigVer.rsp.bz2")
   188  	if err != nil {
   189  		t.Fatal(err)
   190  	}
   191  
   192  	buf := bufio.NewReader(bzip2.NewReader(f))
   193  
   194  	lineNo := 1
   195  	var h hash.Hash
   196  	var msg []byte
   197  	var hashed []byte
   198  	var r, s *big.Int
   199  	pub := new(PublicKey)
   200  
   201  	for {
   202  		line, err := buf.ReadString('\n')
   203  		if len(line) == 0 {
   204  			if err == io.EOF {
   205  				break
   206  			}
   207  			t.Fatalf("error reading from input: %s", err)
   208  		}
   209  		lineNo++
   210  		// Need to remove \r\n from the end of the line.
   211  		if !strings.HasSuffix(line, "\r\n") {
   212  			t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
   213  		}
   214  		line = line[:len(line)-2]
   215  
   216  		if len(line) == 0 || line[0] == '#' {
   217  			continue
   218  		}
   219  
   220  		if line[0] == '[' {
   221  			line = line[1 : len(line)-1]
   222  			parts := strings.SplitN(line, ",", 2)
   223  
   224  			switch parts[0] {
   225  			case "P-224":
   226  				pub.Curve = elliptic.P224()
   227  			case "P-256":
   228  				pub.Curve = elliptic.P256()
   229  			case "P-384":
   230  				pub.Curve = elliptic.P384()
   231  			case "P-521":
   232  				pub.Curve = elliptic.P521()
   233  			default:
   234  				pub.Curve = nil
   235  			}
   236  
   237  			switch parts[1] {
   238  			case "SHA-1":
   239  				h = sha1.New()
   240  			case "SHA-224":
   241  				h = sha256.New224()
   242  			case "SHA-256":
   243  				h = sha256.New()
   244  			case "SHA-384":
   245  				h = sha512.New384()
   246  			case "SHA-512":
   247  				h = sha512.New()
   248  			default:
   249  				h = nil
   250  			}
   251  
   252  			continue
   253  		}
   254  
   255  		if h == nil || pub.Curve == nil {
   256  			continue
   257  		}
   258  
   259  		switch {
   260  		case strings.HasPrefix(line, "Msg = "):
   261  			if msg, err = hex.DecodeString(line[6:]); err != nil {
   262  				t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
   263  			}
   264  		case strings.HasPrefix(line, "Qx = "):
   265  			pub.X = fromHex(line[5:])
   266  		case strings.HasPrefix(line, "Qy = "):
   267  			pub.Y = fromHex(line[5:])
   268  		case strings.HasPrefix(line, "R = "):
   269  			r = fromHex(line[4:])
   270  		case strings.HasPrefix(line, "S = "):
   271  			s = fromHex(line[4:])
   272  		case strings.HasPrefix(line, "Result = "):
   273  			expected := line[9] == 'P'
   274  			h.Reset()
   275  			h.Write(msg)
   276  			hashed := h.Sum(hashed[:0])
   277  			if Verify(pub, hashed, r, s) != expected {
   278  				t.Fatalf("incorrect result on line %d", lineNo)
   279  			}
   280  		default:
   281  			t.Fatalf("unknown variable on line %d: %s", lineNo, line)
   282  		}
   283  	}
   284  }
   285  
   286  func TestNegativeInputs(t *testing.T) {
   287  	testAllCurves(t, testNegativeInputs)
   288  }
   289  
   290  func testNegativeInputs(t *testing.T, curve elliptic.Curve) {
   291  	key, err := GenerateKey(curve, rand.Reader)
   292  	if err != nil {
   293  		t.Errorf("failed to generate key")
   294  	}
   295  
   296  	var hash [32]byte
   297  	r := new(big.Int).SetInt64(1)
   298  	r.Lsh(r, 550 /* larger than any supported curve */)
   299  	r.Neg(r)
   300  
   301  	if Verify(&key.PublicKey, hash[:], r, r) {
   302  		t.Errorf("bogus signature accepted")
   303  	}
   304  }
   305  
   306  func TestZeroHashSignature(t *testing.T) {
   307  	testAllCurves(t, testZeroHashSignature)
   308  }
   309  
   310  func testZeroHashSignature(t *testing.T, curve elliptic.Curve) {
   311  	zeroHash := make([]byte, 64)
   312  
   313  	privKey, err := GenerateKey(curve, rand.Reader)
   314  	if err != nil {
   315  		panic(err)
   316  	}
   317  
   318  	// Sign a hash consisting of all zeros.
   319  	r, s, err := Sign(rand.Reader, privKey, zeroHash)
   320  	if err != nil {
   321  		panic(err)
   322  	}
   323  
   324  	// Confirm that it can be verified.
   325  	if !Verify(&privKey.PublicKey, zeroHash, r, s) {
   326  		t.Errorf("zero hash signature verify failed for %T", curve)
   327  	}
   328  }
   329  
   330  func benchmarkAllCurves(t *testing.B, f func(*testing.B, elliptic.Curve)) {
   331  	tests := []struct {
   332  		name  string
   333  		curve elliptic.Curve
   334  	}{
   335  		{"P256", elliptic.P256()},
   336  		{"P224", elliptic.P224()},
   337  		{"P384", elliptic.P384()},
   338  		{"P521", elliptic.P521()},
   339  	}
   340  	for _, test := range tests {
   341  		curve := test.curve
   342  		t.Run(test.name, func(t *testing.B) {
   343  			f(t, curve)
   344  		})
   345  	}
   346  }
   347  
   348  func BenchmarkSign(b *testing.B) {
   349  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   350  		priv, err := GenerateKey(curve, rand.Reader)
   351  		if err != nil {
   352  			b.Fatal(err)
   353  		}
   354  		hashed := []byte("testing")
   355  
   356  		b.ReportAllocs()
   357  		b.ResetTimer()
   358  		for i := 0; i < b.N; i++ {
   359  			sig, err := SignASN1(rand.Reader, priv, hashed)
   360  			if err != nil {
   361  				b.Fatal(err)
   362  			}
   363  			// Prevent the compiler from optimizing out the operation.
   364  			hashed[0] = sig[0]
   365  		}
   366  	})
   367  }
   368  
   369  func BenchmarkVerify(b *testing.B) {
   370  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   371  		priv, err := GenerateKey(curve, rand.Reader)
   372  		if err != nil {
   373  			b.Fatal(err)
   374  		}
   375  		hashed := []byte("testing")
   376  		r, s, err := Sign(rand.Reader, priv, hashed)
   377  		if err != nil {
   378  			b.Fatal(err)
   379  		}
   380  
   381  		b.ReportAllocs()
   382  		b.ResetTimer()
   383  		for i := 0; i < b.N; i++ {
   384  			if !Verify(&priv.PublicKey, hashed, r, s) {
   385  				b.Fatal("verify failed")
   386  			}
   387  		}
   388  	})
   389  }
   390  
   391  func BenchmarkGenerateKey(b *testing.B) {
   392  	benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
   393  		b.ReportAllocs()
   394  		b.ResetTimer()
   395  		for i := 0; i < b.N; i++ {
   396  			if _, err := GenerateKey(curve, rand.Reader); err != nil {
   397  				b.Fatal(err)
   398  			}
   399  		}
   400  	})
   401  }
   402  

View as plain text