From 4e67a6216bf3633320950117aba3566cbfd5ffda Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 25 Jul 2011 15:13:55 -0700 Subject: Faster Base64 decoder. --- src/bitcoinrpc.cpp | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 5a1fab6943..db2e610fad 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1830,24 +1830,6 @@ string EncodeBase64(string s) return result; } -string DecodeBase64(string s) -{ - BIO *b64, *bmem; - - char* buffer = static_cast(calloc(s.size(), sizeof(char))); - - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new_mem_buf(const_cast(s.c_str()), s.size()); - bmem = BIO_push(b64, bmem); - BIO_read(bmem, buffer, s.size()); - BIO_free_all(bmem); - - string result(buffer); - free(buffer); - return result; -} - bool HTTPAuthorized(map& mapHeaders) { string strAuth = mapHeaders["authorization"]; -- cgit v1.2.3 From 4b603f1cd6a0b8480c15555389077a4b401c2c7b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 20 Sep 2011 15:38:29 +0200 Subject: Inline base64 encoder/decoder This replaces the openssl-based base64 encoder and decoder with a more efficient internal one. Tested against the rfc4648 test vectors. Decoder is based on JoelKatz' version. --- src/bitcoinrpc.cpp | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index db2e610fad..23d97db89b 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -1811,25 +1811,6 @@ int ReadHTTP(std::basic_istream& stream, map& mapHeadersRe return nStatus; } -string EncodeBase64(string s) -{ - BIO *b64, *bmem; - BUF_MEM *bptr; - - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new(BIO_s_mem()); - b64 = BIO_push(b64, bmem); - BIO_write(b64, s.c_str(), s.size()); - BIO_flush(b64); - BIO_get_mem_ptr(b64, &bptr); - - string result(bptr->data, bptr->length); - BIO_free_all(b64); - - return result; -} - bool HTTPAuthorized(map& mapHeaders) { string strAuth = mapHeaders["authorization"]; -- cgit v1.2.3 From cc2567e32fb62df84f40d3f28f2ee48ab1009775 Mon Sep 17 00:00:00 2001 From: Khalahan Date: Sun, 24 Apr 2011 14:27:52 +0200 Subject: Sign and verify message with bitcoin address and public key Add padding to input (fixed string + address) before hashing --- src/bitcoinrpc.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 23d97db89b..1b2a5b5f7e 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -526,6 +526,70 @@ Value sendtoaddress(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } +Value signmessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "signmessage \n" + "Sign a message with the private key of an address"); + + string strAddress = params[0].get_str(); + string strMessage = params[1].get_str(); + strMessage.insert(0, "Padding text - "); + + uint160 hash160; + if(!AddressToHash160(strAddress, hash160)) + throw JSONRPCError(-3, "Invalid address"); + + vector& vchPubKey = mapPubKeys[hash160]; + CKey key; + if(!key.SetPubKey(vchPubKey)) + throw JSONRPCError(-3, "Public key not found"); + strMessage.insert(0, HexStr(vchPubKey.begin(), vchPubKey.end()).c_str()); + + vector vchMsg(strMessage.begin(), strMessage.end()); + vector vchSig; + if (!CKey::Sign(mapKeys[vchPubKey], Hash(vchMsg.begin(), vchMsg.end()), vchSig)) + throw JSONRPCError(-3, "Sign failed"); + + Object obj; + obj.push_back(Pair("address", strAddress)); + obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()).c_str())); + obj.push_back(Pair("sign", HexStr(vchSig.begin(), vchSig.end()).c_str())); + + return obj; +} + +Value verifymessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "verifymessage \n" + "Verify a signed message with the public key"); + + string strPubKey = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); + strMessage.insert(0, "Padding text - "); + strMessage.insert(0, strPubKey.c_str()); + + vector vchPubKey = ParseHex(strPubKey); + vector vchSig = ParseHex(strSign); + vector vchMsg(strMessage.begin(), strMessage.end()); + + CKey key; + if(!key.SetPubKey(vchPubKey)) + throw JSONRPCError(-3, "Invalid pubkey"); + + if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) + throw JSONRPCError(-3, "Verify failed"); + + Object obj; + obj.push_back(Pair("address", PubKeyToAddress(vchPubKey))); + obj.push_back(Pair("pubkey", strPubKey.c_str())); + return obj; +} + Value getreceivedbyaddress(const Array& params, bool fHelp) { @@ -1636,6 +1700,8 @@ pair pCallTable[] = make_pair("sendmany", &sendmany), make_pair("gettransaction", &gettransaction), make_pair("listtransactions", &listtransactions), + make_pair("signmessage", &signmessage), + make_pair("verifymessage", &verifymessage), make_pair("getwork", &getwork), make_pair("listaccounts", &listaccounts), make_pair("settxfee", &settxfee), -- cgit v1.2.3 From b53d6284eb5b2833ed1bde46dbce5b5a4284804a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 19 Sep 2011 20:03:03 +0200 Subject: Incorporate pubkey in signature, check based on address Include the public key in the signature string, to allow verification based on address. --- src/bitcoinrpc.cpp | 86 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 37 deletions(-) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 1b2a5b5f7e..3638adac38 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -526,6 +526,8 @@ Value sendtoaddress(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } +static const string strMessageMagic = "Bitcoin Signed Message:\n"; + Value signmessage(const Array& params, bool fHelp) { if (fHelp || params.size() != 2) @@ -533,61 +535,71 @@ Value signmessage(const Array& params, bool fHelp) "signmessage \n" "Sign a message with the private key of an address"); + if (pwalletMain->IsLocked()) + throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); + string strAddress = params[0].get_str(); string strMessage = params[1].get_str(); - strMessage.insert(0, "Padding text - "); - - uint160 hash160; - if(!AddressToHash160(strAddress, hash160)) + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) throw JSONRPCError(-3, "Invalid address"); - - vector& vchPubKey = mapPubKeys[hash160]; + CKey key; - if(!key.SetPubKey(vchPubKey)) - throw JSONRPCError(-3, "Public key not found"); - strMessage.insert(0, HexStr(vchPubKey.begin(), vchPubKey.end()).c_str()); + if (!pwalletMain->GetKey(addr, key)) + throw JSONRPCError(-4, "Private key not available"); + + CDataStream ss(SER_GETHASH); + ss << strMessageMagic; + ss << strMessage; - vector vchMsg(strMessage.begin(), strMessage.end()); vector vchSig; - if (!CKey::Sign(mapKeys[vchPubKey], Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - throw JSONRPCError(-3, "Sign failed"); + if (!key.Sign(Hash(ss.begin(), ss.end()), vchSig)) + throw JSONRPCError(-5, "Sign failed"); - Object obj; - obj.push_back(Pair("address", strAddress)); - obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()).c_str())); - obj.push_back(Pair("sign", HexStr(vchSig.begin(), vchSig.end()).c_str())); + CDataStream sres(SER_NETWORK); + sres << key.GetPubKey(); // public key + sres << vchSig; // signature; - return obj; + return HexStr(sres.begin(), sres.end()); } Value verifymessage(const Array& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( - "verifymessage \n" - "Verify a signed message with the public key"); + "verifymessage \n" + "Verify a signed message"); - string strPubKey = params[0].get_str(); - string strSign = params[1].get_str(); - string strMessage = params[2].get_str(); - strMessage.insert(0, "Padding text - "); - strMessage.insert(0, strPubKey.c_str()); + string strAddress = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); - vector vchPubKey = ParseHex(strPubKey); - vector vchSig = ParseHex(strSign); - vector vchMsg(strMessage.begin(), strMessage.end()); + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(-3, "Invalid address"); + + vector vchResult = ParseHex(strSign); + CDataStream sres(vchResult); + + std::vector vchPubKey; + sres >> vchPubKey; + std::vector vchSig; + sres >> vchSig; CKey key; - if(!key.SetPubKey(vchPubKey)) - throw JSONRPCError(-3, "Invalid pubkey"); - - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - throw JSONRPCError(-3, "Verify failed"); - - Object obj; - obj.push_back(Pair("address", PubKeyToAddress(vchPubKey))); - obj.push_back(Pair("pubkey", strPubKey.c_str())); - return obj; + if (!key.SetPubKey(vchPubKey)) + throw JSONRPCError(-5, "Invalid public key in signature"); + + if (key.GetAddress() == addr) + { + CDataStream ss(SER_GETHASH); + ss << strMessageMagic; + ss << strMessage; + return key.Verify(Hash(ss.begin(), ss.end()), vchSig); + } + else + return false; } -- cgit v1.2.3 From d9867551fc58ebb62eddef3dfbdb1dc711110577 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 20 Sep 2011 15:42:36 +0200 Subject: base64-based sign/verify --- src/bitcoinrpc.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 3638adac38..c8a0076bfa 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -561,7 +561,8 @@ Value signmessage(const Array& params, bool fHelp) sres << key.GetPubKey(); // public key sres << vchSig; // signature; - return HexStr(sres.begin(), sres.end()); + vector vchRet(sres.begin(), sres.end()); + return EncodeBase64(&vchRet[0], vchRet.size()); } Value verifymessage(const Array& params, bool fHelp) @@ -579,7 +580,12 @@ Value verifymessage(const Array& params, bool fHelp) if (!addr.IsValid()) throw JSONRPCError(-3, "Invalid address"); - vector vchResult = ParseHex(strSign); + bool fInvalid = false; + vector vchResult = DecodeBase64(strSign.c_str(), &fInvalid); + + if (fInvalid) + throw JSONRPCError(-5, "Malformed base64 encoding"); + CDataStream sres(vchResult); std::vector vchPubKey; -- cgit v1.2.3 From 3a570dc80a7391b7f3943cb83849055318e0217a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 21 Sep 2011 17:03:28 +0200 Subject: Use key recovery for message signatures Instead of encoding the public key inside the signature string, use key recovery to do verification. This allows 88-character base64-encoded signature strings instead of 188-character ones. --- src/bitcoinrpc.cpp | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) (limited to 'src/bitcoinrpc.cpp') diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index c8a0076bfa..8468e56105 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -554,15 +554,10 @@ Value signmessage(const Array& params, bool fHelp) ss << strMessage; vector vchSig; - if (!key.Sign(Hash(ss.begin(), ss.end()), vchSig)) + if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) throw JSONRPCError(-5, "Sign failed"); - CDataStream sres(SER_NETWORK); - sres << key.GetPubKey(); // public key - sres << vchSig; // signature; - - vector vchRet(sres.begin(), sres.end()); - return EncodeBase64(&vchRet[0], vchRet.size()); + return EncodeBase64(&vchSig[0], vchSig.size()); } Value verifymessage(const Array& params, bool fHelp) @@ -581,31 +576,20 @@ Value verifymessage(const Array& params, bool fHelp) throw JSONRPCError(-3, "Invalid address"); bool fInvalid = false; - vector vchResult = DecodeBase64(strSign.c_str(), &fInvalid); + vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); if (fInvalid) throw JSONRPCError(-5, "Malformed base64 encoding"); - CDataStream sres(vchResult); - - std::vector vchPubKey; - sres >> vchPubKey; - std::vector vchSig; - sres >> vchSig; + CDataStream ss(SER_GETHASH); + ss << strMessageMagic; + ss << strMessage; CKey key; - if (!key.SetPubKey(vchPubKey)) - throw JSONRPCError(-5, "Invalid public key in signature"); - - if (key.GetAddress() == addr) - { - CDataStream ss(SER_GETHASH); - ss << strMessageMagic; - ss << strMessage; - return key.Verify(Hash(ss.begin(), ss.end()), vchSig); - } - else + if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) return false; + + return (key.GetAddress() == addr); } -- cgit v1.2.3