-
Notifications
You must be signed in to change notification settings - Fork 0
Store a root of trust for your life.
License
cgaebel/lifecrypt
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Overview -------- Lifecrypt stores your encrypted personal root of trust. Some examples of what to include in it are 2fa keys and password manager master keys. Lifecrypt supports three operations over this data: [lifecrypt edit] opens the stored data with vim, for editing. [lifecrypt view] prints the stored data to stdout. [lifecrypt change-password] changes the encryption password. Key-derivation is provided by scrypt. Encryption and authentication is provided ChaCha20Poly1305. To learn more about scrypt, see the original tarsnap paper: https://www.tarsnap.com/scrypt/scrypt.pdf ChaCha20Poly1305 authenticated encryption is defined in RFC 7539, which can be found at https://tools.ietf.org/html/rfc7539. Quick Start ----------- git clone https://github.com/cgaebel/lifecrypt.git cd lifecrypt cargo build --release mkdir -p vault cp ./target/release/lifecrypt vault rm -rf target ./vault/lifecrypt edit ./vault/encrypted # type a password, then add some data to encrypt # decrypt the vault vault/lifecrypt view vault/encrypted If you move the vault to another system you might need to rebuild lifecrypt, but the encrypted file doesn't need to be regenerated -- it's portable. Motivation ---------- Suppose every electronic device you own is destroyed. How will you log in to gmail? How will you log in to anything? You're using 2FA, right? Those keys are gone. With lifecrypt, you can store recovery codes for all that stuff on a buddy's computer. If all your computers are kill, you might still stand a chance. Threat Model ------------ The on-disk data is available to the attacker. They would like to read it. The attacker is likely a friend or family member, or someone with access to them. Or the file could be leaked onto the internet, and a smart 14-year kid with a lot of free time will try disproportionally hard to break into it. The attacker does not have access to the computer on which the file is stored at the time it's edited or viewed. They only have access long after creation. Constraints ----------- It needs to be easy to interpret the file even if the code that would do that has entirely rotted. Even if there's no rust compiler in the future, the words in this document and a copy of the file should be enough to decrypt it. We wrote the first working version of this tool in less than 5 hours. If all we needed was to decrypt a file, it would've been even faster. Disk Format ----------- The on-disk format is a single JSON object with the following keys: = salt = A salt to use with scrypt. 32 bytes base64 encoded. = nonce = A nonce to use with ChaCha20Poly1305. 8 bytes base64 encoded. = ciphertext = Ciphertext generated by ChaCha20Poly1305. Variable-length Base64 encoded. = tag = An authentication tag generated by ChaCha20Poly1305. 16 bytes base64 encoded. The Base64 alphabet is "[A-Z][a-b][0-9]+/.". If you need a more formal definition see Section 3 of RFC3548. Lifecrypt does no padding. Here's an example of what this file might look like on disk: { "salt": "efx8L9xEQgqKCd8/+jPAlO8oRO+oxB0bkH/Dv/jAIzg", "nonce": "YLnDhkib/HU", "ciphertext": "sNiY30NV", "tag": "xyX+f3N0U084zthdY70VhQ" } Decoding -------- To view the plaintext you must know the password and have the on-disk data. Then, key = scrypt(password, disk.salt, log_n=14, r=8, p=1) plaintext = ChaCha20Poly1305::decrypt(disk.ciphertext, disk.nonce, disk.tag, key) Encoding -------- Encoding directly follows from the decoding process: password = get_password_input() plaintext = get_plaintext() salt = random_bytes(32) key = scrypt(password, salt, log_n=14, r=8, p=1) nonce = random_bytes(8) ciphertext, tag = ChaCha20Poly1305::encrypt(plaintext, nonce, key)
About
Store a root of trust for your life.