diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index fabbe4379b..deec70bf10 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2705,6 +2705,8 @@ True + + True @@ -2743,6 +2745,11 @@ + + True + + + True @@ -2814,6 +2821,9 @@ True + + True + True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 5641b4aed3..9f89b82bda 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -3762,6 +3762,9 @@ ripple\rpc\handlers + + ripple\rpc\handlers + ripple\rpc\handlers @@ -3807,6 +3810,12 @@ ripple\rpc\impl + + ripple\rpc\impl + + + ripple\rpc\impl + ripple\rpc\impl @@ -3891,6 +3900,9 @@ ripple\rpc\tests + + ripple\rpc\tests + ripple\rpc\tests diff --git a/src/ripple/rpc/handlers/WalletPropose.cpp b/src/ripple/rpc/handlers/WalletPropose.cpp index a60063c574..586e0797d2 100644 --- a/src/ripple/rpc/handlers/WalletPropose.cpp +++ b/src/ripple/rpc/handlers/WalletPropose.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include namespace ripple { @@ -25,14 +26,19 @@ namespace ripple { // passphrase: // } Json::Value doWalletPropose (RPC::Context& context) +{ + return walletPropose (context.params); +} + +Json::Value walletPropose (Json::Value const& params) { RippleAddress naSeed; RippleAddress naAccount; - if (!context.params.isMember ("passphrase")) + if (!params.isMember ("passphrase")) naSeed.setSeedRandom (); - else if (!naSeed.setSeedGeneric (context.params["passphrase"].asString ())) + else if (!naSeed.setSeedGeneric (params["passphrase"].asString ())) return rpcError(rpcBAD_SEED); RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); diff --git a/src/ripple/rpc/handlers/WalletPropose.h b/src/ripple/rpc/handlers/WalletPropose.h new file mode 100644 index 0000000000..b53042cb33 --- /dev/null +++ b/src/ripple/rpc/handlers/WalletPropose.h @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H +#define RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H + +#include + +namespace ripple { + +Json::Value walletPropose (Json::Value const& params); + +} // ripple + +#endif diff --git a/src/ripple/rpc/impl/KeypairForSignature.cpp b/src/ripple/rpc/impl/KeypairForSignature.cpp new file mode 100644 index 0000000000..16b9cd714f --- /dev/null +++ b/src/ripple/rpc/impl/KeypairForSignature.cpp @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include + +namespace ripple { +namespace RPC { + +KeyPair keypairForSignature (Json::Value const& params, Json::Value& error) +{ + if (! params.isMember ("secret")) + { + error = RPC::missing_field_error ("secret"); + + return KeyPair(); + } + + RippleAddress seed; + + if (! seed.setSeedGeneric (params["secret"].asString ())) + { + error = RPC::make_error (rpcBAD_SEED, + RPC::invalid_field_message ("secret")); + + return KeyPair(); + } + + KeyPair result; + + RippleAddress generator = RippleAddress::createGeneratorPublic (seed); + result.secretKey.setAccountPrivate (generator, seed, 0); + result.publicKey.setAccountPublic (generator, 0); + + return result; +} + +} // RPC +} // ripple diff --git a/src/ripple/rpc/impl/KeypairForSignature.h b/src/ripple/rpc/impl/KeypairForSignature.h new file mode 100644 index 0000000000..66e84c82f4 --- /dev/null +++ b/src/ripple/rpc/impl/KeypairForSignature.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_RPC_SIGNATUREKEYPAIR_H_INCLUDED +#define RIPPLE_RPC_SIGNATUREKEYPAIR_H_INCLUDED + +#include +#include + +namespace ripple { +namespace RPC { + +struct KeyPair +{ + RippleAddress secretKey; + RippleAddress publicKey; +}; + +KeyPair keypairForSignature (Json::Value const& params, Json::Value& error); + +} // RPC +} // ripple + +#endif diff --git a/src/ripple/rpc/impl/TransactionSign.cpp b/src/ripple/rpc/impl/TransactionSign.cpp index 6144d9863b..e6a1a5480c 100644 --- a/src/ripple/rpc/impl/TransactionSign.cpp +++ b/src/ripple/rpc/impl/TransactionSign.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -335,18 +336,16 @@ transactionSign ( WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params; - if (! params.isMember ("secret")) - return RPC::missing_field_error ("secret"); + KeyPair const keypair = keypairForSignature (params, jvResult); + + if (contains_error (jvResult)) + { + return jvResult; + } if (! params.isMember ("tx_json")) return RPC::missing_field_error ("tx_json"); - RippleAddress naSeed; - - if (! naSeed.setSeedGeneric (params["secret"].asString ())) - return RPC::make_error (rpcBAD_SEED, - RPC::invalid_field_message ("secret")); - Json::Value& tx_json (params ["tx_json"]); if (! tx_json.isObject ()) @@ -426,20 +425,13 @@ transactionSign ( return rpcError (rpcSRC_ACT_NOT_FOUND); } - RippleAddress secret = RippleAddress::createSeedGeneric ( - params["secret"].asString ()); - RippleAddress masterGenerator = RippleAddress::createGeneratorPublic ( - secret); - RippleAddress masterAccountPublic = RippleAddress::createAccountPublic ( - masterGenerator, 0); - if (verify) { WriteLog (lsTRACE, RPCHandler) << - "verify: " << masterAccountPublic.humanAccountID () << + "verify: " << keypair.publicKey.humanAccountID() << " : " << raSrcAddressID.humanAccountID (); - auto const secretAccountID = masterAccountPublic.getAccountID(); + auto const secretAccountID = keypair.publicKey.getAccountID(); if (raSrcAddressID.getAccountID () == secretAccountID) { if (ledgerFacade.accountMasterDisabled ()) @@ -462,7 +454,7 @@ transactionSign ( std::unique_ptr sopTrans = std::move(parsed.object); sopTrans->setFieldVL ( sfSigningPubKey, - masterAccountPublic.getAccountPublic ()); + keypair.publicKey.getAccountPublic()); STTx::pointer stpTrans; @@ -489,10 +481,8 @@ transactionSign ( // FIXME: For performance, transactions should not be signed in this code // path. - RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate ( - masterGenerator, secret, 0); - stpTrans->sign (naAccountPrivate); + stpTrans->sign (keypair.secretKey); Transaction::pointer tpTrans; diff --git a/src/ripple/rpc/tests/KeyGeneration.test.cpp b/src/ripple/rpc/tests/KeyGeneration.test.cpp new file mode 100644 index 0000000000..81e7d15891 --- /dev/null +++ b/src/ripple/rpc/tests/KeyGeneration.test.cpp @@ -0,0 +1,178 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2015 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include + +namespace ripple { + +namespace RPC { + +struct key_strings +{ + char const* account_id; + char const* master_key; + char const* master_seed; + char const* master_seed_hex; + char const* public_key; + char const* public_key_hex; + char const* secret_key_hex; +}; + +namespace common { +static char const* passphrase = "REINDEER FLOTILLA"; +static char const* master_key = "SCAT BERN ISLE FOR ROIL BUS SOAK AQUA FREE FOR DRAM BRIG"; +static char const* master_seed = "snMwVWs2hZzfDUF3p2tHZ3EgmyhFs"; +static char const* master_seed_hex = "BE6A670A19B209E112146D0A7ED2AAD7"; +} + +static key_strings const secp256k1_strings = +{ + "r4Vtj2jrfmTVZGfSP3gH9hQPMqFPQFin8f", + common::master_key, + common::master_seed, + common::master_seed_hex, + "aBQxK2YFNqzmAaXNczYcjqDjfiKkLsJUizsr1UBf44RCF8FHdrmX", + "038AAE247B2344B1837FBED8F57389C8C11774510A3F7D784F2A09F0CB6843236C", + "1949ECD889EA71324BC7A30C8E81F4E93CB73EE19D59E9082111E78CC3DDABC2", +}; + +class WalletPropose_test : public ripple::TestSuite +{ +public: + void testRandomWallet() + { + Json::Value params; + Json::Value result = walletPropose (params); + + expect (! contains_error (result)); + expect (result.isMember ("account_id")); + expect (result.isMember ("master_key")); + expect (result.isMember ("master_seed")); + expect (result.isMember ("master_seed_hex")); + expect (result.isMember ("public_key")); + expect (result.isMember ("public_key_hex")); + + std::string seed = result["master_seed"].asString(); + + result = walletPropose (params); + + // We asked for two random seeds, so they shouldn't match. + expect (result["master_seed"].asString() != seed, seed); + } + + void testSecretWallet (Json::Value const& params, key_strings const& s) + { + Json::Value result = walletPropose (params); + + expect (! contains_error (result)); + expectEquals (result["account_id"], s.account_id); + expectEquals (result["master_key"], s.master_key); + expectEquals (result["master_seed"], s.master_seed); + expectEquals (result["master_seed_hex"], s.master_seed_hex); + expectEquals (result["public_key"], s.public_key); + expectEquals (result["public_key_hex"], s.public_key_hex); + } + + void testLegacyPassphrase (char const* value) + { + testcase (value); + + Json::Value params; + params["passphrase"] = value; + + testSecretWallet (params, secp256k1_strings); + } + + void testLegacyPassphrase() + { + testLegacyPassphrase (common::passphrase); + testLegacyPassphrase (secp256k1_strings.master_key); + testLegacyPassphrase (secp256k1_strings.master_seed); + testLegacyPassphrase (secp256k1_strings.master_seed_hex); + } + + void run() + { + testRandomWallet(); + testLegacyPassphrase(); + } +}; + +class KeypairForSignature_test : public ripple::TestSuite +{ +public: + void testEmpty() + { + Json::Value params; + Json::Value error; + + (void) keypairForSignature (params, error); + + expect (contains_error (error) ); + } + + void testSecretWallet (Json::Value const& params, key_strings const& s) + { + Json::Value error; + KeyPair keypair = keypairForSignature (params, error); + + uint256 secret_key = keypair.secretKey.getAccountPrivate(); + Blob public_key = keypair.publicKey.getAccountPublic(); + + std::string secret_key_hex = strHex (secret_key.data(), secret_key.size()); + std::string public_key_hex = strHex (public_key.data(), public_key.size()); + + expectEquals (secret_key_hex, s.secret_key_hex); + expectEquals (public_key_hex, s.public_key_hex); + } + + void testLegacySecret (char const* value) + { + testcase (value); + + Json::Value params; + params["secret"] = value; + + testSecretWallet (params, secp256k1_strings); + } + + void testLegacySecret() + { + testLegacySecret (common::passphrase); + testLegacySecret (secp256k1_strings.master_key); + testLegacySecret (secp256k1_strings.master_seed); + testLegacySecret (secp256k1_strings.master_seed_hex); + } + + void run() + { + testEmpty(); + testLegacySecret(); + } +}; + +BEAST_DEFINE_TESTSUITE(WalletPropose,ripple_basics,ripple); +BEAST_DEFINE_TESTSUITE(KeypairForSignature,ripple_basics,ripple); + +} // RPC +} // ripple diff --git a/src/ripple/unity/rpcx.cpp b/src/ripple/unity/rpcx.cpp index 027cbd6746..f2bb86abc7 100644 --- a/src/ripple/unity/rpcx.cpp +++ b/src/ripple/unity/rpcx.cpp @@ -99,6 +99,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,7 @@ #include #include #include +#include #include #include #include