diff options
author | irungentoo <irungentoo@gmail.com> | 2014-10-10 22:07:43 -0400 |
---|---|---|
committer | irungentoo <irungentoo@gmail.com> | 2014-10-10 22:07:43 -0400 |
commit | 3f855b2445970fb32f06f4e8f5d07c89d617024f (patch) | |
tree | 33fb187e809166ee24853573631daa70f3c9b323 /toxencryptsave | |
parent | d80ee91ae77d0b852c685604b71774b6ee88cc2d (diff) | |
parent | 54fdf3bdd653ebf6e55d2cb93fcae41e68436e11 (diff) |
Merge branch 'master' of https://github.com/dubslow/toxcore
Diffstat (limited to 'toxencryptsave')
-rw-r--r-- | toxencryptsave/toxencryptsave.c | 164 | ||||
-rw-r--r-- | toxencryptsave/toxencryptsave.h | 53 |
2 files changed, 177 insertions, 40 deletions
diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c index 070f0184..7efba089 100644 --- a/toxencryptsave/toxencryptsave.c +++ b/toxencryptsave/toxencryptsave.c | |||
@@ -44,17 +44,22 @@ | |||
44 | /* return size of the messenger data (for encrypted saving). */ | 44 | /* return size of the messenger data (for encrypted saving). */ |
45 | uint32_t tox_encrypted_size(const Tox *tox) | 45 | uint32_t tox_encrypted_size(const Tox *tox) |
46 | { | 46 | { |
47 | return tox_size(tox) + crypto_box_MACBYTES + crypto_box_NONCEBYTES | 47 | return tox_size(tox) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH + TOX_ENC_SAVE_MAGIC_LENGTH; |
48 | + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH; | ||
49 | } | 48 | } |
50 | 49 | ||
51 | /* Save the messenger data encrypted with the given password. | 50 | /* Generates a secret symmetric key from the given passphrase. out_key must be at least |
52 | * data must be at least tox_encrypted_size(). | 51 | * TOX_PASS_KEY_LENGTH bytes long. |
52 | * Be sure to not compromise the key! Only keep it in memory, do not write to disk. | ||
53 | * This function is fairly cheap, but irungentoo insists that you be allowed to | ||
54 | * cache the result if you want, to minimize computation for repeated encryptions. | ||
55 | * The password is zeroed after key derivation. | ||
56 | * The key should only be used with the other functions in this module, as it | ||
57 | * includes a salt. | ||
53 | * | 58 | * |
54 | * returns 0 on success | 59 | * returns 0 on success |
55 | * returns -1 on failure | 60 | * returns -1 on failure |
56 | */ | 61 | */ |
57 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength) | 62 | int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key) |
58 | { | 63 | { |
59 | if (pplength == 0) | 64 | if (pplength == 0) |
60 | return -1; | 65 | return -1; |
@@ -78,16 +83,27 @@ int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint3 | |||
78 | } | 83 | } |
79 | 84 | ||
80 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ | 85 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ |
86 | memcpy(out_key, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
87 | memcpy(out_key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, key, crypto_box_KEYBYTES); | ||
88 | return 0; | ||
89 | } | ||
81 | 90 | ||
82 | /* next get plain save data */ | 91 | /* Encrypt arbitrary with a key produced by tox_derive_key_from_pass. The output |
83 | uint32_t temp_size = tox_size(tox); | 92 | * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. |
84 | uint8_t temp_data[temp_size]; | 93 | * key must be TOX_PASS_KEY_LENGTH bytes. |
85 | tox_save(tox, temp_data); | 94 | * If you already have a symmetric key from somewhere besides this module, simply |
86 | 95 | * call encrypt_data_symmetric in toxcore/crypto_core directly. | |
96 | * | ||
97 | * | ||
98 | * returns 0 on success | ||
99 | * returns -1 on failure | ||
100 | */ | ||
101 | int tox_pass_key_encrypt(uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out) | ||
102 | { | ||
87 | /* the output data consists of, in order: | 103 | /* the output data consists of, in order: |
88 | * magic number, salt, nonce, mac, enc_data | 104 | * salt, nonce, mac, enc_data |
89 | * where the mac is automatically prepended by the encrypt() | 105 | * where the mac is automatically prepended by the encrypt() |
90 | * the magic+salt+nonce is called the prefix | 106 | * the salt+nonce is called the prefix |
91 | * I'm not sure what else I'm supposed to do with the salt and nonce, since we | 107 | * I'm not sure what else I'm supposed to do with the salt and nonce, since we |
92 | * need them to decrypt the data | 108 | * need them to decrypt the data |
93 | */ | 109 | */ |
@@ -96,56 +112,111 @@ int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint3 | |||
96 | uint8_t nonce[crypto_box_NONCEBYTES]; | 112 | uint8_t nonce[crypto_box_NONCEBYTES]; |
97 | random_nonce(nonce); | 113 | random_nonce(nonce); |
98 | 114 | ||
99 | memcpy(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); | 115 | memcpy(out, key, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); |
100 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | 116 | key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; |
101 | memcpy(data, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | 117 | out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; |
102 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | 118 | memcpy(out, nonce, crypto_box_NONCEBYTES); |
103 | memcpy(data, nonce, crypto_box_NONCEBYTES); | 119 | out += crypto_box_NONCEBYTES; |
104 | data += crypto_box_NONCEBYTES; | ||
105 | 120 | ||
106 | /* now encrypt */ | 121 | /* now encrypt */ |
107 | if (encrypt_data_symmetric(key, nonce, temp_data, temp_size, data) | 122 | if (encrypt_data_symmetric(key, nonce, data, data_len, out) |
108 | != temp_size + crypto_box_MACBYTES) { | 123 | != data_len + crypto_box_MACBYTES) { |
109 | return -1; | 124 | return -1; |
110 | } | 125 | } |
111 | 126 | ||
112 | return 0; | 127 | return 0; |
113 | } | 128 | } |
114 | 129 | ||
115 | /* Load the messenger from encrypted data of size length. | 130 | /* Encrypts the given data with the given passphrase. The output array must be |
131 | * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates | ||
132 | * to tox_derive_key_from_pass and tox_pass_key_encrypt. | ||
116 | * | 133 | * |
117 | * returns 0 on success | 134 | * returns 0 on success |
118 | * returns -1 on failure | 135 | * returns -1 on failure |
119 | */ | 136 | */ |
120 | int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength) | 137 | int tox_pass_encrypt(uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out) |
121 | { | 138 | { |
122 | if (length <= crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + | 139 | uint8_t key[TOX_PASS_KEY_LENGTH]; |
123 | TOX_ENC_SAVE_MAGIC_LENGTH) | ||
124 | return -1; | ||
125 | 140 | ||
126 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) | 141 | if (tox_derive_key_from_pass(passphrase, pplength, key) == -1) |
127 | return -1; | 142 | return -1; |
128 | 143 | ||
144 | return tox_pass_key_encrypt(data, data_len, key, out); | ||
145 | } | ||
146 | |||
147 | /* Save the messenger data encrypted with the given password. | ||
148 | * data must be at least tox_encrypted_size(). | ||
149 | * | ||
150 | * returns 0 on success | ||
151 | * returns -1 on failure | ||
152 | */ | ||
153 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength) | ||
154 | { | ||
155 | /* first get plain save data */ | ||
156 | uint32_t temp_size = tox_size(tox); | ||
157 | uint8_t temp_data[temp_size]; | ||
158 | tox_save(tox, temp_data); | ||
159 | |||
160 | /* the output data consists of, in order: magic number, enc_data */ | ||
161 | /* first add the magic number */ | ||
162 | memcpy(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); | ||
129 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | 163 | data += TOX_ENC_SAVE_MAGIC_LENGTH; |
130 | 164 | ||
131 | uint32_t decrypt_length = length - crypto_box_MACBYTES - crypto_box_NONCEBYTES | 165 | /* now encrypt */ |
132 | - crypto_pwhash_scryptsalsa208sha256_SALTBYTES - TOX_ENC_SAVE_MAGIC_LENGTH; | 166 | return tox_pass_encrypt(temp_data, temp_size, passphrase, pplength, data); |
133 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | 167 | } |
168 | |||
169 | /* This is the inverse of tox_pass_key_encrypt, also using only keys produced by | ||
170 | * tox_derive_key_from_pass. | ||
171 | * | ||
172 | * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success | ||
173 | * returns -1 on failure | ||
174 | */ | ||
175 | int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out) | ||
176 | { | ||
177 | if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) | ||
178 | return -1; | ||
179 | |||
180 | uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
181 | //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
134 | uint8_t nonce[crypto_box_NONCEBYTES]; | 182 | uint8_t nonce[crypto_box_NONCEBYTES]; |
135 | 183 | ||
184 | //memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
185 | key += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // ignore the salt, which is only needed for kdf | ||
186 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
187 | memcpy(nonce, data, crypto_box_NONCEBYTES); | ||
188 | data += crypto_box_NONCEBYTES; | ||
189 | |||
190 | /* decrypt the data */ | ||
191 | if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) | ||
192 | != decrypt_length) { | ||
193 | return -1; | ||
194 | } | ||
195 | |||
196 | return decrypt_length; | ||
197 | } | ||
198 | |||
199 | /* Decrypts the given data with the given passphrase. The output array must be | ||
200 | * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. | ||
201 | * | ||
202 | * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success | ||
203 | * returns -1 on failure | ||
204 | */ | ||
205 | int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out) | ||
206 | { | ||
207 | |||
136 | uint8_t passkey[crypto_hash_sha256_BYTES]; | 208 | uint8_t passkey[crypto_hash_sha256_BYTES]; |
137 | crypto_hash_sha256(passkey, passphrase, pplength); | 209 | crypto_hash_sha256(passkey, passphrase, pplength); |
138 | 210 | ||
211 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
139 | memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | 212 | memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); |
140 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
141 | memcpy(nonce, data, crypto_box_NONCEBYTES); | ||
142 | data += crypto_box_NONCEBYTES; | ||
143 | 213 | ||
144 | /* derive the key */ | 214 | /* derive the key */ |
145 | uint8_t key[crypto_box_KEYBYTES]; | 215 | uint8_t key[crypto_box_KEYBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; |
146 | 216 | ||
147 | if (crypto_pwhash_scryptsalsa208sha256( | 217 | if (crypto_pwhash_scryptsalsa208sha256( |
148 | key, sizeof(key), passkey, sizeof(passkey), salt, | 218 | key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, |
219 | crypto_box_KEYBYTES, passkey, sizeof(passkey), salt, | ||
149 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ | 220 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ |
150 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { | 221 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { |
151 | /* out of memory most likely */ | 222 | /* out of memory most likely */ |
@@ -154,13 +225,28 @@ int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t * | |||
154 | 225 | ||
155 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ | 226 | sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ |
156 | 227 | ||
157 | /* decrypt the data */ | 228 | return tox_pass_key_decrypt(data, length, key, out); |
229 | } | ||
230 | |||
231 | /* Load the messenger from encrypted data of size length. | ||
232 | * | ||
233 | * returns 0 on success | ||
234 | * returns -1 on failure | ||
235 | */ | ||
236 | int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength) | ||
237 | { | ||
238 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) | ||
239 | return -1; | ||
240 | |||
241 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
242 | length -= TOX_ENC_SAVE_MAGIC_LENGTH; | ||
243 | |||
244 | uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; | ||
158 | uint8_t temp_data[decrypt_length]; | 245 | uint8_t temp_data[decrypt_length]; |
159 | 246 | ||
160 | if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, temp_data) | 247 | if (tox_pass_decrypt(data, length, passphrase, pplength, temp_data) |
161 | != decrypt_length) { | 248 | != decrypt_length) |
162 | return -1; | 249 | return -1; |
163 | } | ||
164 | 250 | ||
165 | return tox_load(tox, temp_data, decrypt_length); | 251 | return tox_load(tox, temp_data, decrypt_length); |
166 | } | 252 | } |
@@ -170,7 +256,7 @@ int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t * | |||
170 | * returns 1 if it is encrypted | 256 | * returns 1 if it is encrypted |
171 | * returns 0 otherwise | 257 | * returns 0 otherwise |
172 | */ | 258 | */ |
173 | int tox_is_data_encrypted(const uint8_t *data) | 259 | int tox_is_save_encrypted(const uint8_t *data) |
174 | { | 260 | { |
175 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) | 261 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) |
176 | return 1; | 262 | return 1; |
diff --git a/toxencryptsave/toxencryptsave.h b/toxencryptsave/toxencryptsave.h index 75094a2b..527578a5 100644 --- a/toxencryptsave/toxencryptsave.h +++ b/toxencryptsave/toxencryptsave.h | |||
@@ -35,6 +35,10 @@ extern "C" { | |||
35 | typedef struct Tox Tox; | 35 | typedef struct Tox Tox; |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #define TOX_PASS_ENCRYPTION_EXTRA_LENGTH (crypto_box_MACBYTES + crypto_box_NONCEBYTES \ | ||
39 | + crypto_pwhash_scryptsalsa208sha256_SALTBYTES) | ||
40 | |||
41 | #define TOX_PASS_KEY_LENGTH (crypto_box_KEYBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES) | ||
38 | 42 | ||
39 | /* This "module" provides functions analogous to tox_load and tox_save in toxcore | 43 | /* This "module" provides functions analogous to tox_load and tox_save in toxcore |
40 | * Clients should consider alerting their users that, unlike plain data, if even one bit | 44 | * Clients should consider alerting their users that, unlike plain data, if even one bit |
@@ -45,6 +49,43 @@ typedef struct Tox Tox; | |||
45 | /* return size of the messenger data (for encrypted saving). */ | 49 | /* return size of the messenger data (for encrypted saving). */ |
46 | uint32_t tox_encrypted_size(const Tox *tox); | 50 | uint32_t tox_encrypted_size(const Tox *tox); |
47 | 51 | ||
52 | /* Generates a secret symmetric key from the given passphrase. out_key must be at least | ||
53 | * TOX_PASS_KEY_LENGTH bytes long. | ||
54 | * Be sure to not compromise the key! Only keep it in memory, do not write to disk. | ||
55 | * This function is fairly cheap, but irungentoo insists that you be allowed to | ||
56 | * cache the result if you want, to minimize computation for repeated encryptions. | ||
57 | * The password is zeroed after key derivation. | ||
58 | * The key should only be used with the other functions in this module, as it | ||
59 | * includes a salt. | ||
60 | * | ||
61 | * returns 0 on success | ||
62 | * returns -1 on failure | ||
63 | */ | ||
64 | int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key); | ||
65 | |||
66 | /* Encrypt arbitrary with a key produced by tox_derive_key_from_pass. The output | ||
67 | * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. | ||
68 | * key must be TOX_PASS_KEY_LENGTH bytes. | ||
69 | * If you already have a symmetric key from somewhere besides this module, simply | ||
70 | * call encrypt_data_symmetric in toxcore/crypto_core directly. | ||
71 | * | ||
72 | * | ||
73 | * returns 0 on success | ||
74 | * returns -1 on failure | ||
75 | */ | ||
76 | int tox_pass_key_encrypt(uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out); | ||
77 | |||
78 | /* Encrypts the given data with the given passphrase. The output array must be | ||
79 | * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates | ||
80 | * to tox_derive_key_from_pass and tox_pass_key_encrypt. | ||
81 | * | ||
82 | * tox_encrypted_save() is a good example of how to use this function. | ||
83 | * | ||
84 | * returns 0 on success | ||
85 | * returns -1 on failure | ||
86 | */ | ||
87 | int tox_pass_encrypt(uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out); | ||
88 | |||
48 | /* Save the messenger data encrypted with the given password. | 89 | /* Save the messenger data encrypted with the given password. |
49 | * data must be at least tox_encrypted_size(). | 90 | * data must be at least tox_encrypted_size(). |
50 | * | 91 | * |
@@ -53,6 +94,16 @@ uint32_t tox_encrypted_size(const Tox *tox); | |||
53 | */ | 94 | */ |
54 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength); | 95 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength); |
55 | 96 | ||
97 | /* Decrypts the given data with the given passphrase. The output array must be | ||
98 | * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. | ||
99 | * | ||
100 | * tox_encrypted_load() is a good example of how to use this function. | ||
101 | * | ||
102 | * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success | ||
103 | * returns -1 on failure | ||
104 | */ | ||
105 | int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out); | ||
106 | |||
56 | /* Load the messenger from encrypted data of size length. | 107 | /* Load the messenger from encrypted data of size length. |
57 | * | 108 | * |
58 | * returns 0 on success | 109 | * returns 0 on success |
@@ -65,7 +116,7 @@ int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t * | |||
65 | * returns 1 if it is encrypted | 116 | * returns 1 if it is encrypted |
66 | * returns 0 otherwise | 117 | * returns 0 otherwise |
67 | */ | 118 | */ |
68 | int tox_is_data_encrypted(const uint8_t *data); | 119 | int tox_is_save_encrypted(const uint8_t *data); |
69 | 120 | ||
70 | #ifdef __cplusplus | 121 | #ifdef __cplusplus |
71 | } | 122 | } |