On Fri, Aug 3, 2012, at 09:49 PM, Andreas Schildbach wrote:
>
> On 08/03/2012 08:37 PM, Jim Burton wrote:
>
> > 2) Andreas - what do you mean by 'unlock' exactly ? For the MultiBit
> > code all the only things I need the password for are:
> > + encrypt all the private keys, simultaneously clearing the
> > unencrypted key bytes in memory for security.
> > + add new encrypted keys (for create new receiving addresses, wallet
> > import)
> > + clone the encrypted private keys, then decrypt them before
> > spending/ exporting keys/ checking if I already have the key.
> > Clear the unencrypted cloned keys after use for security.
> > + to completely remove the encryption I need the user to reenter the
> > password to decrypt the keys. The password is not being stored in
> > memory so I cannot decrypt the keys otherwise.
> >
> > For most things like transaction management, fork management etc
> > everything uses the key's pubkey and hence is completely
> > uninterested in whether the key is encrypted, decrypted or (in the
> > future) watch-only.
>
> "Unlocking" means preparing the wallet for operations that need access
> to Bitcoin private keys, like spending. I'd rather not name this
> "decrypt", because this sounds like its the opposite of encrypt, which
> it isn't. Most importantly, it does not persist any decrypted keys to
> disk but keeps them in memory only.
I see. After an unlock the unencrypted private keys are available in
memory for whatever you want to do. Makes sense as the password -> key
step is expensive on a mobile. I presume you do it just once.
>
> I don't understand the need for cloning. Can you explain? Your other
> points look good to me. The Satoshi client can sign arbitrary
> messages; something like this would also need to unlock the wallet.
In MultiBit I have a background TimerTask that writes out 'dirty'
wallets. Also there are various threads for the Swing UI, block replay,
background tasks etc. For this reason and for general security I want to
minimise the time the Wallet keys are decrypted and in memory. For
instance, to sign a spend I :
1) Clone the wallet's encrypted keys.
2) Pass the cloned encrypted keys and the password to the signing code.
3) In the wallet signing method I:
+) Decrypt the cloned keys
+) Sign
+) Clear the password and cloned keys' decrypted private keys.
By 'clear' I mean overwrite the bytes/ chars with zeroes.
By doing this:
1) The wallet's keys (i.e. the ECKey objects referenced in the Wallet)
are never decrypted. There is no way another thread can write the
plaintext private key to disk.
2) The decrypted private keys are in memory for the absolute minimum
time before the decrypted data is destroyed. The objects only exist
in the bottom, local method scope so will be garbage collected
promptly.
3) The password is in memory for the absolute minimum time before it is
destroyed.
Good point about signing messages a la Satoshi. That would also need the
wallet password too.
>
> > 3) If the major and minor wallet fields were of general interest
> > then perhaps they should go into the Wallet type.
>
> My feeling is that a version - if we need it at all - should go into
> Wallet directly.
I will move it into Wallet. (Though I think it is currently more
of a MultiBit thing. Hmmm).
>
> WalletType is an enum anyway. Actually I'd rename it to
> EncryptionType.
Yes - that is clearer. Will do.
>
> > Then rather than a VersionableWallet I would just have an extra
> > 'wrapping' message (to avoid my specific MultiBit problem) as:
> >
> > message WrappedWallet { required Wallet wallet = 1000; }
> >
> > This would make the major and minor wallet versions of general use
> > on Wallet. I imagine most bitcoinj users would ignore the
> > WrappedWallet message entirely.
>
> Indeed.
>
> I wonder what exactly do you want to achieve? You want to prevent
> encrypted wallets from being loaded by old implementations. What will
> happen in this case? (just an exception?)
>
That is *exactly* what I am trying to achieve. Unfortunately my code in
previous MultiBits is a little too zealous in recovering from exceptions
and the encrypted wallets DO load. They load, but have blank private
keys. (There is data in the encrypted key field but the old MultiBits do
not understand that field so they ignore it). When the wallets are
stored (MultiBit is again quite zealous in storing the Wallets) the code
writes out the blank private keys ONLY. The encrypted private keys DO
NOT get written. All the private key data is lost.
This is not a theorectical thing - I have done it in real life and lost
BTC ! [only 100 millis :-) ] It is just not acceptable to release code
that does that.
> Will you be able to load _un_encrypted wallets by old implementations?
Yes - the unencrypted wallets are written out with the private key bytes
all there and the previous MultiBits load it happily.
I guess that is wny I find a monotonically increasing wallet version
useful. The current production code looks up the wallet version and
knows it can deal with 'wallet versions up to 2'. Anything higher than
that is from the future so it just will not load it. In a year when
someone fires up an old copy of MultiBit from a USB drive and tries
to load a 'wallet version 5' it will have no idea what that wallet is
but will know not to load it.
Jim