Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal/ethapi: add personal_sign method #2940

Merged
merged 5 commits into from
Oct 28, 2016
Merged

Conversation

bas-vk
Copy link
Member

@bas-vk bas-vk commented Aug 24, 2016

This PR includes several things:

  1. the behavior of eth_sign is changed. It now accepts an arbitrary message, prepends a known message, hashes the result using keccak256 it calculates the signature of the hash (breaks backwards compatability!).
  2. add personal_sign, same semantics as eth_sign but also accepts a password. The private key used to sign the hash is temporary unlocked in the scope of the request.
  3. add personal_recover, returns the address for the account that created the signature.

personal_recover(message, signature)
personal_sign(hash, address [, password])

The known message added to the input before hashing is

"\x19Ethereum Signed Message:\n" + len(message).

@alexvandesande

@robotally
Copy link

robotally commented Aug 24, 2016

Vote Count Reviewers
👍 0
👎 0

Updated: Tue Sep 6 09:00:42 UTC 2016

@mention-bot
Copy link

@bas-vk, thanks for your PR! By analyzing the annotation information on this pull request, we identified @karalabe, @zsfelfoldi and @fjl to be potential reviewers

@Arachnid
Copy link
Contributor

With the impending advent of hardware wallets, I'm concerned this is overly internal-account-specific; is there any way to avoid hardcoding in passwords as an authentication mechanism? (I don't have a suggestion just yet, just thinking out loud)

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

If you use a hardware wallet, it's better to talk to it on the client side.

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

@bas-vk Can we seize this opportunity to fix some of the other issues with eth_sign?

  • It should hash the input on the server side.
  • There was some issue with the Ethereum-specific +27 v value

@Arachnid
Copy link
Contributor

If you use a hardware wallet, it's better to talk to it on the client side.

For signing, perhaps, but I'm thinking more about what sort of interfaces we offer that are backed by accounts, and how those will work if we support accounts other than those whose private keys are held by Geth.

@bas-vk
Copy link
Member Author

bas-vk commented Aug 24, 2016

@bas-vk Can we seize this opportunity to fix some of the other issues with eth_sign?

We can, this PR is rather small so I have no problem adding additional changes.

  • It should hash the input on the server side.

Changing this would break backwards compatibility for eth_sign. Exploiting this requires the key to be unlocked. And in that case obtaining the private key is nice but if it's possible to sign arbitrary data a thief basically has full control over the account during the time he can sign data. I will make this change for the new method.

  • There was some issue with the Ethereum-specific +27 v value

I believe the issue was that according to the yellow paper Ethereum hashes should have a signature with v+27 just like bitcoin. eth_sign currently doesn't add 27. Will add 27 to the signature of the new method to make it compliant with the yellow paper and leave eth_sign untouched.

Maybe at some point we can mark eth_sign deprecated.

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

Thanks. I agree that eth_sign should be deprecated, ideally quite soon. We can keep it around for the 1.5 release cycle and remove it in 1.6.

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

@fjl does the api take the hash or the message?
personal_sign(messageHash, signerAddress [, password])
personal_sign(messageBody, signerAddress [, password])

Its important that we pass the message so that the id mgmt layer (mist/metamask) can present the message to the user for approval

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

My proposal is as follows:

personal_sign(message, address [, password]) should sign keccak256(message) with the key that belongs to address and return the signature format that is commonly used in Ethereum (with V + 27). This means that the message would be available for display in MetaMask.

In internal discussions we have considered to prepend "Signed Ethereum Message:\n" to the message
on the server side. This would make it much harder to misuse the API (i.e. you can't sign a transaction this way). The idea of adding the prefix is not set in stone though.

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

I'm not sure how the prefix makes it much harder to misuse the API. can you expand?
If the attacker is trying to find a hash collision with a tx sig, they would just build a rainbow table with that prefix as the 'salt'.

I understand how a salt might be better than none, but maybe a dynamic salt like a timestamp would provide more security.

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

What we are concerned with specifically is the case of a malicious dapp creating (transaction) signatures on behalf of inexperienced users who just click yes.

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

Yes, that is the primary attack vector im worried about.

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

If you have more ideas for making this safer please dump them here. Adding a timestamp sounds nice at first, but keep in mind that something (probably a contract) will need to verify the signature eventually and it needs to add the same prefix. The user would need to submit the timestamp to said contract later and that sounds complicated. But maybe it's the right thing to do.

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

FWIW we are currently using the old version of the eth_sign API and displaying the messages.
We're currently reworking this UI and it will be more clear what exactly you are signing, the size of the message, and have a bunch of warnings not to sign any weird messages.

image

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

or just use a random salt and include it in the serialized message signature

personal_sign( message ){
  salt = random()
  sig = sign( hash( salt + message ) )
  return [sig, salt]
}

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

Yes that looks better (and pragmatic). I'll think about it.

@fjl fjl added this to the 1.5.0 milestone Aug 24, 2016
@fjl fjl added the crypto label Aug 24, 2016
@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

requesting comment from @Georgi87 and @mhhf who make use of user message signatures in the https://www.gnosis.pm/ predication market dapp

@kumavis
Copy link
Member

kumavis commented Aug 24, 2016

Theres still a problem with signing messages with the same key we use for tx sigs.

given a message signature, theres still a large search space for valid tx hashes that could match the message signature. Tx parameters such as value and toAddress provide a lot of search space that can be explored in parallel to find a hash collision.

evilTx: { value: allYourMoney, to: attacker01 }
evilTx: { value: allYourMoney, to: attacker02 }
evilTx: { value: allYourMoney, to: attacker03 }
...

While significant increasing scope and complexity of this issue, and perhaps breaking compat with existing geth single-key behavior, this could be alleviated by using a different key available on an hd-tree
ethereum/EIPs#84

@fjl
Copy link
Contributor

fjl commented Aug 24, 2016

@nagydani would be good to have your input here as well

@danfinlay
Copy link

Since we're talking about eth_sign, I'd like to chime in here that I think it would be way more useful if a method allowed signing/decrypting arbitrary lengthed data, not just hashes, and I've expressed this opinion in an EIP that hasn't gotten much of a response.

@PaulRBerg
Copy link
Contributor

@alexanderbez No, \x19 could still mean a small integer in RLP-encoding, it's just that is definitely not an RLP-encoded transaction.

Copy link

@kelvin488 kelvin488 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #

@ricmoo
Copy link

ricmoo commented Oct 20, 2021

Late to the game, but FYI:

Does anybody know where the \x19 originally came from?

It is one of the most clever retconed cases I've come across, so I thought I'd share.

The original was from \x18Bitcoin signed message:\n, where \x18 is a Bitcoin VarInt (for small numbers, it's just the same as the value) for 24, which is the length of the string "Bitcoin signed message:\n". So, \x19 is the Bitcoin VarInt for the length of the string `Ethereum signed message:\n".

As it turned out, 0x19 is a value that isn't a valid RLP encoded array, which is what all transactions are encoded as, and so EIP-191 was able to retcon it as the version byte. :)

Copy link

@jakazoll jakazoll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hash

@Yhozen
Copy link

Yhozen commented Nov 23, 2021

Hash

Hash indeed

// Note, Ethereum signatures have a particular format as described in the
// yellow paper. Use the SignEthereum function to calculate a signature
// in Ethereum format.
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
am.mu.RLock()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link

@Maryo77 Maryo77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

]()]()

@mantaray616
Copy link

Jump Task

@mantaray616
Copy link

2F1.bridge.walletconnect.orghttps://app.jumptask.io/home

if !found {
return nil, ErrLocked
}
return crypto.SignEthereum(hash, unlockedKey.PrivateKey)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32rzbnjmJfRa4MH8TcpdNtcdzSwkMRzRr9

@@ -46,7 +46,7 @@ var (
big.NewInt(1),
common.FromHex("5544"),
).WithSignature(
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤙

@@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
if address != keyAddr {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accounts/abi/bind/auth.go Asset Amount Asset Type Date Acquired Date Sold Proceeds (USD) Cost Basis (USD) Gain (USD) Type
0.00000229 BTC 12/12/2014 08/26/2017 0.01 0.00 0.01 Long Term
1.00010001 ZEC 12/20/2014 09/19/2017 0.39 0.03 0.36 Long Term
0.00082408 BTC 12/12/2014 09/19/2017 3.22 0.29 2.93 Long Term
4.12723423 XMR 08/20/2017 10/19/2017 538.57 565.08 -26.51 Short Term
0.00000002 BTC 01/28/2015 09/19/2017 0.00 0.00 0.00 Long Term
0.00000001 BTC 01/10/2015 09/19/2017 0.00 0.00 0.00 Long Term
0.10001200 LTC 12/21/2014 09/19/2017 0.04 0.00 0.04 Long Term
0.00004001 BTC 12/23/2014 09/19/2017 0.12 0.01 0.11 Long Term
0.00000100 ETH 12/20/2014 09/19/2017 0.00 0.00 0.00 Long Term

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import priv-keys in confirmation order

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.