There is encryption in the wallet code, but it is found within both
*ScriptPubKeyMan so is not yet well encapsulated.
|When encryption is enabled secret data must only ever reside in memory and should never be written to disk.
When you unlock an encrypted wallet you can set a
timeout. When the timeout expires secret data is deleted from memory, and the wallet "re-locked".
As detailed in Key types, the
CMasterKey.vchCryptedKey is the actual secret key used to en/de-crypt the keys in the wallet.
CWallet stores a
CMasterKey, which is not a master private key. The
CMasterKey is encrypted by the user’s passphrase.
When the user changes their passphrase, they are only changing the encryption applied to the
CMasterKey, the inner
vchCryptedKey is not changed. This means that we do not have to read all items in the wallet database, decrypt them with the old key, encrypt them with the new key, and then write them, back to the database again. Instead, we only have to change the encryption applied to the
CMasterKey, which is much less error-prone, and more secure.
CWallet has a map of
CMasterKeys and when unlock is called it will try each one to see if it can decrypt and then unlock the wallet.
Only private keys are encrypted. This allows us to watch for new transactions without having to decrypt the wallet as each new block|transaction arrives.
Decrypting the Bitcoin Core wallet requires the user to enter their passphrase, so is not convenient to do at every new block.
When encrypting a wallet, a
CMasterKey encryption key is generated, which is then sent to the
ScriptPubKeyMan to encrypt using its
Once the wallet is encrypted for the first time, we re-generate all of our keys. This is to avoid the wallet using things which were not "born encrypted" in the future. For
LegacyScriptPubKeyMan this means creating a new HD seed, and for
DescriptorScriptPubKeyMan 8 new descriptors.
If the wallet has already been used before — while it existed in un-encrypted state — the old
ScriptPubKeyMan's are retained and so remain usable, but are not marked as
active. The wallet will switch to the new SPKM after encryption has completed by marking the new SPKM as
We take extra care during the encryption phase to either complete atomically or fail. This includes database writes where we don’t want to write half and crash, for example. Therefore we will throw an assertion if the write fails.
When you instruct a BDB database to delete a record, they are actually kept but "marked as" deleted, and might be fully deleted some time in the future.
This is not appropriate for our use case, for example when asking the DB to delete private keys after the wallet is encrypted for the first time. Therefore we use some hacks so that when we request deletion of unencrypted private keys from the DB, they are properly deleted immediately and not "marked as" deleted.
When encryption is enabled secret data must only ever exist in decrypted form in memory.