diff --git a/src/base58.h b/src/base58.h --- a/src/base58.h +++ b/src/base58.h @@ -105,20 +105,8 @@ bool operator>(const CBase58Data &b58) const { return CompareTo(b58) > 0; } }; -/** - * A base58-encoded secret key - */ -class CBitcoinSecret : public CBase58Data { -public: - void SetKey(const CKey &vchSecret); - CKey GetKey(); - bool IsValid() const; - bool SetString(const char *pszSecret); - bool SetString(const std::string &strSecret); - - CBitcoinSecret(const CKey &vchSecret) { SetKey(vchSecret); } - CBitcoinSecret() {} -}; +CKey DecodeSecret(const std::string &str); +std::string EncodeSecret(const CKey &key); template class CBitcoinExtKeyBase : public CBase58Data { diff --git a/src/base58.cpp b/src/base58.cpp --- a/src/base58.cpp +++ b/src/base58.cpp @@ -262,37 +262,38 @@ } } // namespace -void CBitcoinSecret::SetKey(const CKey &vchSecret) { - assert(vchSecret.IsValid()); - SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), - vchSecret.size()); - if (vchSecret.IsCompressed()) vchData.push_back(1); +CKey DecodeSecret(const std::string &str) { + CKey key; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector &privkey_prefix = + Params().Base58Prefix(CChainParams::SECRET_KEY); + if ((data.size() == 32 + privkey_prefix.size() || + (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) && + std::equal(privkey_prefix.begin(), privkey_prefix.end(), + data.begin())) { + bool compressed = data.size() == 33 + privkey_prefix.size(); + key.Set(data.begin() + privkey_prefix.size(), + data.begin() + privkey_prefix.size() + 32, compressed); + } + } + memory_cleanse(data.data(), data.size()); + return key; } -CKey CBitcoinSecret::GetKey() { - CKey ret; - assert(vchData.size() >= 32); - ret.Set(vchData.begin(), vchData.begin() + 32, - vchData.size() > 32 && vchData[32] == 1); +std::string EncodeSecret(const CKey &key) { + assert(key.IsValid()); + std::vector data = + Params().Base58Prefix(CChainParams::SECRET_KEY); + data.insert(data.end(), key.begin(), key.end()); + if (key.IsCompressed()) { + data.push_back(1); + } + std::string ret = EncodeBase58Check(data); + memory_cleanse(data.data(), data.size()); return ret; } -bool CBitcoinSecret::IsValid() const { - bool fExpectedFormat = - vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); - bool fCorrectVersion = - vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); - return fExpectedFormat && fCorrectVersion; -} - -bool CBitcoinSecret::SetString(const char *pszSecret) { - return CBase58Data::SetString(pszSecret) && IsValid(); -} - -bool CBitcoinSecret::SetString(const std::string &strSecret) { - return SetString(strSecret.c_str()); -} - std::string EncodeLegacyAddr(const CTxDestination &dest, const CChainParams ¶ms) { return boost::apply_visitor(DestinationEncoder(params), dest); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -573,13 +573,10 @@ throw std::runtime_error("privatekey not a std::string"); } - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(keysObj[kidx].getValStr()); - if (!fGood) { + CKey key = DecodeSecret(keysObj[kidx].getValStr()); + if (!key.IsValid()) { throw std::runtime_error("privatekey not valid"); } - - CKey key = vchSecret.GetKey(); tempKeystore.AddKey(key); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -295,15 +295,9 @@ std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strPrivkey); - if (!fGood) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - } - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(strPrivkey); if (!key.IsValid()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Private key outside allowed range"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); } CHashWriter ss(SER_GETHASH, 0); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1121,15 +1121,10 @@ const UniValue &keys = request.params[1].get_array(); for (size_t idx = 0; idx < keys.size(); ++idx) { UniValue k = keys[idx]; - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(k.get_str())) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Invalid private key"); - } - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(k.get_str()); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Private key outside allowed range"); + "Invalid private key"); } keystore.AddKey(key); } diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -86,7 +86,7 @@ UniValue tests = read_json(std::string( json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); - CBitcoinSecret secret; + CKey privkey; CTxDestination destination; SelectParams(CBaseChainParams::MAIN); @@ -106,10 +106,8 @@ if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key - BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), - "!SetString:" + strTest); - BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); - CKey privkey = secret.GetKey(); + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && @@ -130,8 +128,8 @@ BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload)); // Public key must be invalid private key - secret.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!secret.IsValid(), + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest); } } @@ -161,9 +159,7 @@ CKey key; key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); assert(key.IsValid()); - CBitcoinSecret secret; - secret.SetKey(key); - BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, + BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest); } else { CTxDestination dest; @@ -185,7 +181,7 @@ read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); - CBitcoinSecret secret; + CKey privkey; CTxDestination destination; for (unsigned int idx = 0; idx < tests.size(); idx++) { @@ -205,8 +201,8 @@ destination = DecodeLegacyAddr(exp_base58string, Params()); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); - secret.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!secret.IsValid(), + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest); } } diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -109,10 +109,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); - CBitcoinSecret vchSecret; - BOOST_CHECK(vchSecret.SetString(strSecret)); - - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(strSecret); CPubKey pubkey = key.GetPubKey(); std::vector vchPubKey(pubkey.begin(), pubkey.end()); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -83,21 +83,16 @@ } BOOST_AUTO_TEST_CASE(key_test1) { - CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; - BOOST_CHECK(bsecret1.SetString(strSecret1)); - BOOST_CHECK(bsecret2.SetString(strSecret2)); - BOOST_CHECK(bsecret1C.SetString(strSecret1C)); - BOOST_CHECK(bsecret2C.SetString(strSecret2C)); - BOOST_CHECK(!baddress1.SetString(strAddressBad)); - - CKey key1 = bsecret1.GetKey(); - BOOST_CHECK(key1.IsCompressed() == false); - CKey key2 = bsecret2.GetKey(); - BOOST_CHECK(key2.IsCompressed() == false); - CKey key1C = bsecret1C.GetKey(); - BOOST_CHECK(key1C.IsCompressed() == true); - CKey key2C = bsecret2C.GetKey(); - BOOST_CHECK(key2C.IsCompressed() == true); + CKey key1 = DecodeSecret(strSecret1); + BOOST_CHECK(key1.IsValid() && !key1.IsCompressed()); + CKey key2 = DecodeSecret(strSecret2); + BOOST_CHECK(key2.IsValid() && !key2.IsCompressed()); + CKey key1C = DecodeSecret(strSecret1C); + BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed()); + CKey key2C = DecodeSecret(strSecret2C); + BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed()); + CKey bad_key = DecodeSecret(strAddressBad); + BOOST_CHECK(!bad_key.IsValid()); CPubKey pubkey1 = key1.GetPubKey(); CPubKey pubkey2 = key2.GetPubKey(); diff --git a/src/test/sigcache_tests.cpp b/src/test/sigcache_tests.cpp --- a/src/test/sigcache_tests.cpp +++ b/src/test/sigcache_tests.cpp @@ -68,13 +68,9 @@ TestCachingTransactionSignatureChecker testChecker(checker); - CBitcoinSecret bsecret1, bsecret1C; - BOOST_CHECK(bsecret1.SetString(strSecret1)); - BOOST_CHECK(bsecret1C.SetString(strSecret1C)); - - CKey key1 = bsecret1.GetKey(); + CKey key1 = DecodeSecret(strSecret1); BOOST_CHECK(key1.IsCompressed() == false); - CKey key1C = bsecret1C.GetKey(); + CKey key1C = DecodeSecret(strSecret1C); BOOST_CHECK(key1C.IsCompressed() == true); CPubKey pubkey1 = key1.GetPubKey(); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -132,18 +132,10 @@ "rescan or wait."); } - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - if (!fGood) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Invalid private key encoding"); - } - - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(strSecret); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Private key outside allowed range"); + "Invalid private key encoding"); } CPubKey pubkey = key.GetPubKey(); @@ -631,9 +623,8 @@ if (vstr.size() < 2) { continue; } - CBitcoinSecret vchSecret; - if (vchSecret.SetString(vstr[0])) { - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(vstr[0]); + if (key.IsValid()) { CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); @@ -752,7 +743,7 @@ throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); } - return CBitcoinSecret(vchSecret).ToString(); + return EncodeSecret(vchSecret); } UniValue dumpwallet(const Config &config, const JSONRPCRequest &request) { @@ -863,8 +854,7 @@ std::string strAddr = EncodeDestination(keyid, config); CKey key; if (pwallet->GetKey(keyid, key)) { - file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), - strTime); + file << strprintf("%s %s ", EncodeSecret(key), strTime); if (pwallet->mapAddressBook.count(keyid)) { file << strprintf( "label=%s", @@ -1054,19 +1044,11 @@ for (size_t i = 0; i < keys.size(); i++) { const std::string &privkey = keys[i].get_str(); - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(privkey); - - if (!fGood) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Invalid private key encoding"); - } - - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(privkey); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Private key outside allowed range"); + "Invalid private key encoding"); } CPubKey pubkey = key.GetPubKey(); @@ -1177,18 +1159,11 @@ const std::string &strPrivkey = keys[0].get_str(); // Checks. - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strPrivkey); - - if (!fGood) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Invalid private key encoding"); - } + CKey key = DecodeSecret(strPrivkey); - CKey key = vchSecret.GetKey(); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Private key outside allowed range"); + "Invalid private key encoding"); } CPubKey pubKey = key.GetPubKey();