-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
117 lines (90 loc) · 3.61 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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)