diff options
Diffstat (limited to 'toxdns/toxdns.c')
-rw-r--r-- | toxdns/toxdns.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/toxdns/toxdns.c b/toxdns/toxdns.c new file mode 100644 index 00000000..31269c15 --- /dev/null +++ b/toxdns/toxdns.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* toxdns.c | ||
2 | * | ||
3 | * Tox secure username DNS toxid resolving 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 "../toxcore/Messenger.h" | ||
29 | |||
30 | static const char base32[32] = {"abcdefghijklmnopqrstuvwxyz012345"}; | ||
31 | |||
32 | #define _encode(a, b, c) \ | ||
33 | { \ | ||
34 | uint8_t i = 0; \ | ||
35 | while(i != c) { \ | ||
36 | *a++ = base32[((b[0] >> bits) | (b[1] << (8 - bits))) & 0x1F]; \ | ||
37 | bits += 5; \ | ||
38 | if(bits >= 8) { \ | ||
39 | bits -= 8; \ | ||
40 | b++; \ | ||
41 | i++; \ | ||
42 | } \ | ||
43 | } \ | ||
44 | } \ | ||
45 | |||
46 | typedef struct { | ||
47 | uint8_t temp_pk[crypto_box_PUBLICKEYBYTES]; | ||
48 | uint8_t temp_sk[crypto_box_SECRETKEYBYTES]; | ||
49 | uint8_t server_public_key[crypto_box_PUBLICKEYBYTES]; | ||
50 | uint8_t shared_key[crypto_box_KEYBYTES]; | ||
51 | uint32_t nonce; | ||
52 | uint32_t nonce_start; | ||
53 | } DNS_Object; | ||
54 | |||
55 | static void dns_new_temp_keys(DNS_Object *d) | ||
56 | { | ||
57 | d->nonce = d->nonce_start = random_int(); | ||
58 | crypto_box_keypair(d->temp_pk, d->temp_sk); | ||
59 | encrypt_precompute(d->server_public_key, d->temp_sk, d->shared_key); | ||
60 | } | ||
61 | |||
62 | /* Create a new tox_dns3 object for server with server_public_key. | ||
63 | * | ||
64 | * return Null on failure. | ||
65 | * return pointer object on success. | ||
66 | */ | ||
67 | void *tox_dns3_new(uint8_t *server_public_key) | ||
68 | { | ||
69 | DNS_Object *d = malloc(sizeof(DNS_Object)); | ||
70 | |||
71 | if (d == NULL) | ||
72 | return NULL; | ||
73 | |||
74 | memcpy(d->server_public_key, server_public_key, crypto_box_PUBLICKEYBYTES); | ||
75 | dns_new_temp_keys(d); | ||
76 | return d; | ||
77 | } | ||
78 | |||
79 | /* Destroy the tox dns3 object. | ||
80 | */ | ||
81 | void tox_dns3_kill(void *dns3_object) | ||
82 | { | ||
83 | memset(dns3_object, 0, sizeof(DNS_Object)); | ||
84 | free(dns3_object); | ||
85 | } | ||
86 | |||
87 | /* Generate a dns3 string of string_max_len used to query the dns server referred to by to | ||
88 | * dns3_object for a tox id registered to user with name of name_len. | ||
89 | * | ||
90 | * the uint32_t pointed by request_id will be set to the request id which must be passed to | ||
91 | * tox_decrypt_dns3_TXT() to correctly decode the response. | ||
92 | * | ||
93 | * This is what the string returned looks like: | ||
94 | * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc | ||
95 | * | ||
96 | * returns length of string on sucess. | ||
97 | * returns -1 on failure. | ||
98 | */ | ||
99 | int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, | ||
100 | uint8_t *name, uint8_t name_len) | ||
101 | { | ||
102 | #define DOT_INTERVAL (6 * 5) | ||
103 | int base = (sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + name_len + crypto_box_MACBYTES); | ||
104 | int end_len = ((base * 8) / 5) + (base / DOT_INTERVAL) + !!(base % 5); | ||
105 | end_len -= !(base % DOT_INTERVAL); | ||
106 | |||
107 | if (end_len > string_max_len) | ||
108 | return -1; | ||
109 | |||
110 | DNS_Object *d = dns3_object; | ||
111 | uint8_t buffer[1024]; | ||
112 | uint8_t nonce[crypto_box_NONCEBYTES] = {0}; | ||
113 | memcpy(nonce, &d->nonce, sizeof(uint32_t)); | ||
114 | memcpy(buffer, &d->nonce, sizeof(uint32_t)); | ||
115 | memcpy(buffer + sizeof(uint32_t), d->temp_pk, crypto_box_PUBLICKEYBYTES); | ||
116 | int len = encrypt_data_symmetric(d->shared_key, nonce, name, name_len, | ||
117 | buffer + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES); | ||
118 | |||
119 | if (len == -1) | ||
120 | return -1; | ||
121 | |||
122 | int total_len = len + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES; | ||
123 | uint8_t *buff = buffer, *old_str = string; | ||
124 | buffer[total_len] = 0; | ||
125 | uint8_t bits = 0; | ||
126 | int i; | ||
127 | |||
128 | for (i = !(total_len % DOT_INTERVAL); i < (total_len / DOT_INTERVAL); ++i) { | ||
129 | _encode(string, buff, DOT_INTERVAL); | ||
130 | *string = '.'; | ||
131 | ++string; | ||
132 | } | ||
133 | |||
134 | int left = total_len - (buff - buffer); | ||
135 | _encode(string, buff, left); | ||
136 | #undef DOT_INTERVAL | ||
137 | *request_id = d->nonce; | ||
138 | ++d->nonce; | ||
139 | |||
140 | if (d->nonce == d->nonce_start) { | ||
141 | dns_new_temp_keys(d); | ||
142 | } | ||
143 | |||
144 | if (end_len != string - old_str) { | ||
145 | printf("tox_generate_dns3_string Fail, %u != %u\n", end_len, string - old_str); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | return string - old_str; | ||
150 | } | ||
151 | |||
152 | |||
153 | static int decode(uint8_t *dest, uint8_t *src) | ||
154 | { | ||
155 | uint8_t *p = src, *op = dest, bits = 0; | ||
156 | *op = 0; | ||
157 | |||
158 | while (*p) { | ||
159 | uint8_t ch = *p++; | ||
160 | |||
161 | switch (ch) { | ||
162 | case 'A' ... 'Z': { | ||
163 | ch = ch - 'A'; | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | case 'a' ... 'z': { | ||
168 | ch = ch - 'a'; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | case '0' ... '5': { | ||
173 | ch = ch - '0' + 26; | ||
174 | break; | ||
175 | } | ||
176 | |||
177 | default: { | ||
178 | return - 1; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | *op |= (ch << bits); | ||
183 | bits += 5; | ||
184 | |||
185 | if (bits >= 8) { | ||
186 | bits -= 8; | ||
187 | ++op; | ||
188 | *op = (ch >> (5 - bits)); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return op - dest; | ||
193 | } | ||
194 | |||
195 | /* Decode and decrypt the id_record returned of length id_record_len into | ||
196 | * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE). | ||
197 | * | ||
198 | * request_id is the request id given by tox_generate_dns3_string() when creating the request. | ||
199 | * | ||
200 | * the id_record passed to this function should look somewhat like this: | ||
201 | * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp | ||
202 | * | ||
203 | * returns -1 on failure. | ||
204 | * returns 0 on success. | ||
205 | * | ||
206 | */ | ||
207 | int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, | ||
208 | uint32_t request_id) | ||
209 | { | ||
210 | DNS_Object *d = dns3_object; | ||
211 | |||
212 | if (id_record_len != 87) | ||
213 | return -1; | ||
214 | |||
215 | /*if (id_record_len > 255 || id_record_len <= (sizeof(uint32_t) + crypto_box_MACBYTES)) | ||
216 | return -1;*/ | ||
217 | |||
218 | uint8_t data[id_record_len]; | ||
219 | int length = decode(data, id_record); | ||
220 | |||
221 | if (length == -1) | ||
222 | return -1; | ||
223 | |||
224 | uint8_t nonce[crypto_box_NONCEBYTES] = {0}; | ||
225 | memcpy(nonce, &request_id, sizeof(uint32_t)); | ||
226 | nonce[sizeof(uint32_t)] = 1; | ||
227 | int len = decrypt_data_symmetric(d->shared_key, nonce, data, length, tox_id); | ||
228 | |||
229 | if (len != FRIEND_ADDRESS_SIZE) | ||
230 | return -1; | ||
231 | |||
232 | return 0; | ||
233 | } | ||