mirror of https://github.com/status-im/op-geth.git
Merge pull request #631 from Gustav-Simonsson/improve_key_store_crypto
Improve key store crypto
This commit is contained in:
commit
d6357aa616
|
@ -33,7 +33,6 @@ and accounts persistence is derived from stored keys' addresses
|
|||
package accounts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"errors"
|
||||
|
@ -41,6 +40,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
|
@ -50,12 +50,12 @@ var (
|
|||
)
|
||||
|
||||
type Account struct {
|
||||
Address []byte
|
||||
Address common.Address
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
keyStore crypto.KeyStore2
|
||||
unlocked map[string]*unlocked
|
||||
unlocked map[common.Address]*unlocked
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -67,40 +67,40 @@ type unlocked struct {
|
|||
func NewManager(keyStore crypto.KeyStore2) *Manager {
|
||||
return &Manager{
|
||||
keyStore: keyStore,
|
||||
unlocked: make(map[string]*unlocked),
|
||||
unlocked: make(map[common.Address]*unlocked),
|
||||
}
|
||||
}
|
||||
|
||||
func (am *Manager) HasAccount(addr []byte) bool {
|
||||
func (am *Manager) HasAccount(addr common.Address) bool {
|
||||
accounts, _ := am.Accounts()
|
||||
for _, acct := range accounts {
|
||||
if bytes.Compare(acct.Address, addr) == 0 {
|
||||
if acct.Address == addr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (am *Manager) Primary() (addr []byte, err error) {
|
||||
func (am *Manager) Primary() (addr common.Address, err error) {
|
||||
addrs, err := am.keyStore.GetKeyAddresses()
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrNoKeys
|
||||
return common.Address{}, ErrNoKeys
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
return common.Address{}, err
|
||||
}
|
||||
if len(addrs) == 0 {
|
||||
return nil, ErrNoKeys
|
||||
return common.Address{}, ErrNoKeys
|
||||
}
|
||||
return addrs[0], nil
|
||||
}
|
||||
|
||||
func (am *Manager) DeleteAccount(address []byte, auth string) error {
|
||||
func (am *Manager) DeleteAccount(address common.Address, auth string) error {
|
||||
return am.keyStore.DeleteKey(address, auth)
|
||||
}
|
||||
|
||||
func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) {
|
||||
am.mutex.RLock()
|
||||
unlockedKey, found := am.unlocked[string(a.Address)]
|
||||
unlockedKey, found := am.unlocked[a.Address]
|
||||
am.mutex.RUnlock()
|
||||
if !found {
|
||||
return nil, ErrLocked
|
||||
|
@ -111,7 +111,7 @@ func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error)
|
|||
|
||||
// TimedUnlock unlocks the account with the given address.
|
||||
// When timeout has passed, the account will be locked again.
|
||||
func (am *Manager) TimedUnlock(addr []byte, keyAuth string, timeout time.Duration) error {
|
||||
func (am *Manager) TimedUnlock(addr common.Address, keyAuth string, timeout time.Duration) error {
|
||||
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -124,7 +124,7 @@ func (am *Manager) TimedUnlock(addr []byte, keyAuth string, timeout time.Duratio
|
|||
// Unlock unlocks the account with the given address. The account
|
||||
// stays unlocked until the program exits or until a TimedUnlock
|
||||
// timeout (started after the call to Unlock) expires.
|
||||
func (am *Manager) Unlock(addr []byte, keyAuth string) error {
|
||||
func (am *Manager) Unlock(addr common.Address, keyAuth string) error {
|
||||
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -157,10 +157,10 @@ func (am *Manager) Accounts() ([]Account, error) {
|
|||
return accounts, err
|
||||
}
|
||||
|
||||
func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked {
|
||||
func (am *Manager) addUnlocked(addr common.Address, key *crypto.Key) *unlocked {
|
||||
u := &unlocked{Key: key, abort: make(chan struct{})}
|
||||
am.mutex.Lock()
|
||||
prev, found := am.unlocked[string(addr)]
|
||||
prev, found := am.unlocked[addr]
|
||||
if found {
|
||||
// terminate dropLater for this key to avoid unexpected drops.
|
||||
close(prev.abort)
|
||||
|
@ -169,12 +169,12 @@ func (am *Manager) addUnlocked(addr []byte, key *crypto.Key) *unlocked {
|
|||
// key, i.e. when Unlock was used.
|
||||
zeroKey(prev.PrivateKey)
|
||||
}
|
||||
am.unlocked[string(addr)] = u
|
||||
am.unlocked[addr] = u
|
||||
am.mutex.Unlock()
|
||||
return u
|
||||
}
|
||||
|
||||
func (am *Manager) dropLater(addr []byte, u *unlocked, timeout time.Duration) {
|
||||
func (am *Manager) dropLater(addr common.Address, u *unlocked, timeout time.Duration) {
|
||||
t := time.NewTimer(timeout)
|
||||
defer t.Stop()
|
||||
select {
|
||||
|
@ -186,9 +186,9 @@ func (am *Manager) dropLater(addr []byte, u *unlocked, timeout time.Duration) {
|
|||
// was launched with. we can check that using pointer equality
|
||||
// because the map stores a new pointer every time the key is
|
||||
// unlocked.
|
||||
if am.unlocked[string(addr)] == u {
|
||||
if am.unlocked[addr] == u {
|
||||
zeroKey(u.PrivateKey)
|
||||
delete(am.unlocked, string(addr))
|
||||
delete(am.unlocked, addr)
|
||||
}
|
||||
am.mutex.Unlock()
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ func zeroKey(k *ecdsa.PrivateKey) {
|
|||
|
||||
// USE WITH CAUTION = this will save an unencrypted private key on disk
|
||||
// no cli or js interface
|
||||
func (am *Manager) Export(path string, addr []byte, keyAuth string) error {
|
||||
func (am *Manager) Export(path string, addr common.Address, keyAuth string) error {
|
||||
key, err := am.keyStore.GetKey(addr, keyAuth)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -126,7 +126,7 @@ func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
|
|||
// Add the accouns to a new set
|
||||
accountSet := set.New()
|
||||
for _, account := range accounts {
|
||||
accountSet.Add(common.BytesToAddress(account.Address))
|
||||
accountSet.Add(account.Address)
|
||||
}
|
||||
|
||||
//ltxs := make([]*tx, len(txs))
|
||||
|
@ -391,7 +391,7 @@ func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
|
|||
}
|
||||
}
|
||||
am := js.ethereum.AccountManager()
|
||||
err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second)
|
||||
err = am.TimedUnlock(common.HexToAddress(addr), passphrase, time.Duration(seconds)*time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("Unlock account failed '%v'\n", err)
|
||||
return otto.FalseValue()
|
||||
|
@ -433,7 +433,7 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
|
|||
fmt.Printf("Could not create the account: %v", err)
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
return js.re.ToVal(common.ToHex(acct.Address))
|
||||
return js.re.ToVal(acct.Address.Hex())
|
||||
}
|
||||
|
||||
func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/docserver"
|
||||
"github.com/ethereum/go-ethereum/common/natspec"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
|
@ -164,7 +165,7 @@ func (self *jsre) UnlockAccount(addr []byte) bool {
|
|||
return false
|
||||
}
|
||||
// TODO: allow retry
|
||||
if err := self.ethereum.AccountManager().Unlock(addr, pass); err != nil {
|
||||
if err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil {
|
||||
return false
|
||||
} else {
|
||||
fmt.Println("Account is now unlocked for this session.")
|
||||
|
|
|
@ -45,7 +45,7 @@ type testjethre struct {
|
|||
}
|
||||
|
||||
func (self *testjethre) UnlockAccount(acc []byte) bool {
|
||||
err := self.ethereum.AccountManager().Unlock(acc, "")
|
||||
err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "")
|
||||
if err != nil {
|
||||
panic("unable to unlock")
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
|
|||
// set up mock genesis with balance on the testAddress
|
||||
core.GenesisData = []byte(testGenesis)
|
||||
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keys"))
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keystore"))
|
||||
am := accounts.NewManager(ks)
|
||||
ethereum, err := eth.New(ð.Config{
|
||||
DataDir: tmp,
|
||||
|
|
|
@ -365,11 +365,10 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass
|
|||
// Load startup keys. XXX we are going to need a different format
|
||||
// Attempt to unlock the account
|
||||
passphrase = getPassPhrase(ctx, "", false)
|
||||
accbytes := common.FromHex(account)
|
||||
if len(accbytes) == 0 {
|
||||
if len(account) == 0 {
|
||||
utils.Fatalf("Invalid account address '%s'", account)
|
||||
}
|
||||
err = am.Unlock(accbytes, passphrase)
|
||||
err = am.Unlock(common.StringToAddress(account), passphrase)
|
||||
if err != nil {
|
||||
utils.Fatalf("Unlock account failed '%v'", err)
|
||||
}
|
||||
|
@ -385,11 +384,11 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|||
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
||||
if len(account) > 0 {
|
||||
if account == "primary" {
|
||||
accbytes, err := am.Primary()
|
||||
primaryAcc, err := am.Primary()
|
||||
if err != nil {
|
||||
utils.Fatalf("no primary account: %v", err)
|
||||
}
|
||||
account = common.ToHex(accbytes)
|
||||
account = primaryAcc.Hex()
|
||||
}
|
||||
unlockAccount(ctx, am, account)
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ func (self *Gui) loadMergedMiningOptions() {
|
|||
func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
|
||||
var inout string
|
||||
from, _ := tx.From()
|
||||
if gui.eth.AccountManager().HasAccount(common.Hex2Bytes(from.Hex())) {
|
||||
if gui.eth.AccountManager().HasAccount(from) {
|
||||
inout = "send"
|
||||
} else {
|
||||
inout = "recv"
|
||||
|
|
|
@ -346,7 +346,7 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat
|
|||
|
||||
func GetAccountManager(ctx *cli.Context) *accounts.Manager {
|
||||
dataDir := ctx.GlobalString(DataDirFlag.Name)
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keys"))
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore"))
|
||||
return accounts.NewManager(ks)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
|
@ -84,7 +85,7 @@ type testFrontend struct {
|
|||
}
|
||||
|
||||
func (self *testFrontend) UnlockAccount(acc []byte) bool {
|
||||
self.ethereum.AccountManager().Unlock(acc, "password")
|
||||
self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -103,19 +104,19 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
|
|||
|
||||
os.RemoveAll("/tmp/eth-natspec/")
|
||||
|
||||
err = os.MkdirAll("/tmp/eth-natspec/keys", os.ModePerm)
|
||||
err = os.MkdirAll("/tmp/eth-natspec/keystore", os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create a testAddress
|
||||
ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keys")
|
||||
ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore")
|
||||
am := accounts.NewManager(ks)
|
||||
testAccount, err := am.NewAccount("password")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testAddress := common.Bytes2Hex(testAccount.Address)
|
||||
testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
|
||||
|
||||
// set up mock genesis with balance on the testAddress
|
||||
core.GenesisData = []byte(`{
|
||||
|
|
|
@ -181,11 +181,11 @@ func Decrypt(prv *ecdsa.PrivateKey, ct []byte) ([]byte, error) {
|
|||
|
||||
// Used only by block tests.
|
||||
func ImportBlockTestKey(privKeyBytes []byte) error {
|
||||
ks := NewKeyStorePassphrase(common.DefaultDataDir() + "/keys")
|
||||
ks := NewKeyStorePassphrase(common.DefaultDataDir() + "/keystore")
|
||||
ecKey := ToECDSA(privKeyBytes)
|
||||
key := &Key{
|
||||
Id: uuid.NewRandom(),
|
||||
Address: PubkeyToAddress(ecKey.PublicKey),
|
||||
Address: common.BytesToAddress(PubkeyToAddress(ecKey.PublicKey)),
|
||||
PrivateKey: ecKey,
|
||||
}
|
||||
err := ks.StoreKey(key, "")
|
||||
|
@ -231,13 +231,13 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
|||
ecKey := ToECDSA(ethPriv)
|
||||
key = &Key{
|
||||
Id: nil,
|
||||
Address: PubkeyToAddress(ecKey.PublicKey),
|
||||
Address: common.BytesToAddress(PubkeyToAddress(ecKey.PublicKey)),
|
||||
PrivateKey: ecKey,
|
||||
}
|
||||
derivedAddr := common.Bytes2Hex(key.Address)
|
||||
derivedAddr := hex.EncodeToString(key.Address.Bytes()) // needed because .Hex() gives leading "0x"
|
||||
expectedAddr := preSaleKeyStruct.EthAddr
|
||||
if derivedAddr != expectedAddr {
|
||||
err = errors.New("decrypted addr not equal to expected addr")
|
||||
err = errors.New(fmt.Sprintf("decrypted addr not equal to expected addr ", derivedAddr, expectedAddr))
|
||||
}
|
||||
return key, err
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ func aesCBCDecrypt(key []byte, cipherText []byte, iv []byte) (plainText []byte,
|
|||
decrypter.CryptBlocks(paddedPlainText, cipherText)
|
||||
plainText = PKCS7Unpad(paddedPlainText)
|
||||
if plainText == nil {
|
||||
err = errors.New("Decryption failed: PKCS7Unpad failed after decryption")
|
||||
err = errors.New("Decryption failed: PKCS7Unpad failed after AES decryption")
|
||||
}
|
||||
return plainText, err
|
||||
}
|
||||
|
|
|
@ -26,44 +26,69 @@ package crypto
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "1"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
Id uuid.UUID // Version 4 "random" for unique id not derived from key data
|
||||
// to simplify lookups we also store the address
|
||||
Address []byte
|
||||
Address common.Address
|
||||
// we only store privkey as pubkey/address can be derived from it
|
||||
// privkey in this struct is always in plaintext
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
type plainKeyJSON struct {
|
||||
Id []byte
|
||||
Address []byte
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
type cipherJSON struct {
|
||||
Salt []byte
|
||||
IV []byte
|
||||
CipherText []byte
|
||||
Address string `json:"address"`
|
||||
PrivateKey string `json:"privatekey"`
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type encryptedKeyJSON struct {
|
||||
Id []byte
|
||||
Address []byte
|
||||
Crypto cipherJSON
|
||||
Address string `json:"address"`
|
||||
Crypto cryptoJSON
|
||||
Id string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type cryptoJSON struct {
|
||||
Cipher string `json:"cipher"`
|
||||
CipherText string `json:"ciphertext"`
|
||||
CipherParams cipherparamsJSON `json:"cipherparams"`
|
||||
KDF string `json:"kdf"`
|
||||
KDFParams scryptParamsJSON `json:"kdfparams"`
|
||||
MAC string `json:"mac"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type cipherparamsJSON struct {
|
||||
IV string `json:"iv"`
|
||||
}
|
||||
|
||||
type scryptParamsJSON struct {
|
||||
N int `json:"n"`
|
||||
R int `json:"r"`
|
||||
P int `json:"p"`
|
||||
DkLen int `json:"dklen"`
|
||||
Salt string `json:"salt"`
|
||||
}
|
||||
|
||||
func (k *Key) MarshalJSON() (j []byte, err error) {
|
||||
jStruct := plainKeyJSON{
|
||||
k.Id,
|
||||
k.Address,
|
||||
FromECDSA(k.PrivateKey),
|
||||
hex.EncodeToString(k.Address[:]),
|
||||
hex.EncodeToString(FromECDSA(k.PrivateKey)),
|
||||
k.Id.String(),
|
||||
version,
|
||||
}
|
||||
j, err = json.Marshal(jStruct)
|
||||
return j, err
|
||||
|
@ -77,19 +102,29 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
|
|||
}
|
||||
|
||||
u := new(uuid.UUID)
|
||||
*u = keyJSON.Id
|
||||
*u = uuid.Parse(keyJSON.Id)
|
||||
k.Id = *u
|
||||
k.Address = keyJSON.Address
|
||||
k.PrivateKey = ToECDSA(keyJSON.PrivateKey)
|
||||
addr, err := hex.DecodeString(keyJSON.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.Address = common.BytesToAddress(addr)
|
||||
k.PrivateKey = ToECDSA(privkey)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
|
||||
id := uuid.NewRandom()
|
||||
key := &Key{
|
||||
Id: id,
|
||||
Address: PubkeyToAddress(privateKeyECDSA.PublicKey),
|
||||
Address: common.BytesToAddress(PubkeyToAddress(privateKeyECDSA.PublicKey)),
|
||||
PrivateKey: privateKeyECDSA,
|
||||
}
|
||||
return key
|
||||
|
|
|
@ -28,24 +28,25 @@ the private key is encrypted and on disk uses another JSON encoding.
|
|||
|
||||
Cryptography:
|
||||
|
||||
1. Encryption key is scrypt derived key from user passphrase. Scrypt parameters
|
||||
1. Encryption key is first 16 bytes of SHA3-256 of first 16 bytes of
|
||||
scrypt derived key from user passphrase. Scrypt parameters
|
||||
(work factors) [1][2] are defined as constants below.
|
||||
2. Scrypt salt is 32 random bytes from CSPRNG. It is appended to ciphertext.
|
||||
3. Checksum is SHA3 of the private key bytes.
|
||||
4. Plaintext is concatenation of private key bytes and checksum.
|
||||
5. Encryption algo is AES 256 CBC [3][4]
|
||||
6. CBC IV is 16 random bytes from CSPRNG. It is appended to ciphertext.
|
||||
2. Scrypt salt is 32 random bytes from CSPRNG.
|
||||
It's stored in plain next to ciphertext in key file.
|
||||
3. MAC is SHA3-256 of concatenation of ciphertext and last 16 bytes of scrypt derived key.
|
||||
4. Plaintext is the EC private key bytes.
|
||||
5. Encryption algo is AES 128 CBC [3][4]
|
||||
6. CBC IV is 16 random bytes from CSPRNG.
|
||||
It's stored in plain next to ciphertext in key file.
|
||||
7. Plaintext padding is PKCS #7 [5][6]
|
||||
|
||||
Encoding:
|
||||
|
||||
1. On disk, ciphertext, salt and IV are encoded in a nested JSON object.
|
||||
1. On disk, the ciphertext, MAC, salt and IV are encoded in a nested JSON object.
|
||||
cat a key file to see the structure.
|
||||
2. byte arrays are base64 JSON strings.
|
||||
3. The EC private key bytes are in uncompressed form [7].
|
||||
They are a big-endian byte slice of the absolute value of D [8][9].
|
||||
4. The checksum is the last 32 bytes of the plaintext byte array and the
|
||||
private key is the preceeding bytes.
|
||||
|
||||
References:
|
||||
|
||||
|
@ -75,11 +76,14 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
keyHeaderVersion = "1"
|
||||
keyHeaderKDF = "scrypt"
|
||||
// 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
|
||||
scryptN = 1 << 18
|
||||
scryptr = 8
|
||||
|
@ -99,7 +103,7 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K
|
|||
return GenerateNewKeyDefault(ks, rand, auth)
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
|
||||
func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
|
||||
keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -112,43 +116,63 @@ func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err
|
|||
return key, err
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) {
|
||||
func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err error) {
|
||||
return GetKeyAddresses(ks.keysDirPath)
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
|
||||
authArray := []byte(auth)
|
||||
salt := randentropy.GetEntropyMixed(32)
|
||||
salt := randentropy.GetEntropyCSPRNG(32)
|
||||
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyBytes := FromECDSA(key.PrivateKey)
|
||||
keyBytesHash := Sha3(keyBytes)
|
||||
toEncrypt := PKCS7Pad(append(keyBytes, keyBytesHash...))
|
||||
encryptKey := Sha3(derivedKey[:16])[:16]
|
||||
|
||||
AES256Block, err := aes.NewCipher(derivedKey)
|
||||
keyBytes := FromECDSA(key.PrivateKey)
|
||||
toEncrypt := PKCS7Pad(keyBytes)
|
||||
|
||||
AES128Block, err := aes.NewCipher(encryptKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iv := randentropy.GetEntropyMixed(aes.BlockSize) // 16
|
||||
AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv)
|
||||
iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
|
||||
AES128CBCEncrypter := cipher.NewCBCEncrypter(AES128Block, iv)
|
||||
cipherText := make([]byte, len(toEncrypt))
|
||||
AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
|
||||
AES128CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
|
||||
|
||||
cipherStruct := cipherJSON{
|
||||
salt,
|
||||
iv,
|
||||
cipherText,
|
||||
mac := Sha3(derivedKey[16:32], cipherText)
|
||||
|
||||
scryptParamsJSON := scryptParamsJSON{
|
||||
N: scryptN,
|
||||
R: scryptr,
|
||||
P: scryptp,
|
||||
DkLen: scryptdkLen,
|
||||
Salt: hex.EncodeToString(salt),
|
||||
}
|
||||
keyStruct := encryptedKeyJSON{
|
||||
key.Id,
|
||||
key.Address,
|
||||
cipherStruct,
|
||||
|
||||
cipherParamsJSON := cipherparamsJSON{
|
||||
IV: hex.EncodeToString(iv),
|
||||
}
|
||||
keyJSON, err := json.Marshal(keyStruct)
|
||||
|
||||
cryptoStruct := cryptoJSON{
|
||||
Cipher: "aes-128-cbc",
|
||||
CipherText: hex.EncodeToString(cipherText),
|
||||
CipherParams: cipherParamsJSON,
|
||||
KDF: "scrypt",
|
||||
KDFParams: scryptParamsJSON,
|
||||
MAC: hex.EncodeToString(mac),
|
||||
Version: "1",
|
||||
}
|
||||
encryptedKeyJSON := encryptedKeyJSON{
|
||||
hex.EncodeToString(key.Address[:]),
|
||||
cryptoStruct,
|
||||
key.Id.String(),
|
||||
version,
|
||||
}
|
||||
keyJSON, err := json.Marshal(encryptedKeyJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -156,18 +180,18 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
|
|||
return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
|
||||
}
|
||||
|
||||
func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) {
|
||||
func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) {
|
||||
// only delete if correct passphrase is given
|
||||
_, _, err = DecryptKey(ks, keyAddr, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyDirPath := filepath.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
|
||||
keyDirPath := filepath.Join(ks.keysDirPath, hex.EncodeToString(keyAddr[:]))
|
||||
return os.RemoveAll(keyDirPath)
|
||||
}
|
||||
|
||||
func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||
func DecryptKey(ks keyStorePassphrase, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||
fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -176,25 +200,48 @@ func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []
|
|||
keyProtected := new(encryptedKeyJSON)
|
||||
err = json.Unmarshal(fileContent, keyProtected)
|
||||
|
||||
keyId = keyProtected.Id
|
||||
salt := keyProtected.Crypto.Salt
|
||||
iv := keyProtected.Crypto.IV
|
||||
cipherText := keyProtected.Crypto.CipherText
|
||||
keyId = uuid.Parse(keyProtected.Id)
|
||||
|
||||
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
salt, err := hex.DecodeString(keyProtected.Crypto.KDFParams.Salt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
n := keyProtected.Crypto.KDFParams.N
|
||||
r := keyProtected.Crypto.KDFParams.R
|
||||
p := keyProtected.Crypto.KDFParams.P
|
||||
dkLen := keyProtected.Crypto.KDFParams.DkLen
|
||||
|
||||
authArray := []byte(auth)
|
||||
derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
|
||||
derivedKey, err := scrypt.Key(authArray, salt, n, r, p, dkLen)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
|
||||
|
||||
calculatedMAC := Sha3(derivedKey[16:32], cipherText)
|
||||
if !bytes.Equal(calculatedMAC, mac) {
|
||||
err = errors.New("Decryption failed: MAC mismatch")
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
plainText, err := aesCBCDecrypt(Sha3(derivedKey[:16])[:16], cipherText, iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyBytes = plainText[:len(plainText)-32]
|
||||
keyBytesHash := plainText[len(plainText)-32:]
|
||||
if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
|
||||
err = errors.New("Decryption failed: checksum mismatch")
|
||||
return nil, nil, err
|
||||
}
|
||||
return keyBytes, keyId, err
|
||||
return plainText, keyId, err
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -37,10 +38,10 @@ import (
|
|||
type KeyStore2 interface {
|
||||
// create new key using io.Reader entropy source and optionally using auth string
|
||||
GenerateNewKey(io.Reader, string) (*Key, error)
|
||||
GetKey([]byte, string) (*Key, error) // key from addr and auth string
|
||||
GetKeyAddresses() ([][]byte, error) // get all addresses
|
||||
StoreKey(*Key, string) error // store key optionally using auth string
|
||||
DeleteKey([]byte, string) error // delete key by addr and auth string
|
||||
GetKey(common.Address, string) (*Key, error) // 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
|
||||
}
|
||||
|
||||
type keyStorePlain struct {
|
||||
|
@ -66,7 +67,7 @@ func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key,
|
|||
return key, err
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
|
||||
func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
|
||||
fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -77,7 +78,7 @@ func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error
|
|||
return key, err
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
|
||||
func (ks keyStorePlain) GetKeyAddresses() (addresses []common.Address, err error) {
|
||||
return GetKeyAddresses(ks.keysDirPath)
|
||||
}
|
||||
|
||||
|
@ -90,19 +91,19 @@ func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
|
||||
keyDirPath := filepath.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
|
||||
func (ks keyStorePlain) DeleteKey(keyAddr common.Address, auth string) (err error) {
|
||||
keyDirPath := filepath.Join(ks.keysDirPath, keyAddr.Hex())
|
||||
err = os.RemoveAll(keyDirPath)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
|
||||
fileName := hex.EncodeToString(keyAddr)
|
||||
func GetKeyFile(keysDirPath string, keyAddr common.Address) (fileContent []byte, err error) {
|
||||
fileName := hex.EncodeToString(keyAddr[:])
|
||||
return ioutil.ReadFile(filepath.Join(keysDirPath, fileName, fileName))
|
||||
}
|
||||
|
||||
func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
|
||||
addrHex := hex.EncodeToString(addr)
|
||||
func WriteKeyFile(addr common.Address, keysDirPath string, content []byte) (err error) {
|
||||
addrHex := hex.EncodeToString(addr[:])
|
||||
keyDirPath := filepath.Join(keysDirPath, addrHex)
|
||||
keyFilePath := filepath.Join(keyDirPath, addrHex)
|
||||
err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
|
||||
|
@ -112,7 +113,7 @@ func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
|
|||
return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
|
||||
}
|
||||
|
||||
func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
|
||||
func GetKeyAddresses(keysDirPath string) (addresses []common.Address, err error) {
|
||||
fileInfos, err := ioutil.ReadDir(keysDirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -122,7 +123,7 @@ func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
addresses = append(addresses, address)
|
||||
addresses = append(addresses, common.BytesToAddress(address))
|
||||
}
|
||||
return addresses, err
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto/randentropy"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
|
|
@ -2,12 +2,8 @@ package randentropy
|
|||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var Reader io.Reader = &randEntropy{}
|
||||
|
@ -16,7 +12,7 @@ type randEntropy struct {
|
|||
}
|
||||
|
||||
func (*randEntropy) Read(bytes []byte) (n int, err error) {
|
||||
readBytes := GetEntropyMixed(len(bytes))
|
||||
readBytes := GetEntropyCSPRNG(len(bytes))
|
||||
copy(bytes, readBytes)
|
||||
return len(bytes), nil
|
||||
}
|
||||
|
@ -29,40 +25,6 @@ func Sha3(data []byte) []byte {
|
|||
return d.Sum(nil)
|
||||
}
|
||||
|
||||
// TODO: verify. this needs to be audited
|
||||
// we start with crypt/rand, then XOR in additional entropy from OS
|
||||
func GetEntropyMixed(n int) []byte {
|
||||
startTime := time.Now().UnixNano()
|
||||
// for each source, we take SHA3 of the source and use it as seed to math/rand
|
||||
// then read bytes from it and XOR them onto the bytes read from crypto/rand
|
||||
mainBuff := GetEntropyCSPRNG(n)
|
||||
// 1. OS entropy sources
|
||||
startTimeBytes := make([]byte, 32)
|
||||
binary.PutVarint(startTimeBytes, startTime)
|
||||
startTimeHash := Sha3(startTimeBytes)
|
||||
mixBytes(mainBuff, startTimeHash)
|
||||
|
||||
pid := os.Getpid()
|
||||
pidBytes := make([]byte, 32)
|
||||
binary.PutUvarint(pidBytes, uint64(pid))
|
||||
pidHash := Sha3(pidBytes)
|
||||
mixBytes(mainBuff, pidHash)
|
||||
|
||||
osEnv := os.Environ()
|
||||
osEnvBytes := []byte(strings.Join(osEnv, ""))
|
||||
osEnvHash := Sha3(osEnvBytes)
|
||||
mixBytes(mainBuff, osEnvHash)
|
||||
|
||||
// not all OS have hostname in env variables
|
||||
osHostName, err := os.Hostname()
|
||||
if err != nil {
|
||||
osHostNameBytes := []byte(osHostName)
|
||||
osHostNameHash := Sha3(osHostNameBytes)
|
||||
mixBytes(mainBuff, osHostNameHash)
|
||||
}
|
||||
return mainBuff
|
||||
}
|
||||
|
||||
func GetEntropyCSPRNG(n int) []byte {
|
||||
mainBuff := make([]byte, n)
|
||||
_, err := io.ReadFull(crand.Reader, mainBuff)
|
||||
|
@ -71,14 +33,3 @@ func GetEntropyCSPRNG(n int) []byte {
|
|||
}
|
||||
return mainBuff
|
||||
}
|
||||
|
||||
func mixBytes(buff []byte, mixBuff []byte) []byte {
|
||||
bytesToMix := len(buff)
|
||||
if bytesToMix > 32 {
|
||||
bytesToMix = 32
|
||||
}
|
||||
for i := 0; i < bytesToMix; i++ {
|
||||
buff[i] ^= mixBuff[i]
|
||||
}
|
||||
return buff
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func GenerateKeyPair() ([]byte, []byte) {
|
|||
const seckey_len = 32
|
||||
|
||||
var pubkey []byte = make([]byte, pubkey_len)
|
||||
var seckey []byte = randentropy.GetEntropyMixed(seckey_len)
|
||||
var seckey []byte = randentropy.GetEntropyCSPRNG(seckey_len)
|
||||
|
||||
var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
|
||||
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
|
||||
|
@ -99,7 +99,7 @@ func GeneratePubKey(seckey []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
func Sign(msg []byte, seckey []byte) ([]byte, error) {
|
||||
nonce := randentropy.GetEntropyMixed(32)
|
||||
nonce := randentropy.GetEntropyCSPRNG(32)
|
||||
|
||||
var sig []byte = make([]byte, 65)
|
||||
var recid C.int
|
||||
|
|
|
@ -14,7 +14,7 @@ const SigSize = 65 //64+1
|
|||
|
||||
func Test_Secp256_00(t *testing.T) {
|
||||
|
||||
var nonce []byte = randentropy.GetEntropyMixed(32) //going to get bitcoins stolen!
|
||||
var nonce []byte = randentropy.GetEntropyCSPRNG(32) //going to get bitcoins stolen!
|
||||
|
||||
if len(nonce) != 32 {
|
||||
t.Fatal()
|
||||
|
@ -52,7 +52,7 @@ func Test_Secp256_01(t *testing.T) {
|
|||
//test size of messages
|
||||
func Test_Secp256_02s(t *testing.T) {
|
||||
pubkey, seckey := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
if sig == nil {
|
||||
|
@ -75,7 +75,7 @@ func Test_Secp256_02s(t *testing.T) {
|
|||
//test signing message
|
||||
func Test_Secp256_02(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
if sig == nil {
|
||||
t.Fatal("Signature nil")
|
||||
|
@ -98,7 +98,7 @@ func Test_Secp256_02(t *testing.T) {
|
|||
//test pubkey recovery
|
||||
func Test_Secp256_02a(t *testing.T) {
|
||||
pubkey1, seckey1 := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey1)
|
||||
|
||||
if sig == nil {
|
||||
|
@ -127,7 +127,7 @@ func Test_Secp256_02a(t *testing.T) {
|
|||
func Test_Secp256_03(t *testing.T) {
|
||||
_, seckey := GenerateKeyPair()
|
||||
for i := 0; i < TESTS; i++ {
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
|
||||
|
@ -143,7 +143,7 @@ func Test_Secp256_03(t *testing.T) {
|
|||
func Test_Secp256_04(t *testing.T) {
|
||||
for i := 0; i < TESTS; i++ {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
CompactSigTest(sig)
|
||||
|
||||
|
@ -166,7 +166,7 @@ func Test_Secp256_04(t *testing.T) {
|
|||
// -SIPA look at this
|
||||
|
||||
func randSig() []byte {
|
||||
sig := randentropy.GetEntropyMixed(65)
|
||||
sig := randentropy.GetEntropyCSPRNG(65)
|
||||
sig[32] &= 0x70
|
||||
sig[64] %= 4
|
||||
return sig
|
||||
|
@ -174,7 +174,7 @@ func randSig() []byte {
|
|||
|
||||
func Test_Secp256_06a_alt0(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
|
||||
if sig == nil {
|
||||
|
@ -205,12 +205,12 @@ func Test_Secp256_06a_alt0(t *testing.T) {
|
|||
|
||||
func Test_Secp256_06b(t *testing.T) {
|
||||
pubkey1, seckey := GenerateKeyPair()
|
||||
msg := randentropy.GetEntropyMixed(32)
|
||||
msg := randentropy.GetEntropyCSPRNG(32)
|
||||
sig, _ := Sign(msg, seckey)
|
||||
|
||||
fail_count := 0
|
||||
for i := 0; i < TESTS; i++ {
|
||||
msg = randentropy.GetEntropyMixed(32)
|
||||
msg = randentropy.GetEntropyCSPRNG(32)
|
||||
pubkey2, _ := RecoverPubkey(msg, sig)
|
||||
if bytes.Equal(pubkey1, pubkey2) == true {
|
||||
t.Fail()
|
||||
|
|
|
@ -386,14 +386,17 @@ func (s *Ethereum) StartMining(threads int) error {
|
|||
func (s *Ethereum) Etherbase() (eb common.Address, err error) {
|
||||
eb = s.etherbase
|
||||
if (eb == common.Address{}) {
|
||||
var ebbytes []byte
|
||||
ebbytes, err = s.accountManager.Primary()
|
||||
eb = common.BytesToAddress(ebbytes)
|
||||
if (eb == common.Address{}) {
|
||||
err = fmt.Errorf("no accounts found")
|
||||
primary, err := s.accountManager.Primary()
|
||||
if err != nil {
|
||||
return eb, err
|
||||
}
|
||||
if (primary == common.Address{}) {
|
||||
err = fmt.Errorf("no accounts found")
|
||||
return eb, err
|
||||
}
|
||||
eb = primary
|
||||
}
|
||||
return
|
||||
return eb, nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) StopMining() { s.miner.Stop() }
|
||||
|
@ -542,7 +545,7 @@ func (self *Ethereum) syncAccounts(tx *types.Transaction) {
|
|||
return
|
||||
}
|
||||
|
||||
if self.accountManager.HasAccount(from.Bytes()) {
|
||||
if self.accountManager.HasAccount(from) {
|
||||
if self.chainManager.TxState().GetNonce(from) < tx.Nonce() {
|
||||
self.chainManager.TxState().SetNonce(from, tx.Nonce())
|
||||
}
|
||||
|
|
|
@ -474,7 +474,7 @@ func gasprice(price *big.Int, pct int64) *big.Int {
|
|||
func accountAddressesSet(accounts []accounts.Account) *set.Set {
|
||||
accountSet := set.New()
|
||||
for _, account := range accounts {
|
||||
accountSet.Add(common.BytesToAddress(account.Address))
|
||||
accountSet.Add(account.Address)
|
||||
}
|
||||
return accountSet
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package rpc
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -117,7 +118,13 @@ func newHexData(input interface{}) *hexdata {
|
|||
binary.BigEndian.PutUint32(buff, input)
|
||||
d.data = buff
|
||||
case string: // hexstring
|
||||
d.data = common.Big(input).Bytes()
|
||||
// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded
|
||||
bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
|
||||
if err != nil {
|
||||
d.isNil = true
|
||||
} else {
|
||||
d.data = bytes
|
||||
}
|
||||
default:
|
||||
d.isNil = true
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ func runBlockTest(name string, test *BlockTest, t *testing.T) {
|
|||
}
|
||||
|
||||
func testEthConfig() *eth.Config {
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keys"))
|
||||
ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"))
|
||||
|
||||
return ð.Config{
|
||||
DataDir: common.DefaultDataDir(),
|
||||
|
|
|
@ -113,7 +113,7 @@ func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, erro
|
|||
if acct.PrivateKey != "" {
|
||||
privkey, err := hex.DecodeString(strings.TrimPrefix(acct.PrivateKey, "0x"))
|
||||
err = crypto.ImportBlockTestKey(privkey)
|
||||
err = ethereum.AccountManager().TimedUnlock(addr, "", 999999*time.Second)
|
||||
err = ethereum.AccountManager().TimedUnlock(common.BytesToAddress(addr), "", 999999*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ func (self *XEth) Accounts() []string {
|
|||
accounts, _ := self.backend.AccountManager().Accounts()
|
||||
accountAddresses := make([]string, len(accounts))
|
||||
for i, ac := range accounts {
|
||||
accountAddresses[i] = common.ToHex(ac.Address)
|
||||
accountAddresses[i] = ac.Address.Hex()
|
||||
}
|
||||
return accountAddresses
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
|
|||
if err != nil || len(accounts) == 0 {
|
||||
from = statedb.GetOrNewStateObject(common.Address{})
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(common.BytesToAddress(accounts[0].Address))
|
||||
from = statedb.GetOrNewStateObject(accounts[0].Address)
|
||||
}
|
||||
} else {
|
||||
from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr))
|
||||
|
@ -817,7 +817,7 @@ func (self *XEth) ConfirmTransaction(tx string) bool {
|
|||
}
|
||||
|
||||
func (self *XEth) doSign(from common.Address, hash common.Hash, didUnlock bool) ([]byte, error) {
|
||||
sig, err := self.backend.AccountManager().Sign(accounts.Account{Address: from.Bytes()}, hash.Bytes())
|
||||
sig, err := self.backend.AccountManager().Sign(accounts.Account{Address: from}, hash.Bytes())
|
||||
if err == accounts.ErrLocked {
|
||||
if didUnlock {
|
||||
return nil, fmt.Errorf("signer account still locked after successful unlock")
|
||||
|
|
Loading…
Reference in New Issue