Skip to content

Commit ef25b82

Browse files
authored
Merge pull request #14502 from karalabe/mobile-import-ecdsa
Enforce 256 bit keys on raw import, support raw mobile imports
2 parents 261b3e2 + 136f78f commit ef25b82

File tree

11 files changed

+49
-34
lines changed

11 files changed

+49
-34
lines changed

accounts/keystore/key.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,13 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
124124
if err != nil {
125125
return err
126126
}
127-
128-
privkey, err := hex.DecodeString(keyJSON.PrivateKey)
127+
privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey)
129128
if err != nil {
130129
return err
131130
}
132131

133132
k.Address = common.BytesToAddress(addr)
134-
k.PrivateKey = crypto.ToECDSA(privkey)
133+
k.PrivateKey = privkey
135134

136135
return nil
137136
}

accounts/keystore/keystore.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,6 @@ func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (acco
450450
if ks.cache.hasAddress(key.Address) {
451451
return accounts.Account{}, fmt.Errorf("account already exists")
452452
}
453-
454453
return ks.importKey(key, passphrase)
455454
}
456455

accounts/keystore/keystore_passphrase.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,10 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
182182
if err != nil {
183183
return nil, err
184184
}
185-
key := crypto.ToECDSA(keyBytes)
185+
key, err := crypto.ToECDSA(keyBytes)
186+
if err != nil {
187+
return nil, err
188+
}
186189
return &Key{
187190
Id: uuid.UUID(keyId),
188191
Address: crypto.PubkeyToAddress(key.PublicKey),

accounts/keystore/keystore_passphrase_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestKeyEncryptDecrypt(t *testing.T) {
4646
// Decrypt with the correct password
4747
key, err := DecryptKey(keyjson, password)
4848
if err != nil {
49-
t.Errorf("test %d: json key failed to decrypt: %v", i, err)
49+
t.Fatalf("test %d: json key failed to decrypt: %v", i, err)
5050
}
5151
if key.Address != address {
5252
t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)

accounts/keystore/presale.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
7474
return nil, err
7575
}
7676
ethPriv := crypto.Keccak256(plainText)
77-
ecKey := crypto.ToECDSA(ethPriv)
77+
ecKey, err := crypto.ToECDSA(ethPriv)
78+
if err != nil {
79+
return nil, err
80+
}
7881
key = &Key{
7982
Id: nil,
8083
Address: crypto.PubkeyToAddress(ecKey.PublicKey),

core/types/transaction_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func decodeTx(data []byte) (*Transaction, error) {
7979
}
8080

8181
func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
82-
key := crypto.ToECDSA(common.Hex2Bytes("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"))
82+
key, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
8383
addr := crypto.PubkeyToAddress(key.PublicKey)
8484
return key, addr
8585
}

crypto/crypto.go

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ import (
2222
"crypto/rand"
2323
"encoding/hex"
2424
"errors"
25+
"fmt"
2526
"io"
2627
"io/ioutil"
2728
"math/big"
2829
"os"
2930

3031
"github.com/ethereum/go-ethereum/common"
32+
"github.com/ethereum/go-ethereum/common/math"
3133
"github.com/ethereum/go-ethereum/crypto/sha3"
3234
"github.com/ethereum/go-ethereum/rlp"
3335
)
@@ -76,23 +78,22 @@ func CreateAddress(b common.Address, nonce uint64) common.Address {
7678
}
7779

7880
// ToECDSA creates a private key with the given D value.
79-
func ToECDSA(prv []byte) *ecdsa.PrivateKey {
80-
if len(prv) == 0 {
81-
return nil
82-
}
83-
81+
func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
8482
priv := new(ecdsa.PrivateKey)
8583
priv.PublicKey.Curve = S256()
86-
priv.D = new(big.Int).SetBytes(prv)
87-
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(prv)
88-
return priv
84+
if 8*len(d) != priv.Params().BitSize {
85+
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
86+
}
87+
priv.D = new(big.Int).SetBytes(d)
88+
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
89+
return priv, nil
8990
}
9091

9192
func FromECDSA(prv *ecdsa.PrivateKey) []byte {
9293
if prv == nil {
9394
return nil
9495
}
95-
return prv.D.Bytes()
96+
return math.PaddedBigBytes(prv.D, 32)
9697
}
9798

9899
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
@@ -116,10 +117,7 @@ func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
116117
if err != nil {
117118
return nil, errors.New("invalid hex string")
118119
}
119-
if len(b) != 32 {
120-
return nil, errors.New("invalid length, need 256 bits")
121-
}
122-
return ToECDSA(b), nil
120+
return ToECDSA(b)
123121
}
124122

125123
// LoadECDSA loads a secp256k1 private key from the given file.
@@ -139,8 +137,7 @@ func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
139137
if err != nil {
140138
return nil, err
141139
}
142-
143-
return ToECDSA(key), nil
140+
return ToECDSA(key)
144141
}
145142

146143
// SaveECDSA saves a secp256k1 private key to the given file with

internal/ethapi/api.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package ethapi
1919
import (
2020
"bytes"
2121
"context"
22-
"encoding/hex"
2322
"errors"
2423
"fmt"
2524
"math/big"
@@ -283,12 +282,11 @@ func fetchKeystore(am *accounts.Manager) *keystore.KeyStore {
283282
// ImportRawKey stores the given hex encoded ECDSA key into the key directory,
284283
// encrypting it with the passphrase.
285284
func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) {
286-
hexkey, err := hex.DecodeString(privkey)
285+
key, err := crypto.HexToECDSA(privkey)
287286
if err != nil {
288287
return common.Address{}, err
289288
}
290-
291-
acc, err := fetchKeystore(s.am).ImportECDSA(crypto.ToECDSA(hexkey), password)
289+
acc, err := fetchKeystore(s.am).ImportECDSA(key, password)
292290
return acc.Address, err
293291
}
294292

mobile/accounts.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/ethereum/go-ethereum/accounts"
2727
"github.com/ethereum/go-ethereum/accounts/keystore"
28+
"github.com/ethereum/go-ethereum/crypto"
2829
)
2930

3031
const (
@@ -176,6 +177,11 @@ func (ks *KeyStore) NewAccount(passphrase string) (*Account, error) {
176177
return &Account{account}, nil
177178
}
178179

180+
// UpdateAccount changes the passphrase of an existing account.
181+
func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error {
182+
return ks.keystore.Update(account.account, passphrase, newPassphrase)
183+
}
184+
179185
// ExportKey exports as a JSON key, encrypted with newPassphrase.
180186
func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) {
181187
return ks.keystore.Export(account.account, passphrase, newPassphrase)
@@ -190,9 +196,17 @@ func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string)
190196
return &Account{acc}, nil
191197
}
192198

193-
// UpdateAccount changes the passphrase of an existing account.
194-
func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error {
195-
return ks.keystore.Update(account.account, passphrase, newPassphrase)
199+
// ImportECDSAKey stores the given encrypted JSON key into the key directory.
200+
func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) {
201+
privkey, err := crypto.ToECDSA(key)
202+
if err != nil {
203+
return nil, err
204+
}
205+
acc, err := ks.keystore.ImportECDSA(privkey, passphrase)
206+
if err != nil {
207+
return nil, err
208+
}
209+
return &Account{acc}, nil
196210
}
197211

198212
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores

swarm/api/config_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ func TestConfigWriteRead(t *testing.T) {
9696
}
9797
defer os.RemoveAll(tmp)
9898

99-
prvkey := crypto.ToECDSA(common.Hex2Bytes(hexprvkey))
99+
prvkey, err := crypto.HexToECDSA(hexprvkey)
100+
if err != nil {
101+
t.Fatalf("failed to load private key: %v", err)
102+
}
100103
orig, err := NewConfig(tmp, common.Address{}, prvkey, 323)
101104
if err != nil {
102105
t.Fatalf("expected no error, got %v", err)

0 commit comments

Comments
 (0)