stellar-client
stellar-client copied to clipboard
sign message to prove address ownership
Please add a feature to the client which allows a user to sign a message or string with the private key, and then allow another user to verify the signature proving the owner of an address authored the message.
Bitcoin clients have this, and its pretty important to be able to prove a gateway or address owner really did author a document.
I would suggest a stellar client api call for sign_message(secretkey,message) -> signature and validate_message(address,sig,message) -> bool
This probably needs a stellard api for fetching public keys for a given address so the signature checks can take place.
edit: Further down It was worked out that the best method is... PersonA wants write a message proven to be authored be owner of addressA. personA signs messageX with privkeyA to create sigA. personA derives pubkeyA from privkeyA. personA sends pubkeyA messageX sigA to personB personB hashes pubkeyA to ensure it matches addressA. if not, signature failed. personB checks messageX sigA using pubkeyA. if passes, message is authentic.
sig + message + pubkey can all be combined
Seems to me this can be done completely out of band, without touching the stellard API. As I understand it, Stellar accounts have a public/private key pair, and the account ID is derived from a hash of the public key. Since you have access to the public/private key pair of your own account, it stands to reason that you can sign messages using the private key, provide the message and the public key together out-of-band as proof that you signed it, and the recipient can then validate that the account ID can be derived from the public key.
I can see the utility in providing this sort of functionality in the client, so I think this issue is reasonable. I'm just saying that it shouldn't require any change whatsoever to the protocol.
I agree signing, and verifying can be completely offline but...
How do you gain access to the public key to verify the signatures though? There needs to be a public api of (walletname or id) -> public key at least. I'll need to look into the algorithms used before I can code a proof of concept.
My usecase is proof of account ownership without forcing someone to send stellar to an address. e.g. a user messages to gateway -> "Hello gateway, I need you to pay all credit on the wallet andrewchambers into this alternative bank account XXX - stellar transaction id is FOO" - sig - XXXXXXX
gateway replies -> "Our gateway has paid the credit transferred in transaction id FOO to bank deposit with reference number BAR" sigYYYY
Both parties can verify this conversation is valid via the signatures and noone is forging anything, both can also verify the transaction id did take place by reading the network, and both parties can verify the bank reference number of the deposit.
bump after edit*
Incidentally, the Ripple RPC docs contain data_sign and data_verify commands as possible future commands to implement, which basically provides a way to ask the server to sign and validate arbitrary json blobs for you (without storing them anywhere). That would do exactly what you want here.
sweet, maybe that can be merged in, it just needs to be added to the stellar ui.
Well, it was never implemented in ripple to begin with (hence "possible future commands").
I realise (i meant in the future) , but if they are gonna do it, we don't need to. I don't know how much things are diverging in terms of code compatibility in merges.
It's up to stellar maintainers to decide the best way to implement it.
I'm just coming from the perspective of someone who wanted to design a specialized gateway, and this was a barrier I ran into while designing the basics of the architecture. I don't really care how its done, as long as its useable by moderately techinical people and in the official client.
+1000 on what @andrewchambers said. This is really important when one manages a gateway, so that I can make sure that I allow people to withdraw only from stellar accounts that they own. It's especially important that this is a simple functionality in the client. I don't want my customers to learn public key signing, that's unrealistic.
I don't understand how ripple or stellar can be securely used without this feature. Its currently impossible to securely prove a stellar address holder authored any sort of request. This isn't too bad in manually controlled gateways with human operators, but its a larger issue with gateways that are run entirely by software.
The current work around is to request a user transfer an arbitrary amount of STR to an arbitrary address just to prove they are the legitimate owner, but you must constantly change the address and amount to ensure attackers aren't guessing, or performing some sort of other tricks, this is far from a secure system.
I think stellar adding this feature would be a huge advantage over ripple.
Well, they could transfer something like 0.001 STR to an address with a specific destination tag. There's 4 billion destination tags, so that's kind of hard to guess (and if you're using an address dedicated to this purpose, you can re-use destination tags because they're only ever used once for a given authentication).
In any case, I'm not sure what data_sign and data_verify would do besides make things easier for client developers. Clients can produce signatures and verify them just as easily as the server can; in fact, since the "best" approach is to never even send your private key to the server at all but to always sign locally, good clients will already have the ability to sign arbitrary json blobs. The only remaining feature is implementing signature verification, but only your server has to do that.
Either way, whether the client supports signing, or whether the API supports data_sign, you still have to be able to instruct the user how to do it. You can't expect the user to understand the Stellar protocol, so telling them to issue a curl command to the API server with their secret key is, well, not very good. The destination tag approach may not be as "secure", but it is something users can understand how to do and won't require special client or server support.
I filed stellar/stellar-protocol#1 regarding changing destination tags to 64-bit, which would make the already-impractical attack of guessing destination tags (i.e. running through all of them) into an impossibility. In the meantime, if you do implement the destination tag approach, make the payment something higher than 1 stroop (e.g. 0.1 STR).
I agree 100 percent the server doesn't need any verify methods. What is needed is a stellard function of the form: getPubKey(address) -> pubkey So the client can actually verify the signatures. Perhaps I should edit my original post.
unless its possible to derive the public key from the address, which I don't know. I was told the address is a hash of the public key, so I assume the key isn't retrievable from the address alone..
The sending of funds to verify someone isn't an imposter is a huge and obvious flaw in the context of a system which is based on key pairs to sign transactions.
@andrewchambers The public key can be derived from the private key, given the curve parameters. It's ECDSA. Assuming Stellar is using the same curve as Ripple, you can get details at https://ripple.com/dev-blog/curves-with-a-twist/, which is a blog post from June 26th of this year about Ripple, talking about a possible change to a different elliptic curve, but it contains information about the current curve.
Also note that stellar-lib already contains the code to derive the public key and sign the tx_json blob. Surely if a javascript library can sign blobs, you can do it too.
You are not understanding properly, You don't have access to a persons private key (thats the point), so you cant derive it.
The only way this works is if they send the public key along with the message. But then they can just sign the message with a different private key, then send you the different public key...
If its possible to convert from publickey -> address then its acceptable, since you can check the key they sent you matches the address you want before validating the signature.
If its possible to go from publickey -> address (I think this is possible) the following workflow is acceptable and no changes are needed to stellard. PersonA wants write a message proven to be authored be owner of addressA. personA signs messageX with privkeyA to create sigA. personA derives pubkeyA from privkeyA. personA sends pubkeyA messageX sigA to personB personB hashes pubkeyA to ensure it matches addressA. if not, signature failed. personB checks messageX sigA using pubkeyA. if passes, message is authentic.
I'm happy with this, and its entirely client side. I'll have to find the code which derives an address from the public key.
@andrewchambers The account ID is a hash of the public key. They embed their public key in the message, sign the whole thing, and hand it to you. You verify the signature with the embedded public key, and then verify that the hash of the public key matches the account ID.
Note that this is largely what you described in your latest comment, except the public key can be embedded in the message directly instead of sent out-of-band. If you look at Stellar transactions, that's exactly how they work (each transaction has a "SigningPubKey" field).
Incidentally, it occurs to me that you can also prove ownership through the Stellar network without having to send a payment at all. You can do it with a trust line instead. The user can issue a TrustSet for a fake currency (e.g. FAK) issued by the gateway address, where the LimitAmount is a value that the gateway told the user. This is similar to a payment in that the "proof" is the usage of a randomly-generated number, except it's not a payment, so it costs the user nothing beyond the basic transaction fee. According to the ripple docs valid currency amounts have a larger range than a 32-bit int (heck, larger than a 64-bit int, though at that point it hardly matters) so it's more secure than destination tags as long as they remain 32-bit. Of course, if destination tags get changed to 64-bit, then it's simpler to just use the destination tag approach with a 1 stroop payment.
Actually, the same docs for the Wire Format indicate that the amount is converted into a 64-bit integer on the wire (constraining the mantissa to 56 bits), so I guess in reality it actually is equivalent to a 64-bit integer, rather than being larger than one.
I'm very happy with the key in sig method then :). Now I just have to push for the official gui client to just have a little ui section for doing it, and a standard format so other clients can interop signatures.
I'm also happy because I can make my own client with this feature in the meantime if I have to.
The fake currency idea is interesting, but the signature method is superior.
Thanks!
Oh sure, I think signing a blob is a better approach, because a) it doesn't cost anything, b) it doesn't show up in the ledger, and c) it's a more secure proof (64-bit random integer is pretty good, but it relies on communicating that number to the user to be secure). The downside is it requires special support from the client (or at least, from a client, but people should not be handing their secret to untrusted clients).
Thats why the official client should support it, even if only in a small submenu or under an advanced tab. So people don't need to use 3rd party clients for basic security.
Its not hard to have a brief explanation of the form. "Any message placed here can be digitally signed, this signature provides proof the message was authored by this account. Do not sign anything you are not sure about."
Then opposite a box saying "paste a signed message into this box" and place the address of the author in the address field. Click verify to prove the address was the author of the message.
Then have a small link "how does this work?" - and link to an article on digital signatures.