Merge pull request #3453 from fjl/api-sign-recover-hex

internal/ethapi: fix hex handling for eth_sign, personal_{sign,recover}
This commit is contained in:
Péter Szilágyi 2016-12-19 11:49:21 +02:00 committed by GitHub
commit e871ae1270

View File

@ -28,6 +28,7 @@ import (
"github.com/ethereum/ethash" "github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -289,14 +290,14 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
} }
// signHash is a helper function that calculates a hash for the given message that can be // signHash is a helper function that calculates a hash for the given message that can be
// safely used to calculate a signature from. The hash is calulcated with: // safely used to calculate a signature from.
//
// The hash is calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
func signHash(message string) []byte { //
data := common.FromHex(message) // This gives context to the signed message and prevents signing of transactions.
// Give context to the signed message. This prevents an adversery to sign a tx. func signHash(data []byte) []byte {
// It has no cryptographic purpose.
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
// Always hash, this prevents choosen plaintext attacks that can extract key information
return crypto.Keccak256([]byte(msg)) return crypto.Keccak256([]byte(msg))
} }
@ -306,13 +307,8 @@ func signHash(message string) []byte {
// The key used to calculate the signature is decrypted with the given password. // The key used to calculate the signature is decrypted with the given password.
// //
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
func (s *PrivateAccountAPI) Sign(ctx context.Context, message string, addr common.Address, passwd string) (string, error) { func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) {
hash := signHash(message) return s.b.AccountManager().SignWithPassphrase(addr, passwd, signHash(data))
signature, err := s.b.AccountManager().SignWithPassphrase(addr, passwd, hash)
if err != nil {
return "0x", err
}
return common.ToHex(signature), nil
} }
// EcRecover returns the address for the account that was used to create the signature. // EcRecover returns the address for the account that was used to create the signature.
@ -322,29 +318,20 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, message string, addr commo
// addr = ecrecover(hash, signature) // addr = ecrecover(hash, signature)
// //
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, message string, signature string) (common.Address, error) { func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
var (
hash = signHash(message)
sig = common.FromHex(signature)
)
if len(sig) != 65 { if len(sig) != 65 {
return common.Address{}, fmt.Errorf("signature must be 65 bytes long") return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
} }
// see crypto.Ecrecover description // see crypto.Ecrecover description
if sig[64] == 27 || sig[64] == 28 { if sig[64] == 27 || sig[64] == 28 {
sig[64] -= 27 sig[64] -= 27
} }
rpk, err := crypto.Ecrecover(signHash(data), sig)
rpk, err := crypto.Ecrecover(hash, sig)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
pubKey := crypto.ToECDSAPub(rpk) pubKey := crypto.ToECDSAPub(rpk)
recoveredAddr := crypto.PubkeyToAddress(*pubKey) recoveredAddr := crypto.PubkeyToAddress(*pubKey)
return recoveredAddr, nil return recoveredAddr, nil
} }
@ -1116,10 +1103,8 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
// The account associated with addr must be unlocked. // The account associated with addr must be unlocked.
// //
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
func (s *PublicTransactionPoolAPI) Sign(addr common.Address, message string) (string, error) { func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
hash := signHash(message) return s.b.AccountManager().SignEthereum(addr, signHash(data))
signature, err := s.b.AccountManager().SignEthereum(addr, hash)
return common.ToHex(signature), err
} }
// SignTransactionArgs represents the arguments to sign a transaction. // SignTransactionArgs represents the arguments to sign a transaction.