add HashMessage to backend, lib, and mobile. (#1421)

* add HashMessage to backend, lib, and mobile.

* move HashMessage out of the backend struct

* fix comment typo
This commit is contained in:
Andrea Franz 2019-03-21 11:48:47 +01:00 committed by GitHub
parent eeaf669006
commit a61c0368bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 0 deletions

View File

@ -1,5 +1,11 @@
package api
import (
"fmt"
"github.com/ethereum/go-ethereum/crypto"
)
// RunAsync runs the specified function asynchronously.
func RunAsync(f func() error) <-chan error {
resp := make(chan error, 1)
@ -10,3 +16,12 @@ func RunAsync(f func() error) <-chan error {
}()
return resp
}
// HashMessage calculates the hash of a message to be safely signed by the keycard
// The hash is calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
// This gives context to the signed message and prevents signing of transactions.
func HashMessage(data []byte) []byte {
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
return crypto.Keccak256([]byte(msg))
}

45
api/utils_test.go Normal file
View File

@ -0,0 +1,45 @@
package api
import (
"fmt"
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/personal"
"github.com/status-im/status-go/t/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestHashMessage(t *testing.T) {
backend := NewStatusBackend()
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
require.NoError(t, err)
err = backend.StartNode(config)
require.NoError(t, err)
defer func() {
require.NoError(t, backend.StopNode())
}()
key, err := crypto.GenerateKey()
require.NoError(t, err)
addr := crypto.PubkeyToAddress(key.PublicKey)
originalMessage := []byte{0x01, 0x02, 0x03}
hash := HashMessage(originalMessage)
// simulate signature from external signer like a keycard
sig, err := crypto.Sign(hash, key)
require.NoError(t, err)
sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
// check that the message was wrapped correctly before hashing it
recParams := personal.RecoverParams{
Message: fmt.Sprintf("0x%x", originalMessage),
Signature: fmt.Sprintf("0x%x", sig),
}
recoveredAddr, err := backend.Recover(recParams)
require.NoError(t, err)
assert.Equal(t, addr, recoveredAddr)
}

View File

@ -454,6 +454,21 @@ func HashTransaction(txArgsJSON *C.char) *C.char {
return C.CString(prepareJSONResponseWithCode(result, err, code))
}
// HashMessage calculates the hash of a message to be safely signed by the keycard
// The hash is calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
// This gives context to the signed message and prevents signing of transactions.
//export HashMessage
func HashMessage(messageString *C.char) *C.char {
message, err := hex.DecodeString(C.GoString(messageString))
if err != nil {
return C.CString(prepareJSONResponseWithCode(nil, err, codeFailedParseParams))
}
hash := api.HashMessage(message)
return C.CString(prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, codeUnknown))
}
// SignTypedData unmarshall data into TypedData, validate it and signs with selected account,
// if password matches selected account.
//export SignTypedData

View File

@ -442,6 +442,20 @@ func HashTransaction(txArgsJSON string) string {
return prepareJSONResponseWithCode(result, err, code)
}
// HashMessage calculates the hash of a message to be safely signed by the keycard
// The hash is calulcated as
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
// This gives context to the signed message and prevents signing of transactions.
func HashMessage(messageString string) string {
message, err := hex.DecodeString(messageString)
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
hash := api.HashMessage(message)
return prepareJSONResponseWithCode(fmt.Sprintf("0x%x", hash), err, codeUnknown)
}
// StartCPUProfile runs pprof for CPU.
func StartCPUProfile(dataDir string) string {
err := profiling.StartCPUProfile(dataDir)