pre-EIP: Password-protected Paper Wallets
A mechanism is presented for generating password protected wallets, generated in such a fashion that a printing facility can generate a paper wallet that is encrypted with a user-supplied password, produced in such a fashion that the neither the printer nor the user can recover the account's private key without both the paper wallet and the password. This facilitates generating secure paper wallets or 'physical ether', whose security rests neither on the trustworthiness of the printer nor on the user's ability to effectively conceal their password. Password-protected wallets are encoded as mnemonic phrases, as described in BIP39.
Paper wallets provide an attractive option for secure offline storage of cryptocurrencies, but securely generating a paper wallet can be an involved process, requiring an offline ('airgapped') computer and considerable care to protect private information. Third-party printers can generate paper wallets, but then users have to trust that the printer will treat the private information appropriately and will not retain copies of the private key.
BIP38 describes mechanisms for generating encrypted Bitcoin keypairs such that the printer can generate a correct address, but cannot recover the private key without the user's password, which is not supplied as part of the generation process. This EIP describes an implementation of password-protected keypair generation that is simpler and easier to implement than the scheme described in BIP38, while also adapting it for common Ethereum use-cases.
User story: I would like to be able to generate a secure offline wallet to store my Ether in, without having to trust in the integrity of a third-party printer, and with a greater degree of security than I can accomplish myself by printing a paper wallet from my browser.
User story: I would like to be able to withdraw funds from my offline wallet using a computer with an Ethereum client or web browser, with as little fuss as possible, and with minimal chance of user error.
Because both password-protected and regular wallets can be encoded as mnemonic phrases, it is necessary to provide a means for wallet software to distinguish the two. We propose the following:
- Regular (non-password-protected) wallets are encoded as mnemonic strings whose binary representation's most significant bit is 0.
- Password-protected wallets are encoded as mnemonic strings whose binary representation's most significant byte is 0x81. Software should provide a means for users to override this detection and treat the wallet as a regular wallet.
- Other values for the most significant byte are reserved for future types of wallet.
- Implementations that encounter unrecognized values for the leading byte should assume these are generated naively by software unaware of this standard, and should treat them as regular wallets.
This mechanism minimises the overhead for standard wallets, requiring a reduction in strength of only 1 bit, while seeking to provide expandability for other wallet schemes. 50% of naively generated wallets will appear to be special wallets, but only 1/256 will be mistakenly identified as password protected.
- The user is prompted for a passphrase,
passphrase
. - A 32 bit salt,
salt
is randomly generated using a secure source of pseudorandom data. - Hash
passphrase
andsalt
using PBKDF2, using the settings described in BIP39 (iteration count 2048, HMAC-SHA512 hash function). Call the first 256 bits of the outputU_l
.U_l
is the user's component of the private key. - Derive the corresponding secp256k1 public key from
U_l
, and call itU_pub
.
Send (salt
, U_pub
) to the wallet issuer.
The procedure below describes a manner of generating a paper wallet that encodes as a mnemonic sequence, for easy entry by users.
- Generate a random string
rand
of length (88 + 32n) bits, where n is an integer >= 0. - Set
W_rand = 0x81 + salt + rand
, where+
denotes concatenation. - Encode
W_rand
as a mnemonic as described in BIP39, calling the outputmnemonic
. - Print
mnemonic
on the user's paper wallet as the private key. - Use the seed derivation function described in BIP39 to generate a seed value from
mnemonic
. Call the first 256 bitsW_l
.W_l
is the wallet issuer's component of the private key. - Derive the corresponding secp256k1 public key from
W_l
, and call itW_pub
. - Set
pubkey = U_pub + W_pub
, where+
is the addition operation in the secp256k1 finite field. - Derive the Ethereum address from this public key, and encode it on the user's paper wallet as their address.
- Collect
mnemonic
andpassphrase
from the user. - Decode
mnemonic
to binary data to recoverW_rand
. - Verify the mnemonic corresponds to a password-protected wallet by verifying the first 8 bits of
W_rand
are 0x81. - Extract
salt
from bits 8-40 ofW_rand
. - Hash
passphrase
andsalt
using PBKDF2, as per BIP39. Split the result into two 256-bit components,U_l
andU_r
. - Use the seed derivation function described in BIP39 to generate a seed value from
mnemonic
. Split it into two 256-bit components,W_l
andW_r
. - Compute
privkey = U_l + W_l
, where+
is the secp256k1 point addition operation. - If an HD wallet is required, compute
right = U_r ^ W_r
, where^
is bitwise XOR, and use the concatenation ofprivkey
andright
as the seed value for the corresponding wallet.