plain_test.go 7.62 KB
Newer Older
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 6 7 8
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
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 13 14
// GNU Lesser General Public License for more details.
//
// 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 keystore
18 19

import (
20
	"crypto/rand"
21 22
	"encoding/hex"
	"fmt"
23 24
	"io/ioutil"
	"os"
25
	"path/filepath"
26
	"reflect"
27
	"strings"
28
	"testing"
29 30

	"github.com/ethereum/go-ethereum/common"
31
	"github.com/ethereum/go-ethereum/crypto"
32 33
)

34
func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
35 36 37 38 39
	d, err := ioutil.TempDir("", "geth-keystore-test")
	if err != nil {
		t.Fatal(err)
	}
	if encrypted {
40
		ks = &keyStorePassphrase{d, veryLightScryptN, veryLightScryptP, true}
41 42 43 44 45 46
	} else {
		ks = &keyStorePlain{d}
	}
	return d, ks
}

47
func TestKeyStorePlain(t *testing.T) {
48
	dir, ks := tmpKeyStoreIface(t, false)
49 50
	defer os.RemoveAll(dir)

51
	pass := "" // not used but required by API
52
	k1, account, err := storeNewKey(ks, rand.Reader, pass)
53
	if err != nil {
54
		t.Fatal(err)
55
	}
56
	k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
57
	if err != nil {
58
		t.Fatal(err)
59
	}
60
	if !reflect.DeepEqual(k1.Address, k2.Address) {
61
		t.Fatal(err)
62 63
	}
	if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
64
		t.Fatal(err)
65 66 67 68
	}
}

func TestKeyStorePassphrase(t *testing.T) {
69
	dir, ks := tmpKeyStoreIface(t, true)
70 71
	defer os.RemoveAll(dir)

72
	pass := "foo"
73
	k1, account, err := storeNewKey(ks, rand.Reader, pass)
74
	if err != nil {
75
		t.Fatal(err)
76
	}
77
	k2, err := ks.GetKey(k1.Address, account.URL.Path, pass)
78
	if err != nil {
79
		t.Fatal(err)
80
	}
81
	if !reflect.DeepEqual(k1.Address, k2.Address) {
82
		t.Fatal(err)
83 84
	}
	if !reflect.DeepEqual(k1.PrivateKey, k2.PrivateKey) {
85
		t.Fatal(err)
86 87 88 89
	}
}

func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
90
	dir, ks := tmpKeyStoreIface(t, true)
91 92
	defer os.RemoveAll(dir)

93
	pass := "foo"
94
	k1, account, err := storeNewKey(ks, rand.Reader, pass)
95
	if err != nil {
96
		t.Fatal(err)
97
	}
98
	if _, err = ks.GetKey(k1.Address, account.URL.Path, "bar"); err != ErrDecrypt {
99
		t.Fatalf("wrong error for invalid password\ngot %q\nwant %q", err, ErrDecrypt)
100 101
	}
}
Gustav Simonsson's avatar
Gustav Simonsson committed
102 103

func TestImportPreSaleKey(t *testing.T) {
104
	dir, ks := tmpKeyStoreIface(t, true)
105 106
	defer os.RemoveAll(dir)

Gustav Simonsson's avatar
Gustav Simonsson committed
107 108 109 110 111
	// file content of a presale key file generated with:
	// python pyethsaletool.py genwallet
	// with password "foo"
	fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}"
	pass := "foo"
112
	account, _, err := importPreSaleKey(ks, []byte(fileContent), pass)
Gustav Simonsson's avatar
Gustav Simonsson committed
113 114 115
	if err != nil {
		t.Fatal(err)
	}
116 117 118
	if account.Address != common.HexToAddress("d4584b5f6229b7be90727b0fc8c6b91bb427821f") {
		t.Errorf("imported account has wrong address %x", account.Address)
	}
119
	if !strings.HasPrefix(account.URL.Path, dir) {
120
		t.Errorf("imported account file not in keystore directory: %q", account.URL)
121
	}
Gustav Simonsson's avatar
Gustav Simonsson committed
122
}
123 124

// Test and utils for the key store tests in the Ethereum JSON tests;
125
// testdataKeyStoreTests/basic_tests.json
126 127 128 129 130 131 132 133 134 135 136 137 138
type KeyStoreTestV3 struct {
	Json     encryptedKeyJSONV3
	Password string
	Priv     string
}

type KeyStoreTestV1 struct {
	Json     encryptedKeyJSONV1
	Password string
	Priv     string
}

func TestV3_PBKDF2_1(t *testing.T) {
139
	t.Parallel()
140
	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
141 142 143
	testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t)
}

144 145 146 147 148 149 150 151
var testsSubmodule = filepath.Join("..", "..", "tests", "testdata", "KeyStoreTests")

func skipIfSubmoduleMissing(t *testing.T) {
	if !common.FileExist(testsSubmodule) {
		t.Skipf("can't find JSON tests from submodule at %s", testsSubmodule)
	}
}

152
func TestV3_PBKDF2_2(t *testing.T) {
153
	skipIfSubmoduleMissing(t)
154
	t.Parallel()
155
	tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
156 157 158 159
	testDecryptV3(tests["test1"], t)
}

func TestV3_PBKDF2_3(t *testing.T) {
160
	skipIfSubmoduleMissing(t)
161
	t.Parallel()
162
	tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
163 164 165 166
	testDecryptV3(tests["python_generated_test_with_odd_iv"], t)
}

func TestV3_PBKDF2_4(t *testing.T) {
167
	skipIfSubmoduleMissing(t)
168
	t.Parallel()
169
	tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
170 171 172 173
	testDecryptV3(tests["evilnonce"], t)
}

func TestV3_Scrypt_1(t *testing.T) {
174
	t.Parallel()
175
	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
176 177 178 179
	testDecryptV3(tests["wikipage_test_vector_scrypt"], t)
}

func TestV3_Scrypt_2(t *testing.T) {
180
	skipIfSubmoduleMissing(t)
181
	t.Parallel()
182
	tests := loadKeyStoreTestV3(filepath.Join(testsSubmodule, "basic_tests.json"), t)
183 184 185 186
	testDecryptV3(tests["test2"], t)
}

func TestV1_1(t *testing.T) {
187
	t.Parallel()
188
	tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t)
189 190 191 192
	testDecryptV1(tests["test1"], t)
}

func TestV1_2(t *testing.T) {
193
	t.Parallel()
194
	ks := &keyStorePassphrase{"testdata/v1", LightScryptN, LightScryptP, true}
195
	addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e")
196 197
	file := "testdata/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
	k, err := ks.GetKey(addr, file, "g")
198 199 200
	if err != nil {
		t.Fatal(err)
	}
201
	privHex := hex.EncodeToString(crypto.FromECDSA(k.PrivateKey))
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
	expectedHex := "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
	if privHex != expectedHex {
		t.Fatal(fmt.Errorf("Unexpected privkey: %v, expected %v", privHex, expectedHex))
	}
}

func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
	privBytes, _, err := decryptKeyV3(&test.Json, test.Password)
	if err != nil {
		t.Fatal(err)
	}
	privHex := hex.EncodeToString(privBytes)
	if test.Priv != privHex {
		t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
	}
}

func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
	privBytes, _, err := decryptKeyV1(&test.Json, test.Password)
	if err != nil {
		t.Fatal(err)
	}
	privHex := hex.EncodeToString(privBytes)
	if test.Priv != privHex {
		t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
	}
}

func loadKeyStoreTestV3(file string, t *testing.T) map[string]KeyStoreTestV3 {
	tests := make(map[string]KeyStoreTestV3)
	err := common.LoadJSON(file, &tests)
	if err != nil {
		t.Fatal(err)
	}
	return tests
}

func loadKeyStoreTestV1(file string, t *testing.T) map[string]KeyStoreTestV1 {
	tests := make(map[string]KeyStoreTestV1)
	err := common.LoadJSON(file, &tests)
	if err != nil {
		t.Fatal(err)
	}
	return tests
}
247 248

func TestKeyForDirectICAP(t *testing.T) {
249 250
	t.Parallel()
	key := NewKeyForDirectICAP(rand.Reader)
251 252 253 254
	if !strings.HasPrefix(key.Address.Hex(), "0x00") {
		t.Errorf("Expected first address byte to be zero, have: %s", key.Address.Hex())
	}
}
255 256 257 258 259 260 261 262 263 264 265 266

func TestV3_31_Byte_Key(t *testing.T) {
	t.Parallel()
	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
	testDecryptV3(tests["31_byte_key"], t)
}

func TestV3_30_Byte_Key(t *testing.T) {
	t.Parallel()
	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t)
	testDecryptV3(tests["30_byte_key"], t)
}