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  }