github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/keystore_test.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package accounts
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"crypto/rand"
    23  	"encoding/hex"
    24  	"encoding/json"
    25  	"fmt"
    26  	"io/ioutil"
    27  	"os"
    28  	"reflect"
    29  	"strings"
    30  	"testing"
    31  
    32  	"github.com/ethereumproject/go-ethereum/common"
    33  	"github.com/ethereumproject/go-ethereum/crypto"
    34  	"github.com/ethereumproject/go-ethereum/crypto/secp256k1"
    35  )
    36  
    37  func tmpKeyStore(t *testing.T) (dir string, ks *keyStore) {
    38  	dir, err := ioutil.TempDir("", "geth-keystore-test")
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	store, err := newKeyStore(dir, veryLightScryptN, veryLightScryptP)
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  
    48  	return dir, store
    49  }
    50  
    51  func TestKeyStore(t *testing.T) {
    52  	dir, ks := tmpKeyStore(t)
    53  	defer os.RemoveAll(dir)
    54  
    55  	pass := "foo"
    56  	key, account, err := storeNewKey(ks, pass)
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	got, err := ks.Lookup(account.File, pass)
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  	if !reflect.DeepEqual(got.Address, key.Address) {
    66  		t.Errorf("got address %x, want %x", got.Address, key.Address)
    67  	}
    68  	if !reflect.DeepEqual(key.PrivateKey, key.PrivateKey) {
    69  		t.Errorf("got private key %x, want %x", got.PrivateKey, key.PrivateKey)
    70  	}
    71  }
    72  
    73  func TestKeyStoreDecryptionFail(t *testing.T) {
    74  	dir, ks := tmpKeyStore(t)
    75  	defer os.RemoveAll(dir)
    76  
    77  	pass := "foo"
    78  	_, account, err := storeNewKey(ks, pass)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  	if _, err = ks.Lookup(account.File, "bar"); err != ErrDecrypt {
    83  		t.Fatalf("wrong error for invalid passphrase\ngot %q\nwant %q", err, ErrDecrypt)
    84  	}
    85  }
    86  
    87  func TestImportPreSaleKey(t *testing.T) {
    88  	dir, ks := tmpKeyStore(t)
    89  	defer os.RemoveAll(dir)
    90  
    91  	// file content of a presale key file generated with:
    92  	// python pyethsaletool.py genwallet
    93  	// with password "foo"
    94  	fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
    95  	pass := "foo"
    96  	account, _, err := importPreSaleKey(ks, []byte(fileContent), pass)
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
   101  		t.Errorf("imported account has wrong address %x", account.Address)
   102  	}
   103  	if !strings.HasPrefix(account.File, dir) {
   104  		t.Errorf("imported account file not in keystore directory: %q", account.File)
   105  	}
   106  }
   107  
   108  // Test and utils for the key store tests in the Ethereum JSON tests;
   109  // testdataKeyStoreTests/basic_tests.json
   110  type KeyStoreTestV3 struct {
   111  	Json     web3v3
   112  	Password string
   113  	Priv     string
   114  }
   115  
   116  type KeyStoreTestV1 struct {
   117  	Json     web3v1
   118  	Password string
   119  	Priv     string
   120  }
   121  
   122  func TestV3_PBKDF2_1(t *testing.T) {
   123  	t.Parallel()
   124  	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
   125  	testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t)
   126  }
   127  
   128  func TestV3_PBKDF2_2(t *testing.T) {
   129  	t.Parallel()
   130  	tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
   131  	testDecryptV3(tests["test1"], t)
   132  }
   133  
   134  func TestV3_PBKDF2_3(t *testing.T) {
   135  	t.Parallel()
   136  	tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
   137  	testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
   138  }
   139  
   140  func TestV3_PBKDF2_4(t *testing.T) {
   141  	t.Parallel()
   142  	tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
   143  	testDecryptV3(tests["evilnonce"], t)
   144  }
   145  
   146  func TestV3_Scrypt_1(t *testing.T) {
   147  	t.Parallel()
   148  	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
   149  	testDecryptV3(tests["wikipage_test_vector_scrypt"], t)
   150  }
   151  
   152  func TestV3_Scrypt_2(t *testing.T) {
   153  	t.Parallel()
   154  	tests := loadKeyStoreTestV3("../tests/files/KeyStoreTests/basic_tests.json", t)
   155  	testDecryptV3(tests["test2"], t)
   156  }
   157  
   158  func TestV1_1(t *testing.T) {
   159  	t.Parallel()
   160  	tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t)
   161  	testDecryptV1(tests["test1"], t)
   162  }
   163  
   164  func TestV1_2(t *testing.T) {
   165  	t.Parallel()
   166  	store, err := newKeyStore("testdata/v1", LightScryptN, LightScryptP)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	key, err := store.Lookup("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e", "g")
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  
   176  	got := hex.EncodeToString(key.Address[:])
   177  	want := "cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
   178  	if got != want {
   179  		t.Errorf("got address %s, want %s", got, want)
   180  	}
   181  
   182  	got = hex.EncodeToString(crypto.FromECDSA(key.PrivateKey))
   183  	want = "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
   184  	if got != want {
   185  		t.Errorf("got private key %s, want %s", got, want)
   186  	}
   187  }
   188  
   189  func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
   190  	privBytes, err := decryptKeyV3(&test.Json, test.Password)
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	privHex := hex.EncodeToString(privBytes)
   195  	if test.Priv != privHex {
   196  		t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
   197  	}
   198  }
   199  
   200  func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
   201  	privBytes, err := decryptKeyV1(&test.Json, test.Password)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	privHex := hex.EncodeToString(privBytes)
   206  	if test.Priv != privHex {
   207  		t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
   208  	}
   209  }
   210  
   211  func loadKeyStoreTestV3(file string, t *testing.T) map[string]KeyStoreTestV3 {
   212  	tests := make(map[string]KeyStoreTestV3)
   213  	bytes, err := ioutil.ReadFile(file)
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  	if err = json.Unmarshal(bytes, &tests); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	return tests
   221  }
   222  
   223  func loadKeyStoreTestV1(file string, t *testing.T) map[string]KeyStoreTestV1 {
   224  	tests := make(map[string]KeyStoreTestV1)
   225  	bytes, err := ioutil.ReadFile(file)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  	if err = json.Unmarshal(bytes, &tests); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	return tests
   233  }
   234  
   235  // WTF?
   236  // newKeyForDirectICAP generates a key whose address fits into < 155 bits so it can fit
   237  // into the Direct ICAP spec. for simplicity and easier compatibility with other libs, we
   238  // retry until the first byte is 0.
   239  func TestKeyForDirectICAP(t *testing.T) {
   240  	t.Parallel()
   241  
   242  	for {
   243  		randBytes := make([]byte, 64)
   244  		_, err := rand.Read(randBytes)
   245  		if err != nil {
   246  			t.Fatalf("key generation: could not read from random source: %s", err)
   247  		}
   248  
   249  		privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), bytes.NewReader(randBytes))
   250  		if err != nil {
   251  			t.Fatalf("key generation: ecdsa.GenerateKey failed: %s", err)
   252  		}
   253  
   254  		key, err := newKeyFromECDSA(privateKeyECDSA)
   255  		if err != nil {
   256  			t.Fatal(err)
   257  		}
   258  
   259  		if key.Address[0] == 0 {
   260  			return
   261  		}
   262  	}
   263  }
   264  
   265  const (
   266  	veryLightScryptN = 2
   267  	veryLightScryptP = 1
   268  )
   269  
   270  // Tests that a JSON key file can be decrypted and encrypted in multiple rounds.
   271  func TestKeyEncryptDecrypt(t *testing.T) {
   272  	keyjson, err := ioutil.ReadFile("testdata/very-light-scrypt.json")
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	password := ""
   277  	address := common.HexToAddress("45dea0fb0bba44f4fcf290bba71fd57d7117cbb8")
   278  
   279  	// Do a few rounds of decryption and encryption
   280  	for i := 0; i < 3; i++ {
   281  		// try a bad password first
   282  		if _, err := decryptKey(keyjson, password+"bad"); err == nil {
   283  			t.Errorf("test %d: json key decrypted with bad password", i)
   284  		}
   285  		// decrypt with the correct password
   286  		key, err := decryptKey(keyjson, password)
   287  		if err != nil {
   288  			t.Errorf("test %d: json key failed to decrypt: %v", i, err)
   289  		}
   290  		if key.Address != address {
   291  			t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)
   292  		}
   293  		// recrypt with a new password and start over
   294  		password += "new data appended"
   295  		if keyjson, err = encryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
   296  			t.Errorf("test %d: failed to recrypt key %v", i, err)
   297  		}
   298  	}
   299  }