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