github.com/karalabe/go-ethereum@v0.8.5/crypto/ecies/ecies_test.go (about) 1 package ecies 2 3 import ( 4 "bytes" 5 "crypto/elliptic" 6 "crypto/rand" 7 "crypto/sha256" 8 "flag" 9 "fmt" 10 "io/ioutil" 11 "testing" 12 ) 13 14 var dumpEnc bool 15 16 func init() { 17 flDump := flag.Bool("dump", false, "write encrypted test message to file") 18 flag.Parse() 19 dumpEnc = *flDump 20 } 21 22 // Ensure the KDF generates appropriately sized keys. 23 func TestKDF(t *testing.T) { 24 msg := []byte("Hello, world") 25 h := sha256.New() 26 27 k, err := concatKDF(h, msg, nil, 64) 28 if err != nil { 29 fmt.Println(err.Error()) 30 t.FailNow() 31 } 32 if len(k) != 64 { 33 fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n", 34 len(k)) 35 t.FailNow() 36 } 37 } 38 39 var skLen int 40 var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") 41 42 // cmpParams compares a set of ECIES parameters. We assume, as per the 43 // docs, that AES is the only supported symmetric encryption algorithm. 44 func cmpParams(p1, p2 *ECIESParams) bool { 45 if p1.hashAlgo != p2.hashAlgo { 46 return false 47 } else if p1.KeyLen != p2.KeyLen { 48 return false 49 } else if p1.BlockSize != p2.BlockSize { 50 return false 51 } 52 return true 53 } 54 55 // cmpPublic returns true if the two public keys represent the same pojnt. 56 func cmpPublic(pub1, pub2 PublicKey) bool { 57 if pub1.X == nil || pub1.Y == nil { 58 fmt.Println(ErrInvalidPublicKey.Error()) 59 return false 60 } 61 if pub2.X == nil || pub2.Y == nil { 62 fmt.Println(ErrInvalidPublicKey.Error()) 63 return false 64 } 65 pub1Out := elliptic.Marshal(pub1.Curve, pub1.X, pub1.Y) 66 pub2Out := elliptic.Marshal(pub2.Curve, pub2.X, pub2.Y) 67 68 return bytes.Equal(pub1Out, pub2Out) 69 } 70 71 // cmpPrivate returns true if the two private keys are the same. 72 func cmpPrivate(prv1, prv2 *PrivateKey) bool { 73 if prv1 == nil || prv1.D == nil { 74 return false 75 } else if prv2 == nil || prv2.D == nil { 76 return false 77 } else if prv1.D.Cmp(prv2.D) != 0 { 78 return false 79 } else { 80 return cmpPublic(prv1.PublicKey, prv2.PublicKey) 81 } 82 } 83 84 // Validate the ECDH component. 85 func TestSharedKey(t *testing.T) { 86 prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) 87 if err != nil { 88 fmt.Println(err.Error()) 89 t.FailNow() 90 } 91 skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2 92 93 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) 94 if err != nil { 95 fmt.Println(err.Error()) 96 t.FailNow() 97 } 98 99 sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen) 100 if err != nil { 101 fmt.Println(err.Error()) 102 t.FailNow() 103 } 104 105 sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen) 106 if err != nil { 107 fmt.Println(err.Error()) 108 t.FailNow() 109 } 110 111 if !bytes.Equal(sk1, sk2) { 112 fmt.Println(ErrBadSharedKeys.Error()) 113 t.FailNow() 114 } 115 } 116 117 // Verify that the key generation code fails when too much key data is 118 // requested. 119 func TestTooBigSharedKey(t *testing.T) { 120 prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) 121 if err != nil { 122 fmt.Println(err.Error()) 123 t.FailNow() 124 } 125 126 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) 127 if err != nil { 128 fmt.Println(err.Error()) 129 t.FailNow() 130 } 131 132 _, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2) 133 if err != ErrSharedKeyTooBig { 134 fmt.Println("ecdh: shared key should be too large for curve") 135 t.FailNow() 136 } 137 138 _, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2) 139 if err != ErrSharedKeyTooBig { 140 fmt.Println("ecdh: shared key should be too large for curve") 141 t.FailNow() 142 } 143 } 144 145 // Ensure a public key can be successfully marshalled and unmarshalled, and 146 // that the decoded key is the same as the original. 147 func TestMarshalPublic(t *testing.T) { 148 prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) 149 if err != nil { 150 fmt.Println(err.Error()) 151 t.FailNow() 152 } 153 154 out, err := MarshalPublic(&prv.PublicKey) 155 if err != nil { 156 fmt.Println(err.Error()) 157 t.FailNow() 158 } 159 160 pub, err := UnmarshalPublic(out) 161 if err != nil { 162 fmt.Println(err.Error()) 163 t.FailNow() 164 } 165 166 if !cmpPublic(prv.PublicKey, *pub) { 167 fmt.Println("ecies: failed to unmarshal public key") 168 t.FailNow() 169 } 170 } 171 172 // Ensure that a private key can be encoded into DER format, and that 173 // the resulting key is properly parsed back into a public key. 174 func TestMarshalPrivate(t *testing.T) { 175 prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) 176 if err != nil { 177 fmt.Println(err.Error()) 178 t.FailNow() 179 } 180 181 out, err := MarshalPrivate(prv) 182 if err != nil { 183 fmt.Println(err.Error()) 184 t.FailNow() 185 } 186 187 if dumpEnc { 188 ioutil.WriteFile("test.out", out, 0644) 189 } 190 191 prv2, err := UnmarshalPrivate(out) 192 if err != nil { 193 fmt.Println(err.Error()) 194 t.FailNow() 195 } 196 197 if !cmpPrivate(prv, prv2) { 198 fmt.Println("ecdh: private key import failed") 199 t.FailNow() 200 } 201 } 202 203 // Ensure that a private key can be successfully encoded to PEM format, and 204 // the resulting key is properly parsed back in. 205 func TestPrivatePEM(t *testing.T) { 206 prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) 207 if err != nil { 208 fmt.Println(err.Error()) 209 t.FailNow() 210 } 211 212 out, err := ExportPrivatePEM(prv) 213 if err != nil { 214 fmt.Println(err.Error()) 215 t.FailNow() 216 } 217 218 if dumpEnc { 219 ioutil.WriteFile("test.key", out, 0644) 220 } 221 222 prv2, err := ImportPrivatePEM(out) 223 if err != nil { 224 fmt.Println(err.Error()) 225 t.FailNow() 226 } else if !cmpPrivate(prv, prv2) { 227 fmt.Println("ecdh: import from PEM failed") 228 t.FailNow() 229 } 230 } 231 232 // Ensure that a public key can be successfully encoded to PEM format, and 233 // the resulting key is properly parsed back in. 234 func TestPublicPEM(t *testing.T) { 235 prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) 236 if err != nil { 237 fmt.Println(err.Error()) 238 t.FailNow() 239 } 240 241 out, err := ExportPublicPEM(&prv.PublicKey) 242 if err != nil { 243 fmt.Println(err.Error()) 244 t.FailNow() 245 } 246 247 if dumpEnc { 248 ioutil.WriteFile("test.pem", out, 0644) 249 } 250 251 pub2, err := ImportPublicPEM(out) 252 if err != nil { 253 fmt.Println(err.Error()) 254 t.FailNow() 255 } else if !cmpPublic(prv.PublicKey, *pub2) { 256 fmt.Println("ecdh: import from PEM failed") 257 t.FailNow() 258 } 259 } 260 261 // Benchmark the generation of P256 keys. 262 func BenchmarkGenerateKeyP256(b *testing.B) { 263 for i := 0; i < b.N; i++ { 264 if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil { 265 fmt.Println(err.Error()) 266 b.FailNow() 267 } 268 } 269 } 270 271 // Benchmark the generation of P256 shared keys. 272 func BenchmarkGenSharedKeyP256(b *testing.B) { 273 prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil) 274 if err != nil { 275 fmt.Println(err.Error()) 276 b.FailNow() 277 } 278 279 for i := 0; i < b.N; i++ { 280 _, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen) 281 if err != nil { 282 fmt.Println(err.Error()) 283 b.FailNow() 284 } 285 } 286 } 287 288 // Verify that an encrypted message can be successfully decrypted. 289 func TestEncryptDecrypt(t *testing.T) { 290 prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) 291 if err != nil { 292 fmt.Println(err.Error()) 293 t.FailNow() 294 } 295 296 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) 297 if err != nil { 298 fmt.Println(err.Error()) 299 t.FailNow() 300 } 301 302 message := []byte("Hello, world.") 303 ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) 304 if err != nil { 305 fmt.Println(err.Error()) 306 t.FailNow() 307 } 308 309 pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) 310 if err != nil { 311 fmt.Println(err.Error()) 312 t.FailNow() 313 } 314 315 if !bytes.Equal(pt, message) { 316 fmt.Println("ecies: plaintext doesn't match message") 317 t.FailNow() 318 } 319 320 _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) 321 if err == nil { 322 fmt.Println("ecies: encryption should not have succeeded") 323 t.FailNow() 324 } 325 } 326 327 // TestMarshalEncryption validates the encode/decode produces a valid 328 // ECIES encryption key. 329 func TestMarshalEncryption(t *testing.T) { 330 prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) 331 if err != nil { 332 fmt.Println(err.Error()) 333 t.FailNow() 334 } 335 336 out, err := MarshalPrivate(prv1) 337 if err != nil { 338 fmt.Println(err.Error()) 339 t.FailNow() 340 } 341 342 prv2, err := UnmarshalPrivate(out) 343 if err != nil { 344 fmt.Println(err.Error()) 345 t.FailNow() 346 } 347 348 message := []byte("Hello, world.") 349 ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) 350 if err != nil { 351 fmt.Println(err.Error()) 352 t.FailNow() 353 } 354 355 pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) 356 if err != nil { 357 fmt.Println(err.Error()) 358 t.FailNow() 359 } 360 361 if !bytes.Equal(pt, message) { 362 fmt.Println("ecies: plaintext doesn't match message") 363 t.FailNow() 364 } 365 366 _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) 367 if err != nil { 368 fmt.Println(err.Error()) 369 t.FailNow() 370 } 371 372 } 373 374 type testCase struct { 375 Curve elliptic.Curve 376 Name string 377 Expected bool 378 } 379 380 var testCases = []testCase{ 381 testCase{ 382 Curve: elliptic.P224(), 383 Name: "P224", 384 Expected: false, 385 }, 386 testCase{ 387 Curve: elliptic.P256(), 388 Name: "P256", 389 Expected: true, 390 }, 391 testCase{ 392 Curve: elliptic.P384(), 393 Name: "P384", 394 Expected: true, 395 }, 396 testCase{ 397 Curve: elliptic.P521(), 398 Name: "P521", 399 Expected: true, 400 }, 401 } 402 403 // Test parameter selection for each curve, and that P224 fails automatic 404 // parameter selection (see README for a discussion of P224). Ensures that 405 // selecting a set of parameters automatically for the given curve works. 406 func TestParamSelection(t *testing.T) { 407 for _, c := range testCases { 408 testParamSelection(t, c) 409 } 410 } 411 412 func testParamSelection(t *testing.T, c testCase) { 413 params := ParamsFromCurve(c.Curve) 414 if params == nil && c.Expected { 415 fmt.Printf("%s (%s)\n", ErrInvalidParams.Error(), c.Name) 416 t.FailNow() 417 } else if params != nil && !c.Expected { 418 fmt.Printf("ecies: parameters should be invalid (%s)\n", 419 c.Name) 420 t.FailNow() 421 } 422 423 prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) 424 if err != nil { 425 fmt.Printf("%s (%s)\n", err.Error(), c.Name) 426 t.FailNow() 427 } 428 429 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) 430 if err != nil { 431 fmt.Printf("%s (%s)\n", err.Error(), c.Name) 432 t.FailNow() 433 } 434 435 message := []byte("Hello, world.") 436 ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) 437 if err != nil { 438 fmt.Printf("%s (%s)\n", err.Error(), c.Name) 439 t.FailNow() 440 } 441 442 pt, err := prv2.Decrypt(rand.Reader, ct, nil, nil) 443 if err != nil { 444 fmt.Printf("%s (%s)\n", err.Error(), c.Name) 445 t.FailNow() 446 } 447 448 if !bytes.Equal(pt, message) { 449 fmt.Printf("ecies: plaintext doesn't match message (%s)\n", 450 c.Name) 451 t.FailNow() 452 } 453 454 _, err = prv1.Decrypt(rand.Reader, ct, nil, nil) 455 if err == nil { 456 fmt.Printf("ecies: encryption should not have succeeded (%s)\n", 457 c.Name) 458 t.FailNow() 459 } 460 461 } 462 463 // Ensure that the basic public key validation in the decryption operation 464 // works. 465 func TestBasicKeyValidation(t *testing.T) { 466 badBytes := []byte{0, 1, 5, 6, 7, 8, 9} 467 468 prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) 469 if err != nil { 470 fmt.Println(err.Error()) 471 t.FailNow() 472 } 473 474 message := []byte("Hello, world.") 475 ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil) 476 if err != nil { 477 fmt.Println(err.Error()) 478 t.FailNow() 479 } 480 481 for _, b := range badBytes { 482 ct[0] = b 483 _, err := prv.Decrypt(rand.Reader, ct, nil, nil) 484 if err != ErrInvalidPublicKey { 485 fmt.Println("ecies: validated an invalid key") 486 t.FailNow() 487 } 488 } 489 }