Bitcoin ABC 0.34.3
P2P Digital Currency
Loading...
Searching...
No Matches
encrypt.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2021 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
7#include <rpc/server.h>
8#include <rpc/util.h>
9#include <wallet/rpc/util.h>
10#include <wallet/wallet.h>
11
13 return RPCHelpMan{
14 "walletpassphrase",
15 "Stores the wallet decryption key in memory for 'timeout' seconds.\n"
16 "This is needed prior to performing transactions related to private "
17 "keys such as sending bitcoins\n"
18 "\nNote:\n"
19 "Issuing the walletpassphrase command while the wallet is already "
20 "unlocked will set a new unlock\n"
21 "time that overrides the old one.\n",
22 {
24 "The wallet passphrase"},
26 "The time to keep the decryption key in seconds; capped at "
27 "100000000 (~3 years)."},
28 },
31 "\nUnlock the wallet for 60 seconds\n" +
32 HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
33 "\nLock the wallet again (before 60 seconds)\n" +
34 HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
35 HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")},
36 [&](const RPCHelpMan &self, const Config &config,
37 const JSONRPCRequest &request) -> UniValue {
38 std::shared_ptr<CWallet> const wallet =
40 if (!wallet) {
41 return NullUniValue;
42 }
43 CWallet *const pwallet = wallet.get();
44
45 int64_t nSleepTime;
46 int64_t relock_time;
47 // Prevent concurrent calls to walletpassphrase with the same
48 // wallet.
49 LOCK(pwallet->m_unlock_mutex);
50 {
51 LOCK(pwallet->cs_wallet);
52
53 if (!pwallet->IsCrypted()) {
54 throw JSONRPCError(
56 "Error: running with an unencrypted wallet, but "
57 "walletpassphrase was called.");
58 }
59
60 // Note that the walletpassphrase is stored in request.params[0]
61 // which is not mlock()ed
62 SecureString strWalletPass;
63 strWalletPass.reserve(100);
64 // TODO: get rid of this .c_str() by implementing
65 // SecureString::operator=(std::string)
66 // Alternately, find a way to make request.params[0] mlock()'d
67 // to begin with.
68 strWalletPass = request.params[0].get_str().c_str();
69
70 // Get the timeout
71 nSleepTime = request.params[1].getInt<int64_t>();
72 // Timeout cannot be negative, otherwise it will relock
73 // immediately
74 if (nSleepTime < 0) {
76 "Timeout cannot be negative.");
77 }
78 // Clamp timeout
79 // larger values trigger a macos/libevent bug?
80 constexpr int64_t MAX_SLEEP_TIME = 100000000;
81 if (nSleepTime > MAX_SLEEP_TIME) {
82 nSleepTime = MAX_SLEEP_TIME;
83 }
84
85 if (strWalletPass.empty()) {
87 "passphrase can not be empty");
88 }
89
90 if (!pwallet->Unlock(strWalletPass)) {
91 throw JSONRPCError(
93 "Error: The wallet passphrase entered was incorrect.");
94 }
95
96 pwallet->TopUpKeyPool();
97
98 pwallet->nRelockTime = GetTime() + nSleepTime;
99 relock_time = pwallet->nRelockTime;
100 }
101
102 // rpcRunLater must be called without cs_wallet held otherwise a
103 // deadlock can occur. The deadlock would happen when RPCRunLater
104 // removes the previous timer (and waits for the callback to finish
105 // if already running) and the callback locks cs_wallet.
106 AssertLockNotHeld(wallet->cs_wallet);
107 // Keep a weak pointer to the wallet so that it is possible to
108 // unload the wallet before the following callback is called. If a
109 // valid shared pointer is acquired in the callback then the wallet
110 // is still loaded.
111 std::weak_ptr<CWallet> weak_wallet = wallet;
112 pwallet->chain().rpcRunLater(
113 strprintf("lockwallet(%s)", pwallet->GetName()),
114 [weak_wallet, relock_time] {
115 if (auto shared_wallet = weak_wallet.lock()) {
116 LOCK(shared_wallet->cs_wallet);
117 // Skip if this is not the most recent rpcRunLater
118 // callback.
119 if (shared_wallet->nRelockTime != relock_time) {
120 return;
121 }
122 shared_wallet->Lock();
123 shared_wallet->nRelockTime = 0;
124 }
125 },
126 nSleepTime);
127
128 return NullUniValue;
129 },
130 };
131}
132
134 return RPCHelpMan{
135 "walletpassphrasechange",
136 "Changes the wallet passphrase from 'oldpassphrase' to "
137 "'newpassphrase'.\n",
138 {
139 {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
140 "The current passphrase"},
141 {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
142 "The new passphrase"},
143 },
145 RPCExamples{HelpExampleCli("walletpassphrasechange",
146 "\"old one\" \"new one\"") +
147 HelpExampleRpc("walletpassphrasechange",
148 "\"old one\", \"new one\"")},
149 [&](const RPCHelpMan &self, const Config &config,
150 const JSONRPCRequest &request) -> UniValue {
151 std::shared_ptr<CWallet> const wallet =
153 if (!wallet) {
154 return NullUniValue;
155 }
156 CWallet *const pwallet = wallet.get();
157
158 LOCK(pwallet->cs_wallet);
159
160 if (!pwallet->IsCrypted()) {
161 throw JSONRPCError(
163 "Error: running with an unencrypted wallet, but "
164 "walletpassphrasechange was called.");
165 }
166
167 // TODO: get rid of these .c_str() calls by implementing
168 // SecureString::operator=(std::string)
169 // Alternately, find a way to make request.params[0] mlock()'d to
170 // begin with.
171 SecureString strOldWalletPass;
172 strOldWalletPass.reserve(100);
173 strOldWalletPass = request.params[0].get_str().c_str();
174
175 SecureString strNewWalletPass;
176 strNewWalletPass.reserve(100);
177 strNewWalletPass = request.params[1].get_str().c_str();
178
179 if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
181 "passphrase can not be empty");
182 }
183
184 if (!pwallet->ChangeWalletPassphrase(strOldWalletPass,
185 strNewWalletPass)) {
186 throw JSONRPCError(
188 "Error: The wallet passphrase entered was incorrect.");
189 }
190
191 return NullUniValue;
192 },
193 };
194}
195
197 return RPCHelpMan{
198 "walletlock",
199 "Removes the wallet encryption key from memory, locking the wallet.\n"
200 "After calling this method, you will need to call walletpassphrase "
201 "again\n"
202 "before being able to call any methods which require the wallet to be "
203 "unlocked.\n",
204 {},
207 "\nSet the passphrase for 2 minutes to perform a transaction\n" +
208 HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
209 "\nPerform a send (requires passphrase set)\n" +
210 HelpExampleCli("sendtoaddress",
211 "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
212 "\nClear the passphrase since we are done before 2 minutes is "
213 "up\n" +
214 HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
215 HelpExampleRpc("walletlock", "")},
216 [&](const RPCHelpMan &self, const Config &config,
217 const JSONRPCRequest &request) -> UniValue {
218 std::shared_ptr<CWallet> const wallet =
220 if (!wallet) {
221 return NullUniValue;
222 }
223 CWallet *const pwallet = wallet.get();
224
225 LOCK(pwallet->cs_wallet);
226
227 if (!pwallet->IsCrypted()) {
228 throw JSONRPCError(
230 "Error: running with an unencrypted wallet, but "
231 "walletlock was called.");
232 }
233
234 pwallet->Lock();
235 pwallet->nRelockTime = 0;
236
237 return NullUniValue;
238 },
239 };
240}
241
243 return RPCHelpMan{
244 "encryptwallet",
245 "Encrypts the wallet with 'passphrase'. This is for first time "
246 "encryption.\n"
247 "After this, any calls that interact with private keys such as sending "
248 "or signing \n"
249 "will require the passphrase to be set prior the making these calls.\n"
250 "Use the walletpassphrase call for this, and then walletlock call.\n"
251 "If the wallet is already encrypted, use the walletpassphrasechange "
252 "call.\n"
253 "** IMPORTANT **\n"
254 "For security reasons, the encryption process will generate a new HD "
255 "seed, resulting\n"
256 "in the creation of a fresh set of active descriptors. Therefore, "
257 "it is crucial to\n"
258 "securely back up the newly generated wallet file using the "
259 "backupwallet RPC.\n",
260 {
262 "The pass phrase to encrypt the wallet with. It must be at least "
263 "1 character, but should be long."},
264 },
266 "A string with further instructions"},
268 "\nEncrypt your wallet\n" +
269 HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
270 "\nNow set the passphrase to use the wallet, such as for signing "
271 "or sending bitcoin\n" +
272 HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
273 "\nNow we can do something like sign\n" +
274 HelpExampleCli("signmessage", "\"address\" \"test message\"") +
275 "\nNow lock the wallet again by removing the passphrase\n" +
276 HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
277 HelpExampleRpc("encryptwallet", "\"my pass phrase\"")},
278 [&](const RPCHelpMan &self, const Config &config,
279 const JSONRPCRequest &request) -> UniValue {
280 std::shared_ptr<CWallet> const wallet =
282 if (!wallet) {
283 return NullUniValue;
284 }
285 CWallet *const pwallet = wallet.get();
286
287 LOCK(pwallet->cs_wallet);
288
291 "Error: wallet does not contain private "
292 "keys, nothing to encrypt.");
293 }
294
295 if (pwallet->IsCrypted()) {
296 throw JSONRPCError(
298 "Error: running with an encrypted wallet, but "
299 "encryptwallet was called.");
300 }
301
302 // TODO: get rid of this .c_str() by implementing
303 // SecureString::operator=(std::string)
304 // Alternately, find a way to make request.params[0] mlock()'d to
305 // begin with.
306 SecureString strWalletPass;
307 strWalletPass.reserve(100);
308 strWalletPass = request.params[0].get_str().c_str();
309
310 if (strWalletPass.empty()) {
312 "passphrase can not be empty");
313 }
314
315 if (!pwallet->EncryptWallet(strWalletPass)) {
317 "Error: Failed to encrypt the wallet.");
318 }
319
320 return "wallet encrypted; The keypool has been flushed and a new "
321 "HD seed was generated. You need to make a new backup with "
322 "the backupwallet RPC.";
323 },
324 };
325}
326
328 // clang-format off
329 static const CRPCCommand commands[] = {
330 // category actor (function)
331 // ------------------ ----------------------
332 { "wallet", encryptwallet, },
333 { "wallet", walletlock, },
334 { "wallet", walletpassphrase, },
335 { "wallet", walletpassphrasechange, },
336 };
337 // clang-format on
338
339 return commands;
340}
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition wallet.h:270
bool Lock()
Definition wallet.cpp:3292
Mutex m_unlock_mutex
Definition wallet.h:594
RecursiveMutex cs_wallet
Definition wallet.h:416
bool Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys=false)
Definition wallet.cpp:3311
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition wallet.h:475
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
Definition wallet.h:428
bool IsCrypted() const
Definition wallet.cpp:3280
A Span is an object that can refer to a contiguous sequence of objects.
Definition span.h:94
virtual void rpcRunLater(const std::string &name, std::function< void()> fn, int64_t seconds)=0
Run function after given number of seconds.
RPCHelpMan walletpassphrasechange()
Definition encrypt.cpp:133
Span< const CRPCCommand > GetWalletEncryptRPCCommands()
Definition encrypt.cpp:327
RPCHelpMan encryptwallet()
Definition encrypt.cpp:242
RPCHelpMan walletlock()
Definition encrypt.cpp:196
RPCHelpMan walletpassphrase()
Definition encrypt.cpp:12
bool TopUpKeyPool(unsigned int kpSize=0)
Definition wallet.cpp:2410
bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase)
Definition wallet.cpp:515
bool EncryptWallet(const SecureString &strWalletPassphrase)
Definition wallet.cpp:781
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition wallet.cpp:1604
UniValue JSONRPCError(int code, const std::string &message)
Definition request.cpp:58
@ RPC_WALLET_WRONG_ENC_STATE
Command given in wrong wallet encryption state (encrypting an encrypted wallet etc....
Definition protocol.h:103
@ RPC_WALLET_ENCRYPTION_FAILED
Failed to encrypt the wallet.
Definition protocol.h:105
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition protocol.h:46
@ RPC_WALLET_PASSPHRASE_INCORRECT
The wallet passphrase entered was incorrect.
Definition protocol.h:100
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition util.cpp:164
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition util.cpp:181
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition secure.h:55
@ NO
Required arg.
#define AssertLockNotHeld(cs)
Definition sync.h:163
#define LOCK(cs)
Definition sync.h:295
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition time.cpp:80
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
const UniValue NullUniValue
Definition univalue.cpp:16
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition util.cpp:63
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition walletutil.h:55