Skip to content

Instantly share code, notes, and snippets.

@Arachnid
Last active October 4, 2016 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Arachnid/0a492495906de1e8907c530219a64d01 to your computer and use it in GitHub Desktop.
Save Arachnid/0a492495906de1e8907c530219a64d01 to your computer and use it in GitHub Desktop.

pre-EIP: Password-protected Paper Wallets

Abstract

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.

Motivation

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.

Rationale

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.

Specification

Recognizing a password-protected mnemonic phrase

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.

Passphrase token generation

  • 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 and salt using PBKDF2, using the settings described in BIP39 (iteration count 2048, HMAC-SHA512 hash function). Call the first 256 bits of the output U_l. U_l is the user's component of the private key.
  • Derive the corresponding secp256k1 public key from U_l, and call it U_pub.

Send (salt, U_pub) to the wallet issuer.

Wallet generation - mnemonic encoded

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 output mnemonic.
  • 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 bits W_l. W_l is the wallet issuer's component of the private key.
  • Derive the corresponding secp256k1 public key from W_l, and call it W_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.

Private key recovery

  • Collect mnemonic and passphrase from the user.
  • Decode mnemonic to binary data to recover W_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 of W_rand.
  • Hash passphrase and salt using PBKDF2, as per BIP39. Split the result into two 256-bit components, U_l and U_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 and W_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 of privkey and right as the seed value for the corresponding wallet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment