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 testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) { 46 priv, _ := GenerateKey(c, rand.Reader) 47 48 hashed := []byte("testing") 49 r, s, err := Sign(rand.Reader, priv, hashed) 50 if err != nil { 51 t.Errorf("%s: error signing: %s", tag, err) 52 return 53 } 54 55 if !Verify(&priv.PublicKey, hashed, r, s) { 56 t.Errorf("%s: Verify failed", tag) 57 } 58 59 hashed[0] ^= 0xff 60 if Verify(&priv.PublicKey, hashed, r, s) { 61 t.Errorf("%s: Verify always works!", tag) 62 } 63 } 64 65 func TestSignAndVerify(t *testing.T) { 66 testSignAndVerify(t, elliptic.P224(), "p224") 67 if testing.Short() { 68 return 69 } 70 testSignAndVerify(t, elliptic.P256(), "p256") 71 testSignAndVerify(t, elliptic.P384(), "p384") 72 testSignAndVerify(t, elliptic.P521(), "p521") 73 } 74 75 func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) { 76 priv, _ := GenerateKey(c, rand.Reader) 77 78 hashed := []byte("testing") 79 r0, s0, err := Sign(zeroReader, priv, hashed) 80 if err != nil { 81 t.Errorf("%s: error signing: %s", tag, err) 82 return 83 } 84 85 hashed = []byte("testing...") 86 r1, s1, err := Sign(zeroReader, priv, hashed) 87 if err != nil { 88 t.Errorf("%s: error signing: %s", tag, err) 89 return 90 } 91 92 if s0.Cmp(s1) == 0 { 93 // This should never happen. 94 t.Errorf("%s: the signatures on two different messages were the same") 95 } 96 97 if r0.Cmp(r1) == 0 { 98 t.Errorf("%s: the nonce used for two diferent messages was the same") 99 } 100 } 101 102 func TestNonceSafety(t *testing.T) { 103 testNonceSafety(t, elliptic.P224(), "p224") 104 if testing.Short() { 105 return 106 } 107 testNonceSafety(t, elliptic.P256(), "p256") 108 testNonceSafety(t, elliptic.P384(), "p384") 109 testNonceSafety(t, elliptic.P521(), "p521") 110 } 111 112 func testINDCCA(t *testing.T, c elliptic.Curve, tag string) { 113 priv, _ := GenerateKey(c, rand.Reader) 114 115 hashed := []byte("testing") 116 r0, s0, err := Sign(rand.Reader, priv, hashed) 117 if err != nil { 118 t.Errorf("%s: error signing: %s", tag, err) 119 return 120 } 121 122 r1, s1, err := Sign(rand.Reader, priv, hashed) 123 if err != nil { 124 t.Errorf("%s: error signing: %s", tag, err) 125 return 126 } 127 128 if s0.Cmp(s1) == 0 { 129 t.Errorf("%s: two signatures of the same message produced the same result") 130 } 131 132 if r0.Cmp(r1) == 0 { 133 t.Errorf("%s: two signatures of the same message produced the same nonce") 134 } 135 } 136 137 func TestINDCCA(t *testing.T) { 138 testINDCCA(t, elliptic.P224(), "p224") 139 if testing.Short() { 140 return 141 } 142 testINDCCA(t, elliptic.P256(), "p256") 143 testINDCCA(t, elliptic.P384(), "p384") 144 testINDCCA(t, elliptic.P521(), "p521") 145 } 146 147 func fromHex(s string) *big.Int { 148 r, ok := new(big.Int).SetString(s, 16) 149 if !ok { 150 panic("bad hex") 151 } 152 return r 153 } 154 155 func TestVectors(t *testing.T) { 156 // This test runs the full set of NIST test vectors from 157 // http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip 158 // 159 // The SigVer.rsp file has been edited to remove test vectors for 160 // unsupported algorithms and has been compressed. 161 162 if testing.Short() { 163 return 164 } 165 166 f, err := os.Open("testdata/SigVer.rsp.bz2") 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 buf := bufio.NewReader(bzip2.NewReader(f)) 172 173 lineNo := 1 174 var h hash.Hash 175 var msg []byte 176 var hashed []byte 177 var r, s *big.Int 178 pub := new(PublicKey) 179 180 for { 181 line, err := buf.ReadString('\n') 182 if len(line) == 0 { 183 if err == io.EOF { 184 break 185 } 186 t.Fatalf("error reading from input: %s", err) 187 } 188 lineNo++ 189 // Need to remove \r\n from the end of the line. 190 if !strings.HasSuffix(line, "\r\n") { 191 t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo) 192 } 193 line = line[:len(line)-2] 194 195 if len(line) == 0 || line[0] == '#' { 196 continue 197 } 198 199 if line[0] == '[' { 200 line = line[1 : len(line)-1] 201 parts := strings.SplitN(line, ",", 2) 202 203 switch parts[0] { 204 case "P-224": 205 pub.Curve = elliptic.P224() 206 case "P-256": 207 pub.Curve = elliptic.P256() 208 case "P-384": 209 pub.Curve = elliptic.P384() 210 case "P-521": 211 pub.Curve = elliptic.P521() 212 default: 213 pub.Curve = nil 214 } 215 216 switch parts[1] { 217 case "SHA-1": 218 h = sha1.New() 219 case "SHA-224": 220 h = sha256.New224() 221 case "SHA-256": 222 h = sha256.New() 223 case "SHA-384": 224 h = sha512.New384() 225 case "SHA-512": 226 h = sha512.New() 227 default: 228 h = nil 229 } 230 231 continue 232 } 233 234 if h == nil || pub.Curve == nil { 235 continue 236 } 237 238 switch { 239 case strings.HasPrefix(line, "Msg = "): 240 if msg, err = hex.DecodeString(line[6:]); err != nil { 241 t.Fatalf("failed to decode message on line %d: %s", lineNo, err) 242 } 243 case strings.HasPrefix(line, "Qx = "): 244 pub.X = fromHex(line[5:]) 245 case strings.HasPrefix(line, "Qy = "): 246 pub.Y = fromHex(line[5:]) 247 case strings.HasPrefix(line, "R = "): 248 r = fromHex(line[4:]) 249 case strings.HasPrefix(line, "S = "): 250 s = fromHex(line[4:]) 251 case strings.HasPrefix(line, "Result = "): 252 expected := line[9] == 'P' 253 h.Reset() 254 h.Write(msg) 255 hashed := h.Sum(hashed[:0]) 256 if Verify(pub, hashed, r, s) != expected { 257 t.Fatalf("incorrect result on line %d", lineNo) 258 } 259 default: 260 t.Fatalf("unknown variable on line %d: %s", lineNo, line) 261 } 262 } 263 } 264