-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Wallet Private Key Encryption (on CWallet) #352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Forum thread: http://forum.bitcoin.org/index.php?topic=8728.0 |
Changed topupkeypool to keypoolrefill at tcatm's suggestion |
A note for users of the previous version - Ill write a converter tomorrow that will try to convert the old encrypted wallets to this new format. |
TODO List: |
Looks OK, I like the feature set, I haven't had a chance to compile and test it. |
Looks OK at first glance. Will give it an in-depth look and test RSN. One nit: mlock() can definitely fail based variable conditions such as ulimit. The code never checks for mlock failure, and seems to assume you may munlock even if mlock failed. |
If it fails, it should continue, yes we are potentially not as secure, but we should stop just because we cant mlock(). |
I spent a couple days beating the hell out of this implementation and Matt has quickly fixed all the bugs I've encountered. In particular I've now sent thousands of transactions and thousands of getaddresses in an abusive testing rig which is constantly unlocking/locking/password changing/account moving, etc. and not lost any coin. I've basically run out of obvious automated testing at this point. I am, however, unable to do GUI testing, so I hope and assume other people are beating on that. To the best of my ability to determine this is now ready for mainline and testing by a broader audience. I think that before release the wallettools probably need to be updated to support this: both as an additional validation of the implementation, but also so that there isn't a gap in recovery tools, but I don't see any reason that should block mainlining it. |
Just tried to build 499334e on win32 using mingw, works fine, except a couple of things.
|
Just figured out if you're trying to read encrypted wallet with official client (0.3.24rc1 in my case) wallet gets destroyed and not readable by anything. It's not very nice. |
If you try to read it with the old client, the client won't (shouldn't) touch it and just complain that it is "Unable to read wallet.dat". However, if you reopen it with this client, it should open fine. |
Well, not really. Official 0.3.23 says basically the same as 0.3.24rc1: EXCEPTION: St13runtime_error ReserveKeyFromKeyPool() : unknown key in key pool (...)bitcoin.exe in AppInit(), EXCEPTION: St13runtime_error ReserveKeyFromKeyPool() : unknown key in key pool (...)bitcoin.exe in CMyApp::OnUnhandledException(), Runtime error! After that wallet.dat becomes completely inaccesible, 499334e says "Error loading wallet.dat". If someone is interested I've tried that only on a new wallet (with no transactions). |
Ah, shit you are totally right, and here I was thinking the client was smarter than that...Ill make sure a fix goes into 0.3.24 so at least people can downgrade to that safely. |
See #378 |
would it be possible to encrypt the wallet with a null/default pass-phrase by default rather than leaving the wallet unencrypted? |
null/default passphrase is 100% identical to no encryption, if an attacker gets the wallet, they can still just dump it in their .bitcoin folder and send coins, its better to be backward compatible if users dont encrypt than just break that too for nothing. |
Inline comment and idea come from the encprivkeys branch by Matt Corallo <matt@bluematt.me>.
I am not sure the mlock() wrappers are correct. ((void *)(((size_t)(a)) & ((size_t)(((PAGESIZE)<<1)-1)))) seems to throw away the high bits of the address, instead of the low ones. I suggest using:
Here is a test program:
|
Apart from the above comment: ACK. |
…ss to be on a page boundary.
re gavin's comment |
This commit adds support for ckeys, or enCrypted private keys, to the wallet. All keys are stored in memory in their encrypted form and thus the passphrase is required from the user to spend coins, or to create new addresses. Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and a random salt. By default, the user's wallet remains unencrypted until they call the RPC command encryptwallet <passphrase> or, from the GUI menu, Options-> Encrypt Wallet. When the user is attempting to call RPC functions which require the password to unlock the wallet, an error will be returned unless they call walletpassphrase <passphrase> <time to keep key in memory> first. A keypoolrefill command has been added which tops up the users keypool (requiring the passphrase via walletpassphrase first). keypoolsize has been added to the output of getinfo to show the user the number of keys left before they need to specify their passphrase (and call keypoolrefill). Note that walletpassphrase will automatically fill keypool in a separate thread which it spawns when the passphrase is set. This could cause some delays in other threads waiting for locks on the wallet passphrase, including one which could cause the passphrase to be stored longer than expected, however it will not allow the passphrase to be used longer than expected as ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon as the specified lock time has arrived. When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool returns vchDefaultKey, meaning miners may start to generate many blocks to vchDefaultKey instead of a new key each time. A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to allow the user to change their password via RPC. Whenever keying material (unencrypted private keys, the user's passphrase, the wallet's AES key) is stored unencrypted in memory, any reasonable attempt is made to mlock/VirtualLock that memory before storing the keying material. This is not true in several (commented) cases where mlock/VirtualLocking the memory is not possible. Although encryption of private keys in memory can be very useful on desktop systems (as some small amount of protection against stupid viruses), on an RPC server, the password is entered fairly insecurely. Thus, the only main advantage encryption has for RPC servers is for RPC servers that do not spend coins, except in rare cases, eg. a webserver of a merchant which only receives payment except for cases of manual intervention. Thanks to jgarzik for the original patch and sipa, gmaxwell and many others for all their input. Conflicts: src/wallet.cpp
This speeds up the encryption process significantly.
This prevents old clients from opening, and thus corrupting or otherwise causing harm to encrypted wallets.
ACK, looks ready-for-prime-time to me. |
Wallet Private Key Encryption (on CWallet)
Unit tests? |
Handle a special case for Parallel Validation
Chinese translation
Why the unencrypted master key is stored in memory? Why not unencrypted private key? |
c8fbc3c [ECDH API change] Allow pass arbitrary data to hash function (Kirill Fomichev) b00be65 [ECDH API change] Support custom hash function (Kirill Fomichev) Pull request description: Solve bitcoin#352 Tree-SHA512: f5985874d03e976cdb3d59036af7720636ad1488da40fd3bd7881b1fb71b05036a952013d519baa84c4ce4b558bdef25c4ce76b384b297e4d0aece9e37e78a01
(cherry picked from commit 91ca83d)
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
See commit message for a more detailed description.