mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
append prefix and hash message before calculating signature
This commit is contained in:
parent
f116d1ab35
commit
9ae6a21e49
3 changed files with 36 additions and 18 deletions
|
|
@ -78,12 +78,12 @@ func Ripemd160(data []byte) []byte {
|
||||||
return ripemd.Sum(nil)
|
return ripemd.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ecrecover returns the public key for the private key that was used
|
// Ecrecover returns the public key for the private key that was used to
|
||||||
// to calculate the signature.
|
// calculate the signature.
|
||||||
//
|
//
|
||||||
// Note: secp256k1 expects the recover id to be either 0, 1. Ethereum
|
// Note: secp256k1 expects the recover id to be either 0, 1. Ethereum
|
||||||
// signatures have a recover id with an offset of 27. Callers must take
|
// signatures have a recover id with an offset of 27. Callers must take
|
||||||
// this into account and if "recovering" an Ethereum signature adjust.
|
// this into account and if "recovering" from an Ethereum signature adjust.
|
||||||
func Ecrecover(hash, sig []byte) ([]byte, error) {
|
func Ecrecover(hash, sig []byte) ([]byte, error) {
|
||||||
return secp256k1.RecoverPubkey(hash, sig)
|
return secp256k1.RecoverPubkey(hash, sig)
|
||||||
}
|
}
|
||||||
|
|
@ -221,8 +221,8 @@ func Sign(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
||||||
// SignEthereum calculates an Ethereum ECDSA signature.
|
// SignEthereum calculates an Ethereum ECDSA signature.
|
||||||
// This function is susceptible to choosen plaintext attacks that can leak
|
// This function is susceptible to choosen plaintext attacks that can leak
|
||||||
// information about the private key that is used for signing. Callers must
|
// information about the private key that is used for signing. Callers must
|
||||||
// be aware that the given hash cannot be choosen by an adversery. Common
|
// be aware that the given hash cannot be freely choosen by an adversery.
|
||||||
// solution is to hash any input before calculating the signature.
|
// Common solution is to hash the message before calculating the signature.
|
||||||
func SignEthereum(data []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
func SignEthereum(data []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
||||||
sig, err := Sign(data, prv)
|
sig, err := Sign(data, prv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -298,13 +298,26 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
|
||||||
return submitTransaction(ctx, s.b, tx, signature)
|
return submitTransaction(ctx, s.b, tx, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign calculates an ECDSA signature from keccack226(message).
|
// 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:
|
||||||
|
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
||||||
|
func signHash(message string) []byte {
|
||||||
|
data := common.FromHex(message)
|
||||||
|
// Give context to the signed message. This prevents an adversery to sign a tx.
|
||||||
|
// It has no cryptographic purpose.
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign calculates an Ethereum ECDSA signature for:
|
||||||
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
||||||
|
//
|
||||||
// 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, message string, addr common.Address, passwd string) (string, error) {
|
||||||
// always hash, this prevents choosen plaintext attacks that can extract the key
|
hash := signHash(message)
|
||||||
hash := crypto.Keccak256(common.FromHex(message))
|
|
||||||
signature, err := s.b.AccountManager().SignWithPassphrase(addr, passwd, hash)
|
signature, err := s.b.AccountManager().SignWithPassphrase(addr, passwd, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "0x", err
|
return "0x", err
|
||||||
|
|
@ -312,13 +325,17 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, message string, addr commo
|
||||||
return common.ToHex(signature), nil
|
return common.ToHex(signature), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// recover 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.
|
||||||
|
// Note, this function is compatible with eth_sign and personal_sign. As such it recovers
|
||||||
|
// the address of:
|
||||||
|
// hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message})
|
||||||
|
// addr = ecrecover(hash, signature)
|
||||||
//
|
//
|
||||||
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_recover
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
||||||
func (s *PrivateAccountAPI) Recover(ctx context.Context, message string, signature string) (common.Address, error) {
|
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, message string, signature string) (common.Address, error) {
|
||||||
var (
|
var (
|
||||||
|
hash = signHash(message)
|
||||||
sig = common.FromHex(signature)
|
sig = common.FromHex(signature)
|
||||||
hash = crypto.Keccak256(common.FromHex(message))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(sig) != 65 {
|
if len(sig) != 65 {
|
||||||
|
|
@ -1047,14 +1064,15 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
|
||||||
return tx.Hash().Hex(), nil
|
return tx.Hash().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign calculates an ECDSA signature from keccack226(message).
|
// Sign calculates an ECDSA signature for:
|
||||||
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
||||||
|
//
|
||||||
// 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, message string) (string, error) {
|
||||||
// always hash, this prevents choosen plaintext attacks that can extract the key
|
hash := signHash(message)
|
||||||
hash := crypto.Keccak256(common.FromHex(message))
|
signature, err := s.b.AccountManager().SignEthereum(addr, hash)
|
||||||
signature, err := s.b.AccountManager().SignEthereum(addr, hash[:])
|
|
||||||
return common.ToHex(signature), err
|
return common.ToHex(signature), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -436,8 +436,8 @@ web3._extend({
|
||||||
inputFormatter: [null, web3._extend.formatters.inputAddressFormatter, null]
|
inputFormatter: [null, web3._extend.formatters.inputAddressFormatter, null]
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'recover',
|
name: 'ecRecover',
|
||||||
call: 'personal_recover',
|
call: 'personal_ecRecover',
|
||||||
params: 2
|
params: 2
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue