BIP: ??? (tbr after sending to mailing list) Layer: Applications Title: Cipherseed – encrypted wallet seed Author: Jonas Schnelli <[email protected]> Comments-Summary: No comments yet. Comments-URI: Status: Draft Type: Standards Track Created: 2018-06-04 License: BSD-2-Clause
This document proposes an encrypted wallet seed format including metadata called Cipherseed
This BIP is licensed under the 2-clause BSD license.
BIP0039, a widely used seed scheme defined in [1] lacks of the following properties:
- No encryption (only salt based derivation)
- Mnemonic implies that users can (and eventually should) memorize the words
- Impossible to change the derivation „passphrase“ after creation
- Lack of versioning
- Lack of seed birthday
- Lack of seed type
- Non effective KDF
This proposal is heavily inspired by LNDs aezeed [2].
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119[3].
As KDF, PBKDF2 SHA2_HMAC_512 with 20000 rounds and a random 5 byte salt MUST be used
ChaCha20 with 256bit keys MUST be used for encryption.
Poly1305 MUST be used to produce two 32bit MAC tags.
The first ChaCha20 key k0
MUST be derived with KDF(userpassphrase0)
(first 256 bits of the output).
The optional second ChaCha20 key k1
MUST be derived with KDF(userpassphrase1)
(first 256 bits of the output). If userpassphrase1
has not been provided, 256 secure random bit for k1
MUST be used (no KDF execution for k1
).
The first Poly1305 key mac_k0
MUST be derived in context0 with ChaCha20_Encrypt(nonce=0, data=k0, counter=0)
.
The first Poly1305 key mac_k1
MUST be derived in context1 with ChaCha20_Encrypt(nonce=0, data=k1, counter=0)
.
Encryption of the header and the seed MUST be done in context0 with ChaCha20_Encrypt(nonce=1, data=k0, counter=1)
The first Poly1305 authentication tag MUST be calculated by Poly1305(k=mac_k0, data=(salt || encrypted_header[type,birthsday] || encrypted_seed))
The second Poly1305 authentication tag MUST be calculated by Poly1305(k=mac_k1, data=(salt || encrypted_header[type,birthsday] || encrypted_seed))
Before decrypting the seed, the MAC tags MUST be verified and only proceed with the decryption if one of the two tags are valid (authenticated).
- 1 byte seed usage-type (scripts restriction and future extensions)
- 2 byte key birthday timestamp in days since genesis (until year 2188)
Value | Type | Description |
---|---|---|
0x00
|
USAGE_TYPE_UNKNOWN
| Unknown usage type |
0x01 |
USAGE_TYPE_BIP44_P2PKH
| The seed is only used to derive P2PKH scripts after BIP44[4]. |
0x02 |
USAGE_TYPE_BIP44_P2WPKH
| The seed is only used to derive P2WPKH scripts after BIPXXX. |
0x03 |
USAGE_TYPE_BIP44_P2SH_P2WPKH
| The seed is only used to derive P2SH(P2WPKH) scripts after BIP49[5]. |
0x04 |
USAGE_TYPE_BIP32_P2PKH
|
The seed is only used to derive P2PKH scripts after BIP32[6] (m/i'/0|1/k) .
|
0x05 |
USAGE_TYPE_BIP32_P2WPKH
| The seed is only used to derive P2WPKH scripts after BIP32. |
0x06 |
USAGE_TYPE_BIP32_P2SH_P2WPKH
| The seed is only used to derive P2SH(P2WPKH) scripts after BIP32. |
In Cipherseed, we append two 32bit truncated Poly1305 MAC tags, each produced with a user defined key, stretched with the KDF. The MAC covers (salt || header[type,birthsday] || seed).
If only one key will be provided by the user during seed encryption, the second key MUST be set with secure random bytes.
The order of the appended tags MUST be random (also if only one passphrase was provided).
The usage of two MAC tags will result in having two "valid", indistinguishable passphrases and thus two valid and indistinguishable plaintext seeds.
The practical usage of the plausible deniability feature is in general questionable. Allowing more then two keys will very likely not increase the robustness against such attacks.
Length | Name | Description |
---|---|---|
4 byte
|
version byte & salt
| 1 version bit, must be zero, 31 bits KDF salt that make precomputation tables (rainbow-tables) for KDF impracticable |
16 or 32 bytes |
ciphertext-seed
| Encrypted 128bit or 256bit seed |
1 bytes |
ciphertext-usage-type
| Encrypted usage type (see table below) |
2 bytes |
ciphertext-birthday
| Encrypted birthday in days since genesis |
4 bytes |
MAC tag 0
| MAC tag done with either key0 or key1 (random order) |
4 bytes |
MAC tag 1
| MAC tag done with other key then MAC tag 0 |
- = Total 33/49 bytes
- 31 bytes == 248 bits == 50 base32 chars (without checksum/hrp)
- 47 bytes == 375 bits == 75 base32 chars (without checksum/hrp)
The encrypted seed MUST be encoded with Bech32X into a 82 character (50 chars base32, 26 chars checksum, 3 chars hrp+separator) resp. 104 character string.
Bech32X is an error correction code optimised for strings with a maximum length of 341 characters with a 26 characters checksum that can correct up to 7 errors (8.86% resp. 6.73% in case of a Cipherseed).
Bech32X is defined in BIPXXXX
An example Cipherseed string could be xp1kc8s5qhz4rsgv54z9a92yla4m2yrsqdlwdl7dvwkuh3zrg66z8ad2snf832tgaxcuv3kmwtnkj2q3a03ky0kg8p7dvv4czpjqg9trlw9
.
Applications supporting Cipherseed MUST show Cipherseeds in a block of 22 times 5 chars. Missing characters can be identified easier with that method.
1. xp1kc 12. 2snf8 2. 8s5qh 13. 32tga 3. z4rsg 14. xcuv3 4. v54z9 15. kmwtn 5. a92yl 16. kj2q3 6. a4m2y 17. a03ky 7. rsqdl 18. 0kg8p 8. wdl7d 19. 7dvv4 9. vwkuh 20. czpjq 10. 3zrg6 21. g9trl 11. 6z8ad 22. w9
Uppercase characters are possible and will be transformed to lowercase within the Bech32X deserialization.
Applications that support importing of Cipherseeds MAY help during the import phase in reducing the typeable charset to the Bech32X charset.
Tests have shown that writing down a 256bit entropy Cipherseed takes no longer then writing down a 24-word BIP39 mnemonic. The process of importing a Cipherseed may take a couple of seconds longer since auto-completing the string-chunks are not possible
- Only new software will be able to use this format.
- There is no interoperability with BIP39
https://github.com/jonasschnelli/cipherseed
- Gregory Maxwell for the idea of using two MAC tags to allow a form of plausible deniability
- Olaoluwa Osuntokun for specifying Aezeed in LND
The "seed birthday" should be taken more care of, otherwise this feature could turn into a bug, if the encoded birthday is later than the actual birthday.
Edit: even if address reuse has been discouraged since the Satoshi era, it's never forbidden. Therefore, the seed birthday will never be reliable in my opinion, since even encountering the first address during the scanning cannot rule out the possiblity of an earlier received transaction.
Also, it's not quite unusual to see system clock to be disturbed - like, booting from different OSes like Windows and Ubuntu, which have different default system clock policy - both have the ability to automatically sync the clock with NTP servers, but by default, Windows uses local time, while Ubuntu uses UTC time.