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