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