diff options
Diffstat (limited to 'toxencryptsave/toxencryptsave.c')
-rw-r--r-- | toxencryptsave/toxencryptsave.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/toxencryptsave/toxencryptsave.c b/toxencryptsave/toxencryptsave.c new file mode 100644 index 00000000..89c47a03 --- /dev/null +++ b/toxencryptsave/toxencryptsave.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* toxencryptsave.c | ||
2 | * | ||
3 | * The Tox encrypted save functions. | ||
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifdef HAVE_CONFIG_H | ||
25 | #include "config.h" | ||
26 | #endif | ||
27 | |||
28 | #include "toxencryptsave.h" | ||
29 | #include "../toxcore/crypto_core.h" | ||
30 | |||
31 | #ifdef VANILLA_NACL | ||
32 | #include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h" | ||
33 | #include "crypto_pwhash_scryptsalsa208sha256/utils.h" /* sodium_memzero */ | ||
34 | #endif | ||
35 | |||
36 | /* This "module" provides functions analogous to tox_load and tox_save in toxcore | ||
37 | * Clients should consider alerting their users that, unlike plain data, if even one bit | ||
38 | * becomes corrupted, the data will be entirely unrecoverable. | ||
39 | * Ditto if they forget their password, there is no way to recover the data. | ||
40 | */ | ||
41 | |||
42 | /* return size of the messenger data (for encrypted saving). */ | ||
43 | uint32_t tox_encrypted_size(const Tox *tox) | ||
44 | { | ||
45 | return tox_size(tox) + crypto_box_MACBYTES + crypto_box_NONCEBYTES | ||
46 | + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH; | ||
47 | } | ||
48 | |||
49 | /* Save the messenger data encrypted with the given password. | ||
50 | * data must be at least tox_encrypted_size(). | ||
51 | * | ||
52 | * returns 0 on success | ||
53 | * returns -1 on failure | ||
54 | */ | ||
55 | int tox_encrypted_save(const Tox *tox, uint8_t *data, uint8_t *passphrase, uint32_t pplength) | ||
56 | { | ||
57 | if (pplength == 0) | ||
58 | return -1; | ||
59 | |||
60 | /* First derive a key from the password */ | ||
61 | /* http://doc.libsodium.org/key_derivation/README.html */ | ||
62 | /* note that, according to the documentation, a generic pwhash interface will be created | ||
63 | * once the pwhash competition (https://password-hashing.net/) is over */ | ||
64 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
65 | uint8_t key[crypto_box_KEYBYTES]; | ||
66 | randombytes(salt, sizeof salt); | ||
67 | |||
68 | if (crypto_pwhash_scryptsalsa208sha256( | ||
69 | key, sizeof(key), passphrase, pplength, salt, | ||
70 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ | ||
71 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { | ||
72 | /* out of memory most likely */ | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | /* calling sodium_memzero segfaults, but printing passphrase works, so... libsodium bug? | ||
77 | * ...eh, it's not segfaulting anywhere else, so I'll assume pebkac... | ||
78 | sodium_memzero(passphrase, pplength); /* wipe plaintext pw */ | ||
79 | |||
80 | /* next get plain save data */ | ||
81 | uint32_t temp_size = tox_size(tox); | ||
82 | uint8_t temp_data[temp_size]; | ||
83 | tox_save(tox, temp_data); | ||
84 | |||
85 | /* the output data consists of, in order: | ||
86 | * magic number, salt, nonce, mac, enc_data | ||
87 | * where the mac is automatically prepended by the encrypt() | ||
88 | * the magic+salt+nonce is called the prefix | ||
89 | * I'm not sure what else I'm supposed to do with the salt and nonce, since we | ||
90 | * need them to decrypt the data | ||
91 | */ | ||
92 | |||
93 | /* first add the prefix */ | ||
94 | uint8_t nonce[crypto_box_NONCEBYTES]; | ||
95 | random_nonce(nonce); | ||
96 | |||
97 | memcpy(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); | ||
98 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
99 | memcpy(data, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
100 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
101 | memcpy(data, nonce, crypto_box_NONCEBYTES); | ||
102 | data += crypto_box_NONCEBYTES; | ||
103 | |||
104 | /* now encrypt */ | ||
105 | if (encrypt_data_symmetric(key, nonce, temp_data, temp_size, data) | ||
106 | != temp_size + crypto_box_MACBYTES) { | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* Load the messenger from encrypted data of size length. | ||
114 | * | ||
115 | * returns 0 on success | ||
116 | * returns -1 on failure | ||
117 | */ | ||
118 | int tox_encrypted_load(Tox *tox, const uint8_t *data, uint32_t length, uint8_t *passphrase, uint32_t pplength) | ||
119 | { | ||
120 | if (length <= crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + | ||
121 | TOX_ENC_SAVE_MAGIC_LENGTH) | ||
122 | return -1; | ||
123 | |||
124 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) | ||
125 | return -1; | ||
126 | |||
127 | data += TOX_ENC_SAVE_MAGIC_LENGTH; | ||
128 | |||
129 | uint32_t decrypt_length = length - crypto_box_MACBYTES - crypto_box_NONCEBYTES | ||
130 | - crypto_pwhash_scryptsalsa208sha256_SALTBYTES - TOX_ENC_SAVE_MAGIC_LENGTH; | ||
131 | uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; | ||
132 | uint8_t nonce[crypto_box_NONCEBYTES]; | ||
133 | |||
134 | memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); | ||
135 | data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; | ||
136 | memcpy(nonce, data, crypto_box_NONCEBYTES); | ||
137 | data += crypto_box_NONCEBYTES; | ||
138 | |||
139 | /* derive the key */ | ||
140 | uint8_t key[crypto_box_KEYBYTES]; | ||
141 | |||
142 | if (crypto_pwhash_scryptsalsa208sha256( | ||
143 | key, sizeof(key), passphrase, pplength, salt, | ||
144 | crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ | ||
145 | crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { | ||
146 | /* out of memory most likely */ | ||
147 | return -1; | ||
148 | } | ||
149 | |||
150 | /* sodium_memzero(passphrase, pplength); /* wipe plaintext pw */ | ||
151 | |||
152 | /* decrypt the data */ | ||
153 | uint8_t temp_data[decrypt_length]; | ||
154 | |||
155 | if (decrypt_data_symmetric(key, nonce, data, decrypt_length + crypto_box_MACBYTES, temp_data) | ||
156 | != decrypt_length) { | ||
157 | return -1; | ||
158 | } | ||
159 | |||
160 | return tox_load(tox, temp_data, decrypt_length); | ||
161 | } | ||
162 | |||
163 | /* Determines whether or not the given data is encrypted (by checking the magic number) | ||
164 | * | ||
165 | * returns 1 if it is encrypted | ||
166 | * returns 0 otherwise | ||
167 | */ | ||
168 | int tox_is_data_encrypted(const uint8_t *data) | ||
169 | { | ||
170 | if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) | ||
171 | return 1; | ||
172 | else | ||
173 | return 0; | ||
174 | } | ||