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

View as plain text