accounts, crypto: move keystore to package accounts
The account management API was originally implemented as a thin layer around crypto.KeyStore, on the grounds that several kinds of key stores would be implemented later on. It turns out that this won't happen so KeyStore is a superflous abstraction. In this commit crypto.KeyStore and everything related to it moves to package accounts and is unexported.
This commit is contained in:
		
							parent
							
								
									dff9b4246f
								
							
						
					
					
						commit
						85e6c40c00
					
				| @ -17,10 +17,12 @@ | ||||
| package bind | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/ecdsa" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/accounts" | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| @ -33,23 +35,24 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	key, err := crypto.DecryptKey(json, passphrase) | ||||
| 	key, err := accounts.DecryptKey(json, passphrase) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return NewKeyedTransactor(key), nil | ||||
| 	return NewKeyedTransactor(key.PrivateKey), nil | ||||
| } | ||||
| 
 | ||||
| // NewKeyedTransactor is a utility method to easily create a transaction signer
 | ||||
| // from a plain go-ethereum crypto key.
 | ||||
| func NewKeyedTransactor(key *crypto.Key) *TransactOpts { | ||||
| // from a single private key.
 | ||||
| func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { | ||||
| 	keyAddr := crypto.PubkeyToAddress(key.PublicKey) | ||||
| 	return &TransactOpts{ | ||||
| 		From: key.Address, | ||||
| 		From: keyAddr, | ||||
| 		Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { | ||||
| 			if address != key.Address { | ||||
| 			if address != keyAddr { | ||||
| 				return nil, errors.New("not authorized to sign this account") | ||||
| 			} | ||||
| 			signature, err := crypto.Sign(tx.SigHash().Bytes(), key.PrivateKey) | ||||
| 			signature, err := crypto.Sign(tx.SigHash().Bytes(), key) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| @ -167,11 +167,9 @@ var bindTests = []struct { | ||||
| 		`[{"constant":true,"inputs":[],"name":"transactString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":true,"inputs":[],"name":"deployString","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"str","type":"string"}],"name":"transact","outputs":[],"type":"function"},{"inputs":[{"name":"str","type":"string"}],"type":"constructor"}]`, | ||||
| 		` | ||||
| 			// Generate a new random account and a funded simulator
 | ||||
| 			key := crypto.NewKey(rand.Reader) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: key.Address, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Convert the tester key to an authorized transactor for ease of use
 | ||||
| 			key, _ := crypto.GenerateKey() | ||||
| 			auth := bind.NewKeyedTransactor(key) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Deploy an interaction tester contract and call a transaction on it
 | ||||
| 			_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") | ||||
| @ -210,11 +208,9 @@ var bindTests = []struct { | ||||
| 		`[{"constant":true,"inputs":[],"name":"tuple","outputs":[{"name":"a","type":"string"},{"name":"b","type":"int256"},{"name":"c","type":"bytes32"}],"type":"function"}]`, | ||||
| 		` | ||||
| 			// Generate a new random account and a funded simulator
 | ||||
| 			key := crypto.NewKey(rand.Reader) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: key.Address, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Convert the tester key to an authorized transactor for ease of use
 | ||||
| 			key, _ := crypto.GenerateKey() | ||||
| 			auth := bind.NewKeyedTransactor(key) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Deploy a tuple tester contract and execute a structured call on it
 | ||||
| 			_, _, tupler, err := DeployTupler(auth, sim) | ||||
| @ -252,11 +248,9 @@ var bindTests = []struct { | ||||
| 		`[{"constant":true,"inputs":[{"name":"input","type":"address[]"}],"name":"echoAddresses","outputs":[{"name":"output","type":"address[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"uint24[23]"}],"name":"echoFancyInts","outputs":[{"name":"output","type":"uint24[23]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"int256[]"}],"name":"echoInts","outputs":[{"name":"output","type":"int256[]"}],"type":"function"},{"constant":true,"inputs":[{"name":"input","type":"bool[]"}],"name":"echoBools","outputs":[{"name":"output","type":"bool[]"}],"type":"function"}]`, | ||||
| 		` | ||||
| 			// Generate a new random account and a funded simulator
 | ||||
| 			key := crypto.NewKey(rand.Reader) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: key.Address, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Convert the tester key to an authorized transactor for ease of use
 | ||||
| 			key, _ := crypto.GenerateKey() | ||||
| 			auth := bind.NewKeyedTransactor(key) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Deploy a slice tester contract and execute a n array call on it
 | ||||
| 			_, _, slicer, err := DeploySlicer(auth, sim) | ||||
| @ -265,10 +259,10 @@ var bindTests = []struct { | ||||
| 			} | ||||
| 			sim.Commit() | ||||
| 
 | ||||
| 			if out, err := slicer.EchoAddresses(nil, []common.Address{key.Address, common.Address{}}); err != nil { | ||||
| 			if out, err := slicer.EchoAddresses(nil, []common.Address{auth.From, common.Address{}}); err != nil { | ||||
| 					t.Fatalf("Failed to call slice echoer: %v", err) | ||||
| 			} else if !reflect.DeepEqual(out, []common.Address{key.Address, common.Address{}}) { | ||||
| 					t.Fatalf("Slice return mismatch: have %v, want %v", out, []common.Address{key.Address, common.Address{}}) | ||||
| 			} else if !reflect.DeepEqual(out, []common.Address{auth.From, common.Address{}}) { | ||||
| 					t.Fatalf("Slice return mismatch: have %v, want %v", out, []common.Address{auth.From, common.Address{}}) | ||||
| 			} | ||||
| 		`, | ||||
| 	}, | ||||
| @ -288,11 +282,9 @@ var bindTests = []struct { | ||||
| 		`[{"constant":true,"inputs":[],"name":"caller","outputs":[{"name":"","type":"address"}],"type":"function"}]`, | ||||
| 		` | ||||
| 			// Generate a new random account and a funded simulator
 | ||||
| 			key := crypto.NewKey(rand.Reader) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: key.Address, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Convert the tester key to an authorized transactor for ease of use
 | ||||
| 			key, _ := crypto.GenerateKey() | ||||
| 			auth := bind.NewKeyedTransactor(key) | ||||
| 			sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) | ||||
| 
 | ||||
| 			// Deploy a default method invoker contract and execute its default method
 | ||||
| 			_, _, defaulter, err := DeployDefaulter(auth, sim) | ||||
| @ -306,8 +298,8 @@ var bindTests = []struct { | ||||
| 
 | ||||
| 			if caller, err := defaulter.Caller(nil); err != nil { | ||||
| 				t.Fatalf("Failed to call address retriever: %v", err) | ||||
| 			} else if (caller != key.Address) { | ||||
| 				t.Fatalf("Address mismatch: have %v, want %v", caller, key.Address) | ||||
| 			} else if (caller != auth.From) { | ||||
| 				t.Fatalf("Address mismatch: have %v, want %v", caller, auth.From) | ||||
| 			} | ||||
| 		`, | ||||
| 	}, | ||||
|  | ||||
| @ -19,9 +19,6 @@ | ||||
| // This abstracts part of a user's interaction with an account she controls.
 | ||||
| package accounts | ||||
| 
 | ||||
| // Currently this is pretty much a passthrough to the KeyStore interface,
 | ||||
| // and accounts persistence is derived from stored keys' addresses
 | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/ecdsa" | ||||
| 	crand "crypto/rand" | ||||
| @ -49,19 +46,26 @@ func (acc *Account) MarshalJSON() ([]byte, error) { | ||||
| } | ||||
| 
 | ||||
| type Manager struct { | ||||
| 	keyStore crypto.KeyStore | ||||
| 	keyStore keyStore | ||||
| 	unlocked map[common.Address]*unlocked | ||||
| 	mutex    sync.RWMutex | ||||
| } | ||||
| 
 | ||||
| type unlocked struct { | ||||
| 	*crypto.Key | ||||
| 	*Key | ||||
| 	abort chan struct{} | ||||
| } | ||||
| 
 | ||||
| func NewManager(keyStore crypto.KeyStore) *Manager { | ||||
| func NewManager(keydir string, scryptN, scryptP int) *Manager { | ||||
| 	return &Manager{ | ||||
| 		keyStore: keyStore, | ||||
| 		keyStore: newKeyStorePassphrase(keydir, scryptN, scryptP), | ||||
| 		unlocked: make(map[common.Address]*unlocked), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func NewPlaintextManager(keydir string) *Manager { | ||||
| 	return &Manager{ | ||||
| 		keyStore: newKeyStorePlain(keydir), | ||||
| 		unlocked: make(map[common.Address]*unlocked), | ||||
| 	} | ||||
| } | ||||
| @ -216,19 +220,23 @@ func (am *Manager) Export(path string, addr common.Address, keyAuth string) erro | ||||
| } | ||||
| 
 | ||||
| func (am *Manager) Import(path string, keyAuth string) (Account, error) { | ||||
| 	privateKeyECDSA, err := crypto.LoadECDSA(path) | ||||
| 	priv, err := crypto.LoadECDSA(path) | ||||
| 	if err != nil { | ||||
| 		return Account{}, err | ||||
| 	} | ||||
| 	key := crypto.NewKeyFromECDSA(privateKeyECDSA) | ||||
| 	if err = am.keyStore.StoreKey(key, keyAuth); err != nil { | ||||
| 	return am.ImportECDSA(priv, keyAuth) | ||||
| } | ||||
| 
 | ||||
| func (am *Manager) ImportECDSA(priv *ecdsa.PrivateKey, keyAuth string) (Account, error) { | ||||
| 	key := newKeyFromECDSA(priv) | ||||
| 	if err := am.keyStore.StoreKey(key, keyAuth); err != nil { | ||||
| 		return Account{}, err | ||||
| 	} | ||||
| 	return Account{Address: key.Address}, nil | ||||
| } | ||||
| 
 | ||||
| func (am *Manager) Update(addr common.Address, authFrom, authTo string) (err error) { | ||||
| 	var key *crypto.Key | ||||
| 	var key *Key | ||||
| 	key, err = am.keyStore.GetKey(addr, authFrom) | ||||
| 
 | ||||
| 	if err == nil { | ||||
| @ -241,8 +249,8 @@ func (am *Manager) Update(addr common.Address, authFrom, authTo string) (err err | ||||
| } | ||||
| 
 | ||||
| func (am *Manager) ImportPreSaleKey(keyJSON []byte, password string) (acc Account, err error) { | ||||
| 	var key *crypto.Key | ||||
| 	key, err = crypto.ImportPreSaleKey(am.keyStore, keyJSON, password) | ||||
| 	var key *Key | ||||
| 	key, err = importPreSaleKey(am.keyStore, keyJSON, password) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @ -21,17 +21,14 @@ import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| ) | ||||
| 
 | ||||
| var testSigData = make([]byte, 32) | ||||
| 
 | ||||
| func TestSign(t *testing.T) { | ||||
| 	dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain) | ||||
| 	dir, am := tmpManager(t, false) | ||||
| 	defer os.RemoveAll(dir) | ||||
| 
 | ||||
| 	am := NewManager(ks) | ||||
| 	pass := "" // not used but required by API
 | ||||
| 	a1, err := am.NewAccount(pass) | ||||
| 	am.Unlock(a1.Address, "") | ||||
| @ -43,10 +40,9 @@ func TestSign(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestTimedUnlock(t *testing.T) { | ||||
| 	dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain) | ||||
| 	dir, am := tmpManager(t, false) | ||||
| 	defer os.RemoveAll(dir) | ||||
| 
 | ||||
| 	am := NewManager(ks) | ||||
| 	pass := "foo" | ||||
| 	a1, err := am.NewAccount(pass) | ||||
| 
 | ||||
| @ -76,10 +72,9 @@ func TestTimedUnlock(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestOverrideUnlock(t *testing.T) { | ||||
| 	dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain) | ||||
| 	dir, am := tmpManager(t, false) | ||||
| 	defer os.RemoveAll(dir) | ||||
| 
 | ||||
| 	am := NewManager(ks) | ||||
| 	pass := "foo" | ||||
| 	a1, err := am.NewAccount(pass) | ||||
| 
 | ||||
| @ -115,11 +110,10 @@ func TestOverrideUnlock(t *testing.T) { | ||||
| 
 | ||||
| // This test should fail under -race if signing races the expiration goroutine.
 | ||||
| func TestSignRace(t *testing.T) { | ||||
| 	dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain) | ||||
| 	dir, am := tmpManager(t, false) | ||||
| 	defer os.RemoveAll(dir) | ||||
| 
 | ||||
| 	// Create a test account.
 | ||||
| 	am := NewManager(ks) | ||||
| 	a1, err := am.NewAccount("") | ||||
| 	if err != nil { | ||||
| 		t.Fatal("could not create the test account", err) | ||||
| @ -141,10 +135,14 @@ func TestSignRace(t *testing.T) { | ||||
| 	t.Errorf("Account did not lock within the timeout") | ||||
| } | ||||
| 
 | ||||
| func tmpKeyStore(t *testing.T, new func(string) crypto.KeyStore) (string, crypto.KeyStore) { | ||||
| func tmpManager(t *testing.T, encrypted bool) (string, *Manager) { | ||||
| 	d, err := ioutil.TempDir("", "eth-keystore-test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	new := NewPlaintextManager | ||||
| 	if encrypted { | ||||
| 		new = func(kd string) *Manager { return NewManager(kd, LightScryptN, LightScryptP) } | ||||
| 	} | ||||
| 	return d, new(d) | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package crypto | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @ -25,6 +25,7 @@ import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/secp256k1" | ||||
| 	"github.com/pborman/uuid" | ||||
| ) | ||||
| @ -42,6 +43,16 @@ type Key struct { | ||||
| 	PrivateKey *ecdsa.PrivateKey | ||||
| } | ||||
| 
 | ||||
| type keyStore interface { | ||||
| 	// create new key using io.Reader entropy source and optionally using auth string
 | ||||
| 	GenerateNewKey(io.Reader, string) (*Key, error) | ||||
| 	GetKey(common.Address, string) (*Key, error) // get key from addr and auth string
 | ||||
| 	GetKeyAddresses() ([]common.Address, error)  // get all addresses
 | ||||
| 	StoreKey(*Key, string) error                 // store key optionally using auth string
 | ||||
| 	DeleteKey(common.Address, string) error      // delete key by addr and auth string
 | ||||
| 	Cleanup(keyAddr common.Address) (err error) | ||||
| } | ||||
| 
 | ||||
| type plainKeyJSON struct { | ||||
| 	Address    string `json:"address"` | ||||
| 	PrivateKey string `json:"privatekey"` | ||||
| @ -87,7 +98,7 @@ type scryptParamsJSON struct { | ||||
| func (k *Key) MarshalJSON() (j []byte, err error) { | ||||
| 	jStruct := plainKeyJSON{ | ||||
| 		hex.EncodeToString(k.Address[:]), | ||||
| 		hex.EncodeToString(FromECDSA(k.PrivateKey)), | ||||
| 		hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)), | ||||
| 		k.Id.String(), | ||||
| 		version, | ||||
| 	} | ||||
| @ -116,16 +127,16 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) { | ||||
| 	} | ||||
| 
 | ||||
| 	k.Address = common.BytesToAddress(addr) | ||||
| 	k.PrivateKey = ToECDSA(privkey) | ||||
| 	k.PrivateKey = crypto.ToECDSA(privkey) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func NewKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { | ||||
| func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { | ||||
| 	id := uuid.NewRandom() | ||||
| 	key := &Key{ | ||||
| 		Id:         id, | ||||
| 		Address:    PubkeyToAddress(privateKeyECDSA.PublicKey), | ||||
| 		Address:    crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), | ||||
| 		PrivateKey: privateKeyECDSA, | ||||
| 	} | ||||
| 	return key | ||||
| @ -143,7 +154,7 @@ func NewKey(rand io.Reader) *Key { | ||||
| 		panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	return NewKeyFromECDSA(privateKeyECDSA) | ||||
| 	return newKeyFromECDSA(privateKeyECDSA) | ||||
| } | ||||
| 
 | ||||
| // generate key whose address fits into < 155 bits so it can fit into
 | ||||
| @ -160,7 +171,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key { | ||||
| 	if err != nil { | ||||
| 		panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) | ||||
| 	} | ||||
| 	key := NewKeyFromECDSA(privateKeyECDSA) | ||||
| 	key := newKeyFromECDSA(privateKeyECDSA) | ||||
| 	if !strings.HasPrefix(key.Address.Hex(), "0x00") { | ||||
| 		return NewKeyForDirectICAP(rand) | ||||
| 	} | ||||
| @ -23,7 +23,7 @@ The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-St | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| package crypto | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @ -36,6 +36,7 @@ import ( | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| 	"github.com/pborman/uuid" | ||||
| 	"golang.org/x/crypto/pbkdf2" | ||||
| @ -63,12 +64,12 @@ type keyStorePassphrase struct { | ||||
| 	scryptP     int | ||||
| } | ||||
| 
 | ||||
| func NewKeyStorePassphrase(path string, scryptN int, scryptP int) KeyStore { | ||||
| func newKeyStorePassphrase(path string, scryptN int, scryptP int) keyStore { | ||||
| 	return &keyStorePassphrase{path, scryptN, scryptP} | ||||
| } | ||||
| 
 | ||||
| func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) { | ||||
| 	return GenerateNewKeyDefault(ks, rand, auth) | ||||
| 	return generateNewKeyDefault(ks, rand, auth) | ||||
| } | ||||
| 
 | ||||
| func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) { | ||||
| @ -101,14 +102,14 @@ func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	encryptKey := derivedKey[:16] | ||||
| 	keyBytes := FromECDSA(key.PrivateKey) | ||||
| 	keyBytes := crypto.FromECDSA(key.PrivateKey) | ||||
| 
 | ||||
| 	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
 | ||||
| 	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	mac := Keccak256(derivedKey[16:32], cipherText) | ||||
| 	mac := crypto.Keccak256(derivedKey[16:32], cipherText) | ||||
| 
 | ||||
| 	scryptParamsJSON := make(map[string]interface{}, 5) | ||||
| 	scryptParamsJSON["n"] = scryptN | ||||
| @ -175,10 +176,10 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) { | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	key := ToECDSA(keyBytes) | ||||
| 	key := crypto.ToECDSA(keyBytes) | ||||
| 	return &Key{ | ||||
| 		Id:         uuid.UUID(keyId), | ||||
| 		Address:    PubkeyToAddress(key.PublicKey), | ||||
| 		Address:    crypto.PubkeyToAddress(key.PublicKey), | ||||
| 		PrivateKey: key, | ||||
| 	}, nil | ||||
| } | ||||
| @ -230,7 +231,7 @@ func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byt | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	calculatedMAC := Keccak256(derivedKey[16:32], cipherText) | ||||
| 	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) | ||||
| 	if !bytes.Equal(calculatedMAC, mac) { | ||||
| 		return nil, nil, errors.New("Decryption failed: MAC mismatch") | ||||
| 	} | ||||
| @ -264,12 +265,12 @@ func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byt | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	calculatedMAC := Keccak256(derivedKey[16:32], cipherText) | ||||
| 	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) | ||||
| 	if !bytes.Equal(calculatedMAC, mac) { | ||||
| 		return nil, nil, errors.New("Decryption failed: MAC mismatch") | ||||
| 	} | ||||
| 
 | ||||
| 	plainText, err := aesCBCDecrypt(Keccak256(derivedKey[:16])[:16], cipherText, iv) | ||||
| 	plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| @ -14,7 +14,7 @@ | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package crypto | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| @ -14,7 +14,7 @@ | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package crypto | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| @ -29,29 +29,19 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| type KeyStore interface { | ||||
| 	// create new key using io.Reader entropy source and optionally using auth string
 | ||||
| 	GenerateNewKey(io.Reader, string) (*Key, error) | ||||
| 	GetKey(common.Address, string) (*Key, error) // get key from addr and auth string
 | ||||
| 	GetKeyAddresses() ([]common.Address, error)  // get all addresses
 | ||||
| 	StoreKey(*Key, string) error                 // store key optionally using auth string
 | ||||
| 	DeleteKey(common.Address, string) error      // delete key by addr and auth string
 | ||||
| 	Cleanup(keyAddr common.Address) (err error) | ||||
| } | ||||
| 
 | ||||
| type keyStorePlain struct { | ||||
| 	keysDirPath string | ||||
| } | ||||
| 
 | ||||
| func NewKeyStorePlain(path string) KeyStore { | ||||
| func newKeyStorePlain(path string) keyStore { | ||||
| 	return &keyStorePlain{path} | ||||
| } | ||||
| 
 | ||||
| func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) { | ||||
| 	return GenerateNewKeyDefault(ks, rand, auth) | ||||
| 	return generateNewKeyDefault(ks, rand, auth) | ||||
| } | ||||
| 
 | ||||
| func GenerateNewKeyDefault(ks KeyStore, rand io.Reader, auth string) (key *Key, err error) { | ||||
| func generateNewKeyDefault(ks keyStore, rand io.Reader, auth string) (key *Key, err error) { | ||||
| 	defer func() { | ||||
| 		if r := recover(); r != nil { | ||||
| 			err = fmt.Errorf("GenerateNewKey error: %v", r) | ||||
| @ -14,7 +14,7 @@ | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package crypto | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| @ -24,11 +24,12 @@ import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/randentropy" | ||||
| ) | ||||
| 
 | ||||
| func TestKeyStorePlain(t *testing.T) { | ||||
| 	ks := NewKeyStorePlain(common.DefaultDataDir()) | ||||
| 	ks := newKeyStorePlain(common.DefaultDataDir()) | ||||
| 	pass := "" // not used but required by API
 | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| @ -56,7 +57,7 @@ func TestKeyStorePlain(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestKeyStorePassphrase(t *testing.T) { | ||||
| 	ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	ks := newKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	pass := "foo" | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| @ -82,7 +83,7 @@ func TestKeyStorePassphrase(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestKeyStorePassphraseDecryptionFail(t *testing.T) { | ||||
| 	ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	ks := newKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	pass := "foo" | ||||
| 	k1, err := ks.GenerateNewKey(randentropy.Reader, pass) | ||||
| 	if err != nil { | ||||
| @ -110,16 +111,16 @@ func TestImportPreSaleKey(t *testing.T) { | ||||
| 	// python pyethsaletool.py genwallet
 | ||||
| 	// with password "foo"
 | ||||
| 	fileContent := "{\"encseed\": \"26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba\", \"ethaddr\": \"d4584b5f6229b7be90727b0fc8c6b91bb427821f\", \"email\": \"gustav.simonsson@gmail.com\", \"btcaddr\": \"1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx\"}" | ||||
| 	ks := NewKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	ks := newKeyStorePassphrase(common.DefaultDataDir(), LightScryptN, LightScryptP) | ||||
| 	pass := "foo" | ||||
| 	_, err := ImportPreSaleKey(ks, []byte(fileContent), pass) | ||||
| 	_, err := importPreSaleKey(ks, []byte(fileContent), pass) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Test and utils for the key store tests in the Ethereum JSON tests;
 | ||||
| // tests/KeyStoreTests/basic_tests.json
 | ||||
| // testdataKeyStoreTests/basic_tests.json
 | ||||
| type KeyStoreTestV3 struct { | ||||
| 	Json     encryptedKeyJSONV3 | ||||
| 	Password string | ||||
| @ -133,7 +134,7 @@ type KeyStoreTestV1 struct { | ||||
| } | ||||
| 
 | ||||
| func TestV3_PBKDF2_1(t *testing.T) { | ||||
| 	tests := loadKeyStoreTestV3("tests/v3_test_vector.json", t) | ||||
| 	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t) | ||||
| 	testDecryptV3(tests["wikipage_test_vector_pbkdf2"], t) | ||||
| } | ||||
| 
 | ||||
| @ -153,7 +154,7 @@ func TestV3_PBKDF2_4(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestV3_Scrypt_1(t *testing.T) { | ||||
| 	tests := loadKeyStoreTestV3("tests/v3_test_vector.json", t) | ||||
| 	tests := loadKeyStoreTestV3("testdata/v3_test_vector.json", t) | ||||
| 	testDecryptV3(tests["wikipage_test_vector_scrypt"], t) | ||||
| } | ||||
| 
 | ||||
| @ -163,12 +164,12 @@ func TestV3_Scrypt_2(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestV1_1(t *testing.T) { | ||||
| 	tests := loadKeyStoreTestV1("tests/v1_test_vector.json", t) | ||||
| 	tests := loadKeyStoreTestV1("testdata/v1_test_vector.json", t) | ||||
| 	testDecryptV1(tests["test1"], t) | ||||
| } | ||||
| 
 | ||||
| func TestV1_2(t *testing.T) { | ||||
| 	ks := NewKeyStorePassphrase("tests/v1", LightScryptN, LightScryptP) | ||||
| 	ks := newKeyStorePassphrase("testdata/v1", LightScryptN, LightScryptP) | ||||
| 	addr := common.HexToAddress("cb61d5a9c4896fb9658090b597ef0e7be6f7b67e") | ||||
| 	k, err := ks.GetKey(addr, "g") | ||||
| 	if err != nil { | ||||
| @ -178,7 +179,7 @@ func TestV1_2(t *testing.T) { | ||||
| 		t.Fatal(fmt.Errorf("Unexpected address: %v, expected %v", k.Address, addr)) | ||||
| 	} | ||||
| 
 | ||||
| 	privHex := hex.EncodeToString(FromECDSA(k.PrivateKey)) | ||||
| 	privHex := hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)) | ||||
| 	expectedHex := "d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d" | ||||
| 	if privHex != expectedHex { | ||||
| 		t.Fatal(fmt.Errorf("Unexpected privkey: %v, expected %v", privHex, expectedHex)) | ||||
							
								
								
									
										132
									
								
								accounts/presale.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								accounts/presale.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | ||||
| // Copyright 2016 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // 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.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package accounts | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/aes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/pborman/uuid" | ||||
| 	"golang.org/x/crypto/pbkdf2" | ||||
| ) | ||||
| 
 | ||||
| // creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
 | ||||
| func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (*Key, error) { | ||||
| 	key, err := decryptPreSaleKey(keyJSON, password) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	key.Id = uuid.NewRandom() | ||||
| 	err = keyStore.StoreKey(key, password) | ||||
| 	return key, err | ||||
| } | ||||
| 
 | ||||
| func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) { | ||||
| 	preSaleKeyStruct := struct { | ||||
| 		EncSeed string | ||||
| 		EthAddr string | ||||
| 		Email   string | ||||
| 		BtcAddr string | ||||
| 	}{} | ||||
| 	err = json.Unmarshal(fileContent, &preSaleKeyStruct) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) | ||||
| 	iv := encSeedBytes[:16] | ||||
| 	cipherText := encSeedBytes[16:] | ||||
| 	/* | ||||
| 		See https://github.com/ethereum/pyethsaletool
 | ||||
| 
 | ||||
| 		pyethsaletool generates the encryption key from password by | ||||
| 		2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:(). | ||||
| 		16 byte key length within PBKDF2 and resulting key is used as AES key | ||||
| 	*/ | ||||
| 	passBytes := []byte(password) | ||||
| 	derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) | ||||
| 	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ethPriv := crypto.Keccak256(plainText) | ||||
| 	ecKey := crypto.ToECDSA(ethPriv) | ||||
| 	key = &Key{ | ||||
| 		Id:         nil, | ||||
| 		Address:    crypto.PubkeyToAddress(ecKey.PublicKey), | ||||
| 		PrivateKey: ecKey, | ||||
| 	} | ||||
| 	derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
 | ||||
| 	expectedAddr := preSaleKeyStruct.EthAddr | ||||
| 	if derivedAddr != expectedAddr { | ||||
| 		err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr) | ||||
| 	} | ||||
| 	return key, err | ||||
| } | ||||
| 
 | ||||
| func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { | ||||
| 	// AES-128 is selected due to size of encryptKey.
 | ||||
| 	aesBlock, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	stream := cipher.NewCTR(aesBlock, iv) | ||||
| 	outText := make([]byte, len(inText)) | ||||
| 	stream.XORKeyStream(outText, inText) | ||||
| 	return outText, err | ||||
| } | ||||
| 
 | ||||
| func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) { | ||||
| 	aesBlock, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	decrypter := cipher.NewCBCDecrypter(aesBlock, iv) | ||||
| 	paddedPlaintext := make([]byte, len(cipherText)) | ||||
| 	decrypter.CryptBlocks(paddedPlaintext, cipherText) | ||||
| 	plaintext := pkcs7Unpad(paddedPlaintext) | ||||
| 	if plaintext == nil { | ||||
| 		err = errors.New("Decryption failed: PKCS7Unpad failed after AES decryption") | ||||
| 	} | ||||
| 	return plaintext, err | ||||
| } | ||||
| 
 | ||||
| // From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
 | ||||
| func pkcs7Unpad(in []byte) []byte { | ||||
| 	if len(in) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	padding := in[len(in)-1] | ||||
| 	if int(padding) > len(in) || padding > aes.BlockSize { | ||||
| 		return nil | ||||
| 	} else if padding == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- { | ||||
| 		if in[i] != padding { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return in[:len(in)-int(padding)] | ||||
| } | ||||
| @ -42,8 +42,6 @@ import ( | ||||
| const ( | ||||
| 	testSolcPath = "" | ||||
| 	solcVersion  = "0.9.23" | ||||
| 
 | ||||
| 	testKey     = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674" | ||||
| 	testAddress  = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" | ||||
| 	testBalance  = "10000000000000000000" | ||||
| 	// of empty string
 | ||||
| @ -52,7 +50,8 @@ const ( | ||||
| 
 | ||||
| var ( | ||||
| 	versionRE      = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`)) | ||||
| 	testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")) | ||||
| 	testNodeKey, _ = crypto.HexToECDSA("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f") | ||||
| 	testAccount, _ = crypto.HexToECDSA("e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674") | ||||
| 	testGenesis    = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}` | ||||
| ) | ||||
| 
 | ||||
| @ -99,12 +98,9 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod | ||||
| 		t.Fatalf("failed to create node: %v", err) | ||||
| 	} | ||||
| 	// Initialize and register the Ethereum protocol
 | ||||
| 	keystore := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore")) | ||||
| 	accman := accounts.NewManager(keystore) | ||||
| 
 | ||||
| 	accman := accounts.NewPlaintextManager(filepath.Join(tmp, "keystore")) | ||||
| 	db, _ := ethdb.NewMemDatabase() | ||||
| 	core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)}) | ||||
| 
 | ||||
| 	ethConf := ð.Config{ | ||||
| 		ChainConfig:      &core.ChainConfig{HomesteadBlock: new(big.Int)}, | ||||
| 		TestGenesisState: db, | ||||
| @ -122,15 +118,11 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod | ||||
| 		t.Fatalf("failed to register ethereum protocol: %v", err) | ||||
| 	} | ||||
| 	// Initialize all the keys for testing
 | ||||
| 	keyb, err := crypto.HexToECDSA(testKey) | ||||
| 	a, err := accman.ImportECDSA(testAccount, "") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	key := crypto.NewKeyFromECDSA(keyb) | ||||
| 	if err := keystore.StoreKey(key, ""); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if err := accman.Unlock(key.Address, ""); err != nil { | ||||
| 	if err := accman.Unlock(a.Address, ""); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	// Start the node and assemble the REPL tester
 | ||||
|  | ||||
| @ -106,18 +106,17 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// Create the keystore and inject an unlocked account if requested
 | ||||
| 	keystore := crypto.NewKeyStorePassphrase(keydir, crypto.StandardScryptN, crypto.StandardScryptP) | ||||
| 	accman := accounts.NewManager(keystore) | ||||
| 
 | ||||
| 	accman := accounts.NewPlaintextManager(keydir) | ||||
| 	if len(privkey) > 0 { | ||||
| 		key, err := crypto.HexToECDSA(privkey) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if err := keystore.StoreKey(crypto.NewKeyFromECDSA(key), ""); err != nil { | ||||
| 		a, err := accman.ImportECDSA(key, "") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if err := accman.Unlock(crypto.NewKeyFromECDSA(key).Address, ""); err != nil { | ||||
| 		if err := accman.Unlock(a.Address, ""); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -551,20 +551,15 @@ func MakeDatabaseHandles() int { | ||||
| // MakeAccountManager creates an account manager from set command line flags.
 | ||||
| func MakeAccountManager(ctx *cli.Context) *accounts.Manager { | ||||
| 	// Create the keystore crypto primitive, light if requested
 | ||||
| 	scryptN := crypto.StandardScryptN | ||||
| 	scryptP := crypto.StandardScryptP | ||||
| 
 | ||||
| 	scryptN := accounts.StandardScryptN | ||||
| 	scryptP := accounts.StandardScryptP | ||||
| 	if ctx.GlobalBool(LightKDFFlag.Name) { | ||||
| 		scryptN = crypto.LightScryptN | ||||
| 		scryptP = crypto.LightScryptP | ||||
| 		scryptN = accounts.LightScryptN | ||||
| 		scryptP = accounts.LightScryptP | ||||
| 	} | ||||
| 	// Assemble an account manager using the configured datadir
 | ||||
| 	var ( | ||||
| 		datadir     = MustMakeDataDir(ctx) | ||||
| 		keystoredir = MakeKeyStoreDir(datadir, ctx) | ||||
| 		keystore    = crypto.NewKeyStorePassphrase(keystoredir, scryptN, scryptP) | ||||
| 	) | ||||
| 	return accounts.NewManager(keystore) | ||||
| 	datadir := MustMakeDataDir(ctx) | ||||
| 	keydir := MakeKeyStoreDir(datadir, ctx) | ||||
| 	return accounts.NewManager(keydir, scryptN, scryptP) | ||||
| } | ||||
| 
 | ||||
| // MakeAddress converts an account specified directly as a hex encoded string or
 | ||||
|  | ||||
							
								
								
									
										106
									
								
								crypto/crypto.go
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								crypto/crypto.go
									
									
									
									
									
								
							| @ -17,8 +17,6 @@ | ||||
| package crypto | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/aes" | ||||
| 	"crypto/cipher" | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/elliptic" | ||||
| 	"crypto/rand" | ||||
| @ -30,7 +28,6 @@ import ( | ||||
| 	"os" | ||||
| 
 | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| @ -38,8 +35,6 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/crypto/secp256k1" | ||||
| 	"github.com/ethereum/go-ethereum/crypto/sha3" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| 	"github.com/pborman/uuid" | ||||
| 	"golang.org/x/crypto/pbkdf2" | ||||
| 	"golang.org/x/crypto/ripemd160" | ||||
| ) | ||||
| 
 | ||||
| @ -217,107 +212,6 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) { | ||||
| 	return key.Decrypt(rand.Reader, ct, nil, nil) | ||||
| } | ||||
| 
 | ||||
| // creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
 | ||||
| func ImportPreSaleKey(keyStore KeyStore, keyJSON []byte, password string) (*Key, error) { | ||||
| 	key, err := decryptPreSaleKey(keyJSON, password) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	key.Id = uuid.NewRandom() | ||||
| 	err = keyStore.StoreKey(key, password) | ||||
| 	return key, err | ||||
| } | ||||
| 
 | ||||
| func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error) { | ||||
| 	preSaleKeyStruct := struct { | ||||
| 		EncSeed string | ||||
| 		EthAddr string | ||||
| 		Email   string | ||||
| 		BtcAddr string | ||||
| 	}{} | ||||
| 	err = json.Unmarshal(fileContent, &preSaleKeyStruct) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) | ||||
| 	iv := encSeedBytes[:16] | ||||
| 	cipherText := encSeedBytes[16:] | ||||
| 	/* | ||||
| 		See https://github.com/ethereum/pyethsaletool
 | ||||
| 
 | ||||
| 		pyethsaletool generates the encryption key from password by | ||||
| 		2000 rounds of PBKDF2 with HMAC-SHA-256 using password as salt (:(). | ||||
| 		16 byte key length within PBKDF2 and resulting key is used as AES key | ||||
| 	*/ | ||||
| 	passBytes := []byte(password) | ||||
| 	derivedKey := pbkdf2.Key(passBytes, passBytes, 2000, 16, sha256.New) | ||||
| 	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	ethPriv := Keccak256(plainText) | ||||
| 	ecKey := ToECDSA(ethPriv) | ||||
| 	key = &Key{ | ||||
| 		Id:         nil, | ||||
| 		Address:    PubkeyToAddress(ecKey.PublicKey), | ||||
| 		PrivateKey: ecKey, | ||||
| 	} | ||||
| 	derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
 | ||||
| 	expectedAddr := preSaleKeyStruct.EthAddr | ||||
| 	if derivedAddr != expectedAddr { | ||||
| 		err = fmt.Errorf("decrypted addr '%s' not equal to expected addr '%s'", derivedAddr, expectedAddr) | ||||
| 	} | ||||
| 	return key, err | ||||
| } | ||||
| 
 | ||||
| // AES-128 is selected due to size of encryptKey
 | ||||
| func aesCTRXOR(key, inText, iv []byte) ([]byte, error) { | ||||
| 	aesBlock, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	stream := cipher.NewCTR(aesBlock, iv) | ||||
| 	outText := make([]byte, len(inText)) | ||||
| 	stream.XORKeyStream(outText, inText) | ||||
| 	return outText, err | ||||
| } | ||||
| 
 | ||||
| func aesCBCDecrypt(key, cipherText, iv []byte) ([]byte, error) { | ||||
| 	aesBlock, err := aes.NewCipher(key) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	decrypter := cipher.NewCBCDecrypter(aesBlock, iv) | ||||
| 	paddedPlaintext := make([]byte, len(cipherText)) | ||||
| 	decrypter.CryptBlocks(paddedPlaintext, cipherText) | ||||
| 	plaintext := PKCS7Unpad(paddedPlaintext) | ||||
| 	if plaintext == nil { | ||||
| 		err = errors.New("Decryption failed: PKCS7Unpad failed after AES decryption") | ||||
| 	} | ||||
| 	return plaintext, err | ||||
| } | ||||
| 
 | ||||
| // From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
 | ||||
| func PKCS7Unpad(in []byte) []byte { | ||||
| 	if len(in) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	padding := in[len(in)-1] | ||||
| 	if int(padding) > len(in) || padding > aes.BlockSize { | ||||
| 		return nil | ||||
| 	} else if padding == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	for i := len(in) - 1; i > len(in)-int(padding)-1; i-- { | ||||
| 		if in[i] != padding { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return in[:len(in)-int(padding)] | ||||
| } | ||||
| 
 | ||||
| func PubkeyToAddress(p ecdsa.PublicKey) common.Address { | ||||
| 	pubBytes := FromECDSAPub(&p) | ||||
| 	return common.BytesToAddress(Keccak256(pubBytes[1:])[12:]) | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| package eth | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/ecdsa" | ||||
| 	"crypto/rand" | ||||
| 	"math/big" | ||||
| 	"sync" | ||||
| @ -94,10 +95,9 @@ func (p *testTxPool) GetTransactions() types.Transactions { | ||||
| } | ||||
| 
 | ||||
| // newTestTransaction create a new dummy transaction.
 | ||||
| func newTestTransaction(from *crypto.Key, nonce uint64, datasize int) *types.Transaction { | ||||
| func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { | ||||
| 	tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) | ||||
| 	tx, _ = tx.SignECDSA(from.PrivateKey) | ||||
| 
 | ||||
| 	tx, _ = tx.SignECDSA(from) | ||||
| 	return tx | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,6 @@ | ||||
| package eth | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| @ -35,7 +34,7 @@ func init() { | ||||
| 	// glog.SetV(6)
 | ||||
| } | ||||
| 
 | ||||
| var testAccount = crypto.NewKey(rand.Reader) | ||||
| var testAccount, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||||
| 
 | ||||
| // Tests that handshake failures are detected and reported correctly.
 | ||||
| func TestStatusMsgErrors61(t *testing.T) { testStatusMsgErrors(t, 61) } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user