github.com/arjunbeliever/ignite@v0.0.0-20220406110515-46bbbbec2587/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  	"encoding/hex"
    38  	"fmt"
    39  	"math/big"
    40  	"testing"
    41  
    42  	"github.com/arjunbeliever/ignite/crypto"
    43  )
    44  
    45  func TestKDF(t *testing.T) {
    46  	tests := []struct {
    47  		length int
    48  		output []byte
    49  	}{
    50  		{6, decode("858b192fa2ed")},
    51  		{32, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0")},
    52  		{48, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955")},
    53  		{64, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955f3467fd6672cce1024c5b1effccc0f61")},
    54  	}
    55  
    56  	for _, test := range tests {
    57  		h := sha256.New()
    58  		k := concatKDF(h, []byte("input"), nil, test.length)
    59  		if !bytes.Equal(k, test.output) {
    60  			t.Fatalf("KDF: generated key %x does not match expected output %x", k, test.output)
    61  		}
    62  	}
    63  }
    64  
    65  var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")
    66  
    67  // cmpParams compares a set of ECIES parameters. We assume, as per the
    68  // docs, that AES is the only supported symmetric encryption algorithm.
    69  func cmpParams(p1, p2 *ECIESParams) bool {
    70  	return p1.hashAlgo == p2.hashAlgo &&
    71  		p1.KeyLen == p2.KeyLen &&
    72  		p1.BlockSize == p2.BlockSize
    73  }
    74  
    75  // Validate the ECDH component.
    76  func TestSharedKey(t *testing.T) {
    77  	prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
    82  
    83  	prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  
    88  	sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  
    93  	sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	if !bytes.Equal(sk1, sk2) {
    99  		t.Fatal(ErrBadSharedKeys)
   100  	}
   101  }
   102  
   103  func TestSharedKeyPadding(t *testing.T) {
   104  	// sanity checks
   105  	prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
   106  	prv1 := hexKey("0097a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
   107  	x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
   108  	x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
   109  	y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
   110  	y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16)
   111  
   112  	if prv0.PublicKey.X.Cmp(x0) != 0 {
   113  		t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes())
   114  	}
   115  	if prv0.PublicKey.Y.Cmp(y0) != 0 {
   116  		t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes())
   117  	}
   118  	if prv1.PublicKey.X.Cmp(x1) != 0 {
   119  		t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes())
   120  	}
   121  	if prv1.PublicKey.Y.Cmp(y1) != 0 {
   122  		t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes())
   123  	}
   124  
   125  	// test shared secret generation
   126  	sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16)
   127  	if err != nil {
   128  		t.Log(err.Error())
   129  	}
   130  
   131  	sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16)
   132  	if err != nil {
   133  		t.Fatal(err.Error())
   134  	}
   135  
   136  	if !bytes.Equal(sk1, sk2) {
   137  		t.Fatal(ErrBadSharedKeys.Error())
   138  	}
   139  }
   140  
   141  // Verify that the key generation code fails when too much key data is
   142  // requested.
   143  func TestTooBigSharedKey(t *testing.T) {
   144  	prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	_, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
   155  	if err != ErrSharedKeyTooBig {
   156  		t.Fatal("ecdh: shared key should be too large for curve")
   157  	}
   158  
   159  	_, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
   160  	if err != ErrSharedKeyTooBig {
   161  		t.Fatal("ecdh: shared key should be too large for curve")
   162  	}
   163  }
   164  
   165  // Benchmark the generation of P256 keys.
   166  func BenchmarkGenerateKeyP256(b *testing.B) {
   167  	for i := 0; i < b.N; i++ {
   168  		if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil {
   169  			b.Fatal(err)
   170  		}
   171  	}
   172  }
   173  
   174  // Benchmark the generation of P256 shared keys.
   175  func BenchmarkGenSharedKeyP256(b *testing.B) {
   176  	prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil)
   177  	if err != nil {
   178  		b.Fatal(err)
   179  	}
   180  	b.ResetTimer()
   181  	for i := 0; i < b.N; i++ {
   182  		_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
   183  		if err != nil {
   184  			b.Fatal(err)
   185  		}
   186  	}
   187  }
   188  
   189  // Benchmark the generation of S256 shared keys.
   190  func BenchmarkGenSharedKeyS256(b *testing.B) {
   191  	prv, err := GenerateKey(rand.Reader, crypto.S256(), nil)
   192  	if err != nil {
   193  		b.Fatal(err)
   194  	}
   195  	b.ResetTimer()
   196  	for i := 0; i < b.N; i++ {
   197  		_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
   198  		if err != nil {
   199  			b.Fatal(err)
   200  		}
   201  	}
   202  }
   203  
   204  // Verify that an encrypted message can be successfully decrypted.
   205  func TestEncryptDecrypt(t *testing.T) {
   206  	prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  
   216  	message := []byte("Hello, world.")
   217  	ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  
   222  	pt, err := prv2.Decrypt(ct, nil, nil)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	if !bytes.Equal(pt, message) {
   228  		t.Fatal("ecies: plaintext doesn't match message")
   229  	}
   230  
   231  	_, err = prv1.Decrypt(ct, nil, nil)
   232  	if err == nil {
   233  		t.Fatal("ecies: encryption should not have succeeded")
   234  	}
   235  }
   236  
   237  func TestDecryptShared2(t *testing.T) {
   238  	prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  	message := []byte("Hello, world.")
   243  	shared2 := []byte("shared data 2")
   244  	ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, shared2)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	// Check that decrypting with correct shared data works.
   250  	pt, err := prv.Decrypt(ct, nil, shared2)
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  	if !bytes.Equal(pt, message) {
   255  		t.Fatal("ecies: plaintext doesn't match message")
   256  	}
   257  
   258  	// Decrypting without shared data or incorrect shared data fails.
   259  	if _, err = prv.Decrypt(ct, nil, nil); err == nil {
   260  		t.Fatal("ecies: decrypting without shared data didn't fail")
   261  	}
   262  	if _, err = prv.Decrypt(ct, nil, []byte("garbage")); err == nil {
   263  		t.Fatal("ecies: decrypting with incorrect shared data didn't fail")
   264  	}
   265  }
   266  
   267  type testCase struct {
   268  	Curve    elliptic.Curve
   269  	Name     string
   270  	Expected *ECIESParams
   271  }
   272  
   273  var testCases = []testCase{
   274  	{
   275  		Curve:    elliptic.P256(),
   276  		Name:     "P256",
   277  		Expected: ECIES_AES128_SHA256,
   278  	},
   279  	{
   280  		Curve:    elliptic.P384(),
   281  		Name:     "P384",
   282  		Expected: ECIES_AES256_SHA384,
   283  	},
   284  	{
   285  		Curve:    elliptic.P521(),
   286  		Name:     "P521",
   287  		Expected: ECIES_AES256_SHA512,
   288  	},
   289  }
   290  
   291  // Test parameter selection for each curve, and that P224 fails automatic
   292  // parameter selection (see README for a discussion of P224). Ensures that
   293  // selecting a set of parameters automatically for the given curve works.
   294  func TestParamSelection(t *testing.T) {
   295  	for _, c := range testCases {
   296  		testParamSelection(t, c)
   297  	}
   298  }
   299  
   300  func testParamSelection(t *testing.T, c testCase) {
   301  	params := ParamsFromCurve(c.Curve)
   302  	if params == nil {
   303  		t.Fatal("ParamsFromCurve returned nil")
   304  	} else if params != nil && !cmpParams(params, c.Expected) {
   305  		t.Fatalf("ecies: parameters should be invalid (%s)\n", c.Name)
   306  	}
   307  
   308  	prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   309  	if err != nil {
   310  		t.Fatalf("%s (%s)\n", err.Error(), c.Name)
   311  	}
   312  
   313  	prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   314  	if err != nil {
   315  		t.Fatalf("%s (%s)\n", err.Error(), c.Name)
   316  	}
   317  
   318  	message := []byte("Hello, world.")
   319  	ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
   320  	if err != nil {
   321  		t.Fatalf("%s (%s)\n", err.Error(), c.Name)
   322  	}
   323  
   324  	pt, err := prv2.Decrypt(ct, nil, nil)
   325  	if err != nil {
   326  		t.Fatalf("%s (%s)\n", err.Error(), c.Name)
   327  	}
   328  
   329  	if !bytes.Equal(pt, message) {
   330  		t.Fatalf("ecies: plaintext doesn't match message (%s)\n", c.Name)
   331  	}
   332  
   333  	_, err = prv1.Decrypt(ct, nil, nil)
   334  	if err == nil {
   335  		t.Fatalf("ecies: encryption should not have succeeded (%s)\n", c.Name)
   336  	}
   337  
   338  }
   339  
   340  // Ensure that the basic public key validation in the decryption operation
   341  // works.
   342  func TestBasicKeyValidation(t *testing.T) {
   343  	badBytes := []byte{0, 1, 5, 6, 7, 8, 9}
   344  
   345  	prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
   346  	if err != nil {
   347  		t.Fatal(err)
   348  	}
   349  
   350  	message := []byte("Hello, world.")
   351  	ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil)
   352  	if err != nil {
   353  		t.Fatal(err)
   354  	}
   355  
   356  	for _, b := range badBytes {
   357  		ct[0] = b
   358  		_, err := prv.Decrypt(ct, nil, nil)
   359  		if err != ErrInvalidPublicKey {
   360  			t.Fatal("ecies: validated an invalid key")
   361  		}
   362  	}
   363  }
   364  
   365  func TestBox(t *testing.T) {
   366  	prv1 := hexKey("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")
   367  	prv2 := hexKey("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a")
   368  	pub2 := &prv2.PublicKey
   369  
   370  	message := []byte("Hello, world.")
   371  	ct, err := Encrypt(rand.Reader, pub2, message, nil, nil)
   372  	if err != nil {
   373  		t.Fatal(err)
   374  	}
   375  
   376  	pt, err := prv2.Decrypt(ct, nil, nil)
   377  	if err != nil {
   378  		t.Fatal(err)
   379  	}
   380  	if !bytes.Equal(pt, message) {
   381  		t.Fatal("ecies: plaintext doesn't match message")
   382  	}
   383  	if _, err = prv1.Decrypt(ct, nil, nil); err == nil {
   384  		t.Fatal("ecies: encryption should not have succeeded")
   385  	}
   386  }
   387  
   388  // Verify GenerateShared against static values - useful when
   389  // debugging changes in underlying libs
   390  func TestSharedKeyStatic(t *testing.T) {
   391  	prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad")
   392  	prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9")
   393  
   394  	skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
   395  
   396  	sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
   397  	if err != nil {
   398  		t.Fatal(err)
   399  	}
   400  
   401  	sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
   402  	if err != nil {
   403  		t.Fatal(err)
   404  	}
   405  
   406  	if !bytes.Equal(sk1, sk2) {
   407  		t.Fatal(ErrBadSharedKeys)
   408  	}
   409  
   410  	sk := decode("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62")
   411  	if !bytes.Equal(sk1, sk) {
   412  		t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1)
   413  	}
   414  }
   415  
   416  func hexKey(prv string) *PrivateKey {
   417  	key, err := crypto.HexToECDSA(prv)
   418  	if err != nil {
   419  		panic(err)
   420  	}
   421  	return ImportECDSA(key)
   422  }
   423  
   424  func decode(s string) []byte {
   425  	bytes, err := hex.DecodeString(s)
   426  	if err != nil {
   427  		panic(err)
   428  	}
   429  	return bytes
   430  }