summaryrefslogtreecommitdiff
path: root/toxencryptsave/toxencryptsave.c
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2015-03-31 19:44:51 -0400
committerirungentoo <irungentoo@gmail.com>2015-03-31 19:44:51 -0400
commit99e0fde2977aac291552a678323bb16e62046fb0 (patch)
treea484c48c301538e1c43d54cf056ba0204338f60e /toxencryptsave/toxencryptsave.c
parent48249360dcde0a8c81ae62c2bace349fdb8274a1 (diff)
parente998aca8f75e46cd360210ac588ee77af0106c6d (diff)
Merge branch 'master' of https://github.com/dubslow/toxcore
Diffstat (limited to 'toxencryptsave/toxencryptsave.c')
-rw-r--r--toxencryptsave/toxencryptsave.c238
1 files changed, 92 insertions, 146 deletions
diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c
index 874f0fd0..9b202f49 100644
--- a/toxencryptsave/toxencryptsave.c
+++ b/toxencryptsave/toxencryptsave.c
@@ -37,81 +37,69 @@
37#include <crypto_hash_sha256.h> 37#include <crypto_hash_sha256.h>
38#endif 38#endif
39 39
40#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH (crypto_box_MACBYTES + crypto_box_NONCEBYTES \ 40#if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES
41 + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) 41#error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES
42 42#endif
43#define TOX_PASS_KEY_LENGTH (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES)
44
45int tox_pass_encryption_extra_length()
46{
47 return TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
48}
49 43
50int tox_pass_key_length() 44#if TOX_PASS_KEY_LENGTH != (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES)
51{ 45#error TOX_PASS_KEY_LENGTH is assumed to be equal to (crypto_pwhash_scryptsalsa208sha256_SALTBYTES + crypto_box_KEYBYTES)
52 return TOX_PASS_KEY_LENGTH; 46#endif
53}
54 47
55int tox_pass_salt_length() 48#if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)
56{ 49#error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)
57 return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; 50#endif
58}
59 51
60/* This "module" provides functions analogous to tox_load and tox_save in toxcore 52/* Clients should consider alerting their users that, unlike plain data, if even one bit
61 * Clients should consider alerting their users that, unlike plain data, if even one bit
62 * becomes corrupted, the data will be entirely unrecoverable. 53 * becomes corrupted, the data will be entirely unrecoverable.
63 * Ditto if they forget their password, there is no way to recover the data. 54 * Ditto if they forget their password, there is no way to recover the data.
64 */ 55 */
65 56
66/* return size of the messenger data (for encrypted saving). */
67uint32_t tox_encrypted_size(const Tox *tox)
68{
69 return tox_get_savedata_size(tox) + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
70}
71
72/* This retrieves the salt used to encrypt the given data, which can then be passed to 57/* This retrieves the salt used to encrypt the given data, which can then be passed to
73 * derive_key_with_salt to produce the same key as was previously used. Any encrpyted 58 * derive_key_with_salt to produce the same key as was previously used. Any encrpyted
74 * data with this module can be used as input. 59 * data with this module can be used as input.
75 * 60 *
76 * returns -1 if the magic number is wrong 61 * returns true if magic number matches
77 * returns 0 otherwise (no guarantee about validity of data) 62 * success does not say anything about the validity of the data, only that data of
63 * the appropriate size was copied
78 */ 64 */
79int tox_get_salt(uint8_t *data, uint8_t *salt) 65bool tox_get_salt(const uint8_t *data, uint8_t *salt)
80{ 66{
81 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) 67 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0)
82 return -1; 68 return 0;
83 69
84 data += TOX_ENC_SAVE_MAGIC_LENGTH; 70 data += TOX_ENC_SAVE_MAGIC_LENGTH;
85 memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); 71 memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);
86 return 0; 72 return 1;
87} 73}
88 74
89/* Generates a secret symmetric key from the given passphrase. out_key must be at least 75/* Generates a secret symmetric key from the given passphrase. out_key must be at least
90 * TOX_PASS_KEY_LENGTH bytes long. 76 * TOX_PASS_KEY_LENGTH bytes long.
91 * Be sure to not compromise the key! Only keep it in memory, do not write to disk. 77 * Be sure to not compromise the key! Only keep it in memory, do not write to disk.
92 * This function is fairly cheap, but irungentoo insists that you be allowed to
93 * cache the result if you want, to minimize computation for repeated encryptions.
94 * The password is zeroed after key derivation. 78 * The password is zeroed after key derivation.
95 * The key should only be used with the other functions in this module, as it 79 * The key should only be used with the other functions in this module, as it
96 * includes a salt. 80 * includes a salt.
81 * Note that this function is not deterministic; to derive the same key from a
82 * password, you also must know the random salt that was used. See below.
97 * 83 *
98 * returns 0 on success 84 * returns true on success
99 * returns -1 on failure
100 */ 85 */
101int tox_derive_key_from_pass(uint8_t *passphrase, uint32_t pplength, uint8_t *out_key) 86bool tox_derive_key_from_pass(uint8_t *passphrase, size_t pplength, uint8_t *out_key, TOX_ERR_KEY_DERIVATION *error)
102{ 87{
103 uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; 88 uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];
104 randombytes(salt, sizeof salt); 89 randombytes(salt, sizeof salt);
105 return tox_derive_key_with_salt(passphrase, pplength, salt, out_key); 90 return tox_derive_key_with_salt(passphrase, pplength, salt, out_key, error);
106} 91}
107 92
108/* Same as above, except with use the given salt for deterministic key derivation. 93/* Same as above, except with use the given salt for deterministic key derivation.
109 * The salt must be tox_salt_length() bytes in length. 94 * The salt must be tox_salt_length() bytes in length.
110 */ 95 */
111int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *salt, uint8_t *out_key) 96bool tox_derive_key_with_salt(uint8_t *passphrase, size_t pplength, uint8_t *salt, uint8_t *out_key,
97 TOX_ERR_KEY_DERIVATION *error)
112{ 98{
113 if (pplength == 0) 99 if (pplength == 0 || !passphrase || !salt || !out_key) {
114 return -1; 100 SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL);
101 return 0;
102 }
115 103
116 uint8_t passkey[crypto_hash_sha256_BYTES]; 104 uint8_t passkey[crypto_hash_sha256_BYTES];
117 crypto_hash_sha256(passkey, passphrase, pplength); 105 crypto_hash_sha256(passkey, passphrase, pplength);
@@ -127,27 +115,33 @@ int tox_derive_key_with_salt(uint8_t *passphrase, uint32_t pplength, uint8_t *sa
127 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ 115 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */
128 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { 116 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) {
129 /* out of memory most likely */ 117 /* out of memory most likely */
130 return -1; 118 SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED);
119 return 0;
131 } 120 }
132 121
133 sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ 122 sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */
134 memcpy(out_key, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); 123 memcpy(out_key, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);
135 memcpy(out_key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, key, crypto_box_KEYBYTES); 124 memcpy(out_key + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, key, crypto_box_KEYBYTES);
136 return 0; 125 SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK);
126 return 1;
137} 127}
138 128
139/* Encrypt arbitrary with a key produced by tox_derive_key_from_pass. The output 129/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output
140 * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. 130 * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long.
141 * key must be TOX_PASS_KEY_LENGTH bytes. 131 * key must be TOX_PASS_KEY_LENGTH bytes.
142 * If you already have a symmetric key from somewhere besides this module, simply 132 * If you already have a symmetric key from somewhere besides this module, simply
143 * call encrypt_data_symmetric in toxcore/crypto_core directly. 133 * call encrypt_data_symmetric in toxcore/crypto_core directly.
144 * 134 *
145 * 135 * returns true on success
146 * returns 0 on success
147 * returns -1 on failure
148 */ 136 */
149int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *key, uint8_t *out) 137bool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const uint8_t *key, uint8_t *out,
138 TOX_ERR_ENCRYPTION *error)
150{ 139{
140 if (data_len == 0 || !data || !key || !out) {
141 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL);
142 return 0;
143 }
144
151 /* the output data consists of, in order: 145 /* the output data consists of, in order:
152 * salt, nonce, mac, enc_data 146 * salt, nonce, mac, enc_data
153 * where the mac is automatically prepended by the encrypt() 147 * where the mac is automatically prepended by the encrypt()
@@ -173,78 +167,62 @@ int tox_pass_key_encrypt(const uint8_t *data, uint32_t data_len, const uint8_t *
173 /* now encrypt */ 167 /* now encrypt */
174 if (encrypt_data_symmetric(key, nonce, data, data_len, out) 168 if (encrypt_data_symmetric(key, nonce, data, data_len, out)
175 != data_len + crypto_box_MACBYTES) { 169 != data_len + crypto_box_MACBYTES) {
176 return -1; 170 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED);
171 return 0;
177 } 172 }
178 173
179 return 0; 174 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK);
175 return 1;
180} 176}
181 177
182/* Encrypts the given data with the given passphrase. The output array must be 178/* Encrypts the given data with the given passphrase. The output array must be
183 * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates 179 * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates
184 * to tox_derive_key_from_pass and tox_pass_key_encrypt. 180 * to tox_derive_key_from_pass and tox_pass_key_encrypt.
185 * 181 *
186 * returns 0 on success 182 * returns true on success
187 * returns -1 on failure
188 */ 183 */
189int tox_pass_encrypt(const uint8_t *data, uint32_t data_len, uint8_t *passphrase, uint32_t pplength, uint8_t *out) 184bool tox_pass_encrypt(const uint8_t *data, size_t data_len, uint8_t *passphrase, size_t pplength, uint8_t *out,
185 TOX_ERR_ENCRYPTION *error)
190{ 186{
191 uint8_t key[TOX_PASS_KEY_LENGTH]; 187 uint8_t key[TOX_PASS_KEY_LENGTH];
188 TOX_ERR_KEY_DERIVATION _error;
192 189
193 if (tox_derive_key_from_pass(passphrase, pplength, key) == -1) 190 if (!tox_derive_key_from_pass(passphrase, pplength, key, &_error)) {
194 return -1; 191 if (_error == TOX_ERR_KEY_DERIVATION_NULL) {
195 192 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL);
196 return tox_pass_key_encrypt(data, data_len, key, out); 193 } else if (_error == TOX_ERR_KEY_DERIVATION_FAILED) {
197} 194 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED);
195 }
198 196
199/* Save the messenger data encrypted with the given password. 197 return 0;
200 * data must be at least tox_encrypted_size(). 198 }
201 *
202 * returns 0 on success
203 * returns -1 on failure
204 */
205int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength)
206{
207 /* first get plain save data */
208 uint32_t temp_size = tox_get_savedata_size(tox);
209 uint8_t temp_data[temp_size];
210 tox_get_savedata(tox, temp_data);
211
212 /* now encrypt */
213 return tox_pass_encrypt(temp_data, temp_size, passphrase, pplength, data);
214}
215
216/* Save the messenger data encrypted with the given key from tox_derive_key.
217 * data must be at least tox_encrypted_size().
218 *
219 * returns 0 on success
220 * returns -1 on failure
221 */
222int tox_encrypted_key_save(const Tox *tox, uint8_t *data, uint8_t *key)
223{
224 /* first get plain save data */
225 uint32_t temp_size = tox_get_savedata_size(tox);
226 uint8_t temp_data[temp_size];
227 tox_get_savedata(tox, temp_data);
228 199
229 /* encrypt */ 200 return tox_pass_key_encrypt(data, data_len, key, out, error);
230 return tox_pass_key_encrypt(temp_data, temp_size, key, data);
231} 201}
232 202
233/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by 203/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by
234 * tox_derive_key_from_pass. 204 * tox_derive_key_from_pass.
235 * 205 *
236 * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success 206 * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
237 * returns -1 on failure 207 *
208 * returns true on success
238 */ 209 */
239int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *key, uint8_t *out) 210bool tox_pass_key_decrypt(const uint8_t *data, size_t length, const uint8_t *key, uint8_t *out,
211 TOX_ERR_DECRYPTION *error)
240{ 212{
241 if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH 213 if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
242 || 0 != memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH)) 214 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);
243 return -1; 215 return 0;
216 }
217
218 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) {
219 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);
220 return 0;
221 }
244 222
245 data += TOX_ENC_SAVE_MAGIC_LENGTH; 223 data += TOX_ENC_SAVE_MAGIC_LENGTH;
246 224
247 uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; 225 size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
248 //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; 226 //uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];
249 uint8_t nonce[crypto_box_NONCEBYTES]; 227 uint8_t nonce[crypto_box_NONCEBYTES];
250 228
@@ -257,20 +235,30 @@ int tox_pass_key_decrypt(const uint8_t *data, uint32_t length, const uint8_t *ke
257 /* decrypt the data */ 235 /* decrypt the data */
258 if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) 236 if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, out)
259 != decrypt_length) { 237 != decrypt_length) {
260 return -1; 238 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED);
239 return 0;
261 } 240 }
262 241
263 return decrypt_length; 242 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK);
243 return 1;
264} 244}
265 245
266/* Decrypts the given data with the given passphrase. The output array must be 246/* Decrypts the given data with the given passphrase. The output array must be
267 * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. 247 * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates
248 * to tox_pass_key_decrypt.
249 *
250 * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH
268 * 251 *
269 * returns the length of the output data (== data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH) on success 252 * returns true on success
270 * returns -1 on failure
271 */ 253 */
272int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength, uint8_t *out) 254bool tox_pass_decrypt(const uint8_t *data, size_t length, uint8_t *passphrase, size_t pplength, uint8_t *out,
255 TOX_ERR_DECRYPTION *error)
273{ 256{
257 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) {
258 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);
259 return 0;
260 }
261
274 uint8_t passkey[crypto_hash_sha256_BYTES]; 262 uint8_t passkey[crypto_hash_sha256_BYTES];
275 crypto_hash_sha256(passkey, passphrase, pplength); 263 crypto_hash_sha256(passkey, passphrase, pplength);
276 264
@@ -286,60 +274,18 @@ int tox_pass_decrypt(const uint8_t *data, uint32_t length, uint8_t *passphrase,
286 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ 274 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */
287 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { 275 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) {
288 /* out of memory most likely */ 276 /* out of memory most likely */
289 return -1; 277 SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED);
278 return 0;
290 } 279 }
291 280
292 sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ 281 sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */
293 282
294 return tox_pass_key_decrypt(data, length, key, out); 283 return tox_pass_key_decrypt(data, length, key, out, error);
295}
296
297/* Load the new messenger from encrypted data of size length.
298 * All other arguments are like toxcore/tox_new().
299 *
300 * returns NULL on failure; see the documentation in toxcore/tox.h.
301 */
302Tox *tox_encrypted_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *passphrase,
303 size_t pplength, TOX_ERR_ENCRYPTED_NEW *error)
304{
305 uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
306 uint8_t temp_data[decrypt_length];
307
308 if (tox_pass_decrypt(data, length, passphrase, pplength, temp_data)
309 != decrypt_length) {
310 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED);
311 return NULL;
312 }
313
314 return tox_new(options, temp_data, decrypt_length, error);
315}
316
317/* Load the messenger from encrypted data of size length, with key from tox_derive_key.
318 * All other arguments are like toxcore/tox_new().
319 *
320 * returns NULL on failure; see the documentation in toxcore/tox.h.
321 */
322Tox *tox_encrypted_key_new(const struct Tox_Options *options, const uint8_t *data, size_t length, uint8_t *key,
323 TOX_ERR_ENCRYPTED_NEW *error)
324{
325 uint32_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;
326 uint8_t temp_data[decrypt_length];
327
328 if (tox_pass_key_decrypt(data, length, key, temp_data)
329 != decrypt_length) {
330 SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED);
331 return NULL;
332 }
333
334 return tox_new(options, temp_data, decrypt_length, error);
335} 284}
336 285
337/* Determines whether or not the given data is encrypted (by checking the magic number) 286/* Determines whether or not the given data is encrypted (by checking the magic number)
338 *
339 * returns 1 if it is encrypted
340 * returns 0 otherwise
341 */ 287 */
342int tox_is_data_encrypted(const uint8_t *data) 288bool tox_is_data_encrypted(const uint8_t *data)
343{ 289{
344 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) 290 if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0)
345 return 1; 291 return 1;