Explorar el Código

accounts/keystore, crypto: enforce 256 bit keys on import

Péter Szilágyi hace 8 años
padre
commit
aa73420207

+ 2 - 3
accounts/keystore/key.go

@@ -124,14 +124,13 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
 	if err != nil {
 		return err
 	}
-
-	privkey, err := hex.DecodeString(keyJSON.PrivateKey)
+	privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey)
 	if err != nil {
 		return err
 	}
 
 	k.Address = common.BytesToAddress(addr)
-	k.PrivateKey = crypto.ToECDSA(privkey)
+	k.PrivateKey = privkey
 
 	return nil
 }

+ 0 - 1
accounts/keystore/keystore.go

@@ -450,7 +450,6 @@ func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (acco
 	if ks.cache.hasAddress(key.Address) {
 		return accounts.Account{}, fmt.Errorf("account already exists")
 	}
-
 	return ks.importKey(key, passphrase)
 }
 

+ 4 - 1
accounts/keystore/keystore_passphrase.go

@@ -182,7 +182,10 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
 	if err != nil {
 		return nil, err
 	}
-	key := crypto.ToECDSA(keyBytes)
+	key, err := crypto.ToECDSA(keyBytes)
+	if err != nil {
+		return nil, err
+	}
 	return &Key{
 		Id:         uuid.UUID(keyId),
 		Address:    crypto.PubkeyToAddress(key.PublicKey),

+ 1 - 1
accounts/keystore/keystore_passphrase_test.go

@@ -46,7 +46,7 @@ func TestKeyEncryptDecrypt(t *testing.T) {
 		// Decrypt with the correct password
 		key, err := DecryptKey(keyjson, password)
 		if err != nil {
-			t.Errorf("test %d: json key failed to decrypt: %v", i, err)
+			t.Fatalf("test %d: json key failed to decrypt: %v", i, err)
 		}
 		if key.Address != address {
 			t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address)

+ 4 - 1
accounts/keystore/presale.go

@@ -74,7 +74,10 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
 		return nil, err
 	}
 	ethPriv := crypto.Keccak256(plainText)
-	ecKey := crypto.ToECDSA(ethPriv)
+	ecKey, err := crypto.ToECDSA(ethPriv)
+	if err != nil {
+		return nil, err
+	}
 	key = &Key{
 		Id:         nil,
 		Address:    crypto.PubkeyToAddress(ecKey.PublicKey),

+ 1 - 1
core/types/transaction_test.go

@@ -79,7 +79,7 @@ func decodeTx(data []byte) (*Transaction, error) {
 }
 
 func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
-	key := crypto.ToECDSA(common.Hex2Bytes("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"))
+	key, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
 	addr := crypto.PubkeyToAddress(key.PublicKey)
 	return key, addr
 }

+ 12 - 15
crypto/crypto.go

@@ -22,12 +22,14 @@ import (
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"math/big"
 	"os"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/crypto/sha3"
 	"github.com/ethereum/go-ethereum/rlp"
 )
@@ -76,23 +78,22 @@ func CreateAddress(b common.Address, nonce uint64) common.Address {
 }
 
 // ToECDSA creates a private key with the given D value.
-func ToECDSA(prv []byte) *ecdsa.PrivateKey {
-	if len(prv) == 0 {
-		return nil
-	}
-
+func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
 	priv := new(ecdsa.PrivateKey)
 	priv.PublicKey.Curve = S256()
-	priv.D = new(big.Int).SetBytes(prv)
-	priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(prv)
-	return priv
+	if 8*len(d) != priv.Params().BitSize {
+		return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
+	}
+	priv.D = new(big.Int).SetBytes(d)
+	priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
+	return priv, nil
 }
 
 func FromECDSA(prv *ecdsa.PrivateKey) []byte {
 	if prv == nil {
 		return nil
 	}
-	return prv.D.Bytes()
+	return math.PaddedBigBytes(prv.D, 32)
 }
 
 func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
@@ -116,10 +117,7 @@ func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
 	if err != nil {
 		return nil, errors.New("invalid hex string")
 	}
-	if len(b) != 32 {
-		return nil, errors.New("invalid length, need 256 bits")
-	}
-	return ToECDSA(b), nil
+	return ToECDSA(b)
 }
 
 // LoadECDSA loads a secp256k1 private key from the given file.
@@ -139,8 +137,7 @@ func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
 	if err != nil {
 		return nil, err
 	}
-
-	return ToECDSA(key), nil
+	return ToECDSA(key)
 }
 
 // SaveECDSA saves a secp256k1 private key to the given file with

+ 2 - 4
internal/ethapi/api.go

@@ -19,7 +19,6 @@ package ethapi
 import (
 	"bytes"
 	"context"
-	"encoding/hex"
 	"errors"
 	"fmt"
 	"math/big"
@@ -283,12 +282,11 @@ func fetchKeystore(am *accounts.Manager) *keystore.KeyStore {
 // ImportRawKey stores the given hex encoded ECDSA key into the key directory,
 // encrypting it with the passphrase.
 func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) {
-	hexkey, err := hex.DecodeString(privkey)
+	key, err := crypto.HexToECDSA(privkey)
 	if err != nil {
 		return common.Address{}, err
 	}
-
-	acc, err := fetchKeystore(s.am).ImportECDSA(crypto.ToECDSA(hexkey), password)
+	acc, err := fetchKeystore(s.am).ImportECDSA(key, password)
 	return acc.Address, err
 }
 

+ 4 - 1
swarm/api/config_test.go

@@ -96,7 +96,10 @@ func TestConfigWriteRead(t *testing.T) {
 	}
 	defer os.RemoveAll(tmp)
 
-	prvkey := crypto.ToECDSA(common.Hex2Bytes(hexprvkey))
+	prvkey, err := crypto.HexToECDSA(hexprvkey)
+	if err != nil {
+		t.Fatalf("failed to load private key: %v", err)
+	}
 	orig, err := NewConfig(tmp, common.Address{}, prvkey, 323)
 	if err != nil {
 		t.Fatalf("expected no error, got %v", err)

+ 2 - 3
tests/util.go

@@ -18,7 +18,6 @@ package tests
 
 import (
 	"bytes"
-	"encoding/hex"
 	"fmt"
 	"math/big"
 	"os"
@@ -161,8 +160,8 @@ func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *st
 
 	origin := common.HexToAddress(tx["caller"])
 	if len(tx["secretKey"]) > 0 {
-		key, _ := hex.DecodeString(tx["secretKey"])
-		origin = crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
+		key, _ := crypto.HexToECDSA(tx["secretKey"])
+		origin = crypto.PubkeyToAddress(key.PublicKey)
 	}
 
 	var to *common.Address