1 /*
2 * Off-the-Record Messaging library
3 * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits,
4 * Chris Alexander, Willy Lew, Lisa Du,
5 * Nikita Borisov
6 * <otr@cypherpunks.ca>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of version 2.1 of the GNU Lesser General
10 * Public License as published by the Free Software Foundation.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /* system headers */
23 #include <stdlib.h>
24
25 /* libgcrypt headers */
26 #include <gcrypt.h>
27
28 /* libotr headers */
29 #include "dh.h"
30
31
32 static const char* DH1536_MODULUS_S = "0x"
33 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
34 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
35 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
36 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
37 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
38 "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
39 "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
40 "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
41 static const char *DH1536_GENERATOR_S = "0x02";
42 static const int DH1536_MOD_LEN_BITS = 1536;
43 static const int DH1536_MOD_LEN_BYTES = 192;
44
45 static gcry_mpi_t DH1536_MODULUS = NULL;
46 static gcry_mpi_t DH1536_MODULUS_MINUS_2 = NULL;
47 static gcry_mpi_t DH1536_GENERATOR = NULL;
48
49 /*
50 * Call this once, at plugin load time. It sets up the modulus and
51 * generator MPIs.
52 */
otrl_dh_init(void)53 void otrl_dh_init(void)
54 {
55 gcry_mpi_scan(&DH1536_MODULUS, GCRYMPI_FMT_HEX,
56 (const unsigned char *)DH1536_MODULUS_S, 0, NULL);
57 gcry_mpi_scan(&DH1536_GENERATOR, GCRYMPI_FMT_HEX,
58 (const unsigned char *)DH1536_GENERATOR_S, 0, NULL);
59 DH1536_MODULUS_MINUS_2 = gcry_mpi_new(DH1536_MOD_LEN_BITS);
60 gcry_mpi_sub_ui(DH1536_MODULUS_MINUS_2, DH1536_MODULUS, 2);
61 }
62
63 /*
64 * Initialize the fields of a DH keypair.
65 */
otrl_dh_keypair_init(DH_keypair * kp)66 void otrl_dh_keypair_init(DH_keypair *kp)
67 {
68 kp->groupid = 0;
69 kp->priv = NULL;
70 kp->pub = NULL;
71 }
72
73 /*
74 * Copy a DH_keypair.
75 */
otrl_dh_keypair_copy(DH_keypair * dst,const DH_keypair * src)76 void otrl_dh_keypair_copy(DH_keypair *dst, const DH_keypair *src)
77 {
78 dst->groupid = src->groupid;
79 dst->priv = gcry_mpi_copy(src->priv);
80 dst->pub = gcry_mpi_copy(src->pub);
81 }
82
83 /*
84 * Deallocate the contents of a DH_keypair (but not the DH_keypair
85 * itself)
86 */
otrl_dh_keypair_free(DH_keypair * kp)87 void otrl_dh_keypair_free(DH_keypair *kp)
88 {
89 gcry_mpi_release(kp->priv);
90 gcry_mpi_release(kp->pub);
91 kp->priv = NULL;
92 kp->pub = NULL;
93 }
94
95 /*
96 * Generate a DH keypair for a specified group.
97 */
otrl_dh_gen_keypair(unsigned int groupid,DH_keypair * kp)98 gcry_error_t otrl_dh_gen_keypair(unsigned int groupid, DH_keypair *kp)
99 {
100 unsigned char *secbuf = NULL;
101 gcry_mpi_t privkey = NULL;
102
103 if (groupid != DH1536_GROUP_ID) {
104 /* Invalid group id */
105 return gcry_error(GPG_ERR_INV_VALUE);
106 }
107
108 /* Generate the secret key: a random 320-bit value */
109 secbuf = gcry_random_bytes_secure(40, GCRY_STRONG_RANDOM);
110 gcry_mpi_scan(&privkey, GCRYMPI_FMT_USG, secbuf, 40, NULL);
111 gcry_free(secbuf);
112
113 kp->groupid = groupid;
114 kp->priv = privkey;
115 kp->pub = gcry_mpi_new(DH1536_MOD_LEN_BITS);
116 gcry_mpi_powm(kp->pub, DH1536_GENERATOR, privkey, DH1536_MODULUS);
117 return gcry_error(GPG_ERR_NO_ERROR);
118 }
119
120 /*
121 * Construct session keys from a DH keypair and someone else's public
122 * key.
123 */
otrl_dh_session(DH_sesskeys * sess,const DH_keypair * kp,gcry_mpi_t y)124 gcry_error_t otrl_dh_session(DH_sesskeys *sess, const DH_keypair *kp,
125 gcry_mpi_t y)
126 {
127 gcry_mpi_t gab;
128 size_t gablen;
129 unsigned char *gabdata;
130 unsigned char *hashdata;
131 unsigned char sendbyte, rcvbyte;
132 gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
133
134 otrl_dh_session_blank(sess);
135
136 if (kp->groupid != DH1536_GROUP_ID) {
137 /* Invalid group id */
138 return gcry_error(GPG_ERR_INV_VALUE);
139 }
140
141 /* Calculate the shared secret MPI */
142 gab = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
143 gcry_mpi_powm(gab, y, kp->priv, DH1536_MODULUS);
144
145 /* Output it in the right format */
146 gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &gablen, gab);
147 gabdata = gcry_malloc_secure(gablen + 5);
148 if (!gabdata) {
149 gcry_mpi_release(gab);
150 return gcry_error(GPG_ERR_ENOMEM);
151 }
152 gabdata[1] = (gablen >> 24) & 0xff;
153 gabdata[2] = (gablen >> 16) & 0xff;
154 gabdata[3] = (gablen >> 8) & 0xff;
155 gabdata[4] = gablen & 0xff;
156 gcry_mpi_print(GCRYMPI_FMT_USG, gabdata+5, gablen, NULL, gab);
157 gcry_mpi_release(gab);
158
159 hashdata = gcry_malloc_secure(20);
160 if (!hashdata) {
161 gcry_free(gabdata);
162 return gcry_error(GPG_ERR_ENOMEM);
163 }
164
165 /* Are we the "high" or "low" end of the connection? */
166 if ( gcry_mpi_cmp(kp->pub, y) > 0 ) {
167 sendbyte = 0x01;
168 rcvbyte = 0x02;
169 } else {
170 sendbyte = 0x02;
171 rcvbyte = 0x01;
172 }
173
174 /* Calculate the sending encryption key */
175 gabdata[0] = sendbyte;
176 gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5);
177 err = gcry_cipher_open(&(sess->sendenc), GCRY_CIPHER_AES,
178 GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
179 if (err) goto err;
180 err = gcry_cipher_setkey(sess->sendenc, hashdata, 16);
181 if (err) goto err;
182
183 /* Calculate the sending MAC key */
184 gcry_md_hash_buffer(GCRY_MD_SHA1, sess->sendmackey, hashdata, 16);
185 err = gcry_md_open(&(sess->sendmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
186 if (err) goto err;
187 err = gcry_md_setkey(sess->sendmac, sess->sendmackey, 20);
188 if (err) goto err;
189
190 /* Calculate the receiving encryption key */
191 gabdata[0] = rcvbyte;
192 gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, gabdata, gablen+5);
193 err = gcry_cipher_open(&(sess->rcvenc), GCRY_CIPHER_AES,
194 GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
195 if (err) goto err;
196 err = gcry_cipher_setkey(sess->rcvenc, hashdata, 16);
197 if (err) goto err;
198
199 /* Calculate the receiving MAC key (and save it in the DH_sesskeys
200 * struct, so we can reveal it later) */
201 gcry_md_hash_buffer(GCRY_MD_SHA1, sess->rcvmackey, hashdata, 16);
202 err = gcry_md_open(&(sess->rcvmac), GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
203 if (err) goto err;
204 err = gcry_md_setkey(sess->rcvmac, sess->rcvmackey, 20);
205 if (err) goto err;
206
207 /* Calculate the extra key (used if applications wish to extract a
208 * symmetric key for transferring files, or something like that) */
209 gabdata[0] = 0xff;
210 gcry_md_hash_buffer(GCRY_MD_SHA256, sess->extrakey, gabdata, gablen+5);
211
212 gcry_free(gabdata);
213 gcry_free(hashdata);
214 return gcry_error(GPG_ERR_NO_ERROR);
215 err:
216 otrl_dh_session_free(sess);
217 gcry_free(gabdata);
218 gcry_free(hashdata);
219 return err;
220 }
221
222 /*
223 * Compute the secure session id, two encryption keys, and four MAC keys
224 * given our DH key and their DH public key.
225 */
otrl_dh_compute_v2_auth_keys(const DH_keypair * our_dh,gcry_mpi_t their_pub,unsigned char * sessionid,size_t * sessionidlenp,gcry_cipher_hd_t * enc_c,gcry_cipher_hd_t * enc_cp,gcry_md_hd_t * mac_m1,gcry_md_hd_t * mac_m1p,gcry_md_hd_t * mac_m2,gcry_md_hd_t * mac_m2p)226 gcry_error_t otrl_dh_compute_v2_auth_keys(const DH_keypair *our_dh,
227 gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
228 gcry_cipher_hd_t *enc_c, gcry_cipher_hd_t *enc_cp,
229 gcry_md_hd_t *mac_m1, gcry_md_hd_t *mac_m1p,
230 gcry_md_hd_t *mac_m2, gcry_md_hd_t *mac_m2p)
231 {
232 gcry_mpi_t s;
233 size_t slen;
234 unsigned char *sdata;
235 unsigned char *hashdata;
236 unsigned char ctr[16];
237 gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
238
239 *enc_c = NULL;
240 *enc_cp = NULL;
241 *mac_m1 = NULL;
242 *mac_m1p = NULL;
243 *mac_m2 = NULL;
244 *mac_m2p = NULL;
245 memset(ctr, 0, 16);
246
247 if (our_dh->groupid != DH1536_GROUP_ID) {
248 /* Invalid group id */
249 return gcry_error(GPG_ERR_INV_VALUE);
250 }
251
252 /* Check that their_pub is in range */
253 if (gcry_mpi_cmp_ui(their_pub, 2) < 0 ||
254 gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) {
255 /* Invalid pubkey */
256 return gcry_error(GPG_ERR_INV_VALUE);
257 }
258
259 /* Calculate the shared secret MPI */
260 s = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
261 gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS);
262
263 /* Output it in the right format */
264 gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s);
265 sdata = gcry_malloc_secure(slen + 5);
266 if (!sdata) {
267 gcry_mpi_release(s);
268 return gcry_error(GPG_ERR_ENOMEM);
269 }
270 sdata[1] = (slen >> 24) & 0xff;
271 sdata[2] = (slen >> 16) & 0xff;
272 sdata[3] = (slen >> 8) & 0xff;
273 sdata[4] = slen & 0xff;
274 gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s);
275 gcry_mpi_release(s);
276
277 /* Calculate the session id */
278 hashdata = gcry_malloc_secure(32);
279 if (!hashdata) {
280 gcry_free(sdata);
281 return gcry_error(GPG_ERR_ENOMEM);
282 }
283 sdata[0] = 0x00;
284 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
285 memmove(sessionid, hashdata, 8);
286 *sessionidlenp = 8;
287
288 /* Calculate the encryption keys */
289 sdata[0] = 0x01;
290 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
291
292 err = gcry_cipher_open(enc_c, GCRY_CIPHER_AES,
293 GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
294 if (err) goto err;
295 err = gcry_cipher_setkey(*enc_c, hashdata, 16);
296 if (err) goto err;
297 err = gcry_cipher_setctr(*enc_c, ctr, 16);
298 if (err) goto err;
299
300 err = gcry_cipher_open(enc_cp, GCRY_CIPHER_AES,
301 GCRY_CIPHER_MODE_CTR, GCRY_CIPHER_SECURE);
302 if (err) goto err;
303 err = gcry_cipher_setkey(*enc_cp, hashdata+16, 16);
304 if (err) goto err;
305 err = gcry_cipher_setctr(*enc_cp, ctr, 16);
306 if (err) goto err;
307
308 /* Calculate the MAC keys */
309 sdata[0] = 0x02;
310 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
311 err = gcry_md_open(mac_m1, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
312 if (err) goto err;
313 err = gcry_md_setkey(*mac_m1, hashdata, 32);
314 if (err) goto err;
315
316 sdata[0] = 0x03;
317 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
318 err = gcry_md_open(mac_m2, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
319 if (err) goto err;
320 err = gcry_md_setkey(*mac_m2, hashdata, 32);
321 if (err) goto err;
322
323 sdata[0] = 0x04;
324 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
325 err = gcry_md_open(mac_m1p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
326 if (err) goto err;
327 err = gcry_md_setkey(*mac_m1p, hashdata, 32);
328 if (err) goto err;
329
330 sdata[0] = 0x05;
331 gcry_md_hash_buffer(GCRY_MD_SHA256, hashdata, sdata, slen+5);
332 err = gcry_md_open(mac_m2p, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
333 if (err) goto err;
334 err = gcry_md_setkey(*mac_m2p, hashdata, 32);
335 if (err) goto err;
336
337 gcry_free(sdata);
338 gcry_free(hashdata);
339 return gcry_error(GPG_ERR_NO_ERROR);
340
341 err:
342 gcry_cipher_close(*enc_c);
343 gcry_cipher_close(*enc_cp);
344 gcry_md_close(*mac_m1);
345 gcry_md_close(*mac_m1p);
346 gcry_md_close(*mac_m2);
347 gcry_md_close(*mac_m2p);
348 *enc_c = NULL;
349 *enc_cp = NULL;
350 *mac_m1 = NULL;
351 *mac_m1p = NULL;
352 *mac_m2 = NULL;
353 *mac_m2p = NULL;
354 gcry_free(sdata);
355 gcry_free(hashdata);
356 return err;
357 }
358
359 /*
360 * Compute the secure session id, given our DH key and their DH public
361 * key.
362 */
otrl_dh_compute_v1_session_id(const DH_keypair * our_dh,gcry_mpi_t their_pub,unsigned char * sessionid,size_t * sessionidlenp,OtrlSessionIdHalf * halfp)363 gcry_error_t otrl_dh_compute_v1_session_id(const DH_keypair *our_dh,
364 gcry_mpi_t their_pub, unsigned char *sessionid, size_t *sessionidlenp,
365 OtrlSessionIdHalf *halfp)
366 {
367 gcry_mpi_t s;
368 size_t slen;
369 unsigned char *sdata;
370 unsigned char *hashdata;
371
372 if (our_dh->groupid != DH1536_GROUP_ID) {
373 /* Invalid group id */
374 return gcry_error(GPG_ERR_INV_VALUE);
375 }
376
377 /* Check that their_pub is in range */
378 if (gcry_mpi_cmp_ui(their_pub, 2) < 0 ||
379 gcry_mpi_cmp(their_pub, DH1536_MODULUS_MINUS_2) > 0) {
380 /* Invalid pubkey */
381 return gcry_error(GPG_ERR_INV_VALUE);
382 }
383
384 /* Calculate the shared secret MPI */
385 s = gcry_mpi_snew(DH1536_MOD_LEN_BITS);
386 gcry_mpi_powm(s, their_pub, our_dh->priv, DH1536_MODULUS);
387
388 /* Output it in the right format */
389 gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &slen, s);
390 sdata = gcry_malloc_secure(slen + 5);
391 if (!sdata) {
392 gcry_mpi_release(s);
393 return gcry_error(GPG_ERR_ENOMEM);
394 }
395 sdata[1] = (slen >> 24) & 0xff;
396 sdata[2] = (slen >> 16) & 0xff;
397 sdata[3] = (slen >> 8) & 0xff;
398 sdata[4] = slen & 0xff;
399 gcry_mpi_print(GCRYMPI_FMT_USG, sdata+5, slen, NULL, s);
400 gcry_mpi_release(s);
401
402 /* Calculate the session id */
403 hashdata = gcry_malloc_secure(20);
404 if (!hashdata) {
405 gcry_free(sdata);
406 return gcry_error(GPG_ERR_ENOMEM);
407 }
408 sdata[0] = 0x00;
409 gcry_md_hash_buffer(GCRY_MD_SHA1, hashdata, sdata, slen+5);
410 memmove(sessionid, hashdata, 20);
411 *sessionidlenp = 20;
412
413 /* Which half should be bold? */
414 if (gcry_mpi_cmp(our_dh->pub, their_pub) > 0) {
415 *halfp = OTRL_SESSIONID_SECOND_HALF_BOLD;
416 } else {
417 *halfp = OTRL_SESSIONID_FIRST_HALF_BOLD;
418 }
419
420 gcry_free(hashdata);
421 gcry_free(sdata);
422 return gcry_error(GPG_ERR_NO_ERROR);
423 }
424
425 /*
426 * Deallocate the contents of a DH_sesskeys (but not the DH_sesskeys
427 * itself)
428 */
otrl_dh_session_free(DH_sesskeys * sess)429 void otrl_dh_session_free(DH_sesskeys *sess)
430 {
431 gcry_cipher_close(sess->sendenc);
432 gcry_cipher_close(sess->rcvenc);
433 gcry_md_close(sess->sendmac);
434 gcry_md_close(sess->rcvmac);
435
436 otrl_dh_session_blank(sess);
437 }
438
439 /*
440 * Blank out the contents of a DH_sesskeys (without releasing it)
441 */
otrl_dh_session_blank(DH_sesskeys * sess)442 void otrl_dh_session_blank(DH_sesskeys *sess)
443 {
444 sess->sendenc = NULL;
445 sess->sendmac = NULL;
446 sess->rcvenc = NULL;
447 sess->rcvmac = NULL;
448 memset(sess->sendctr, 0, 16);
449 memset(sess->rcvctr, 0, 16);
450 memset(sess->sendmackey, 0, 20);
451 memset(sess->rcvmackey, 0, 20);
452 sess->sendmacused = 0;
453 sess->rcvmacused = 0;
454 memset(sess->extrakey, 0, OTRL_EXTRAKEY_BYTES);
455 }
456
457 /* Increment the top half of a counter block */
otrl_dh_incctr(unsigned char * ctr)458 void otrl_dh_incctr(unsigned char *ctr)
459 {
460 int i;
461 for (i=8;i;--i) {
462 if (++ctr[i-1]) break;
463 }
464 }
465
466 /* Compare two counter values (8 bytes each). Return 0 if ctr1 == ctr2,
467 * < 0 if ctr1 < ctr2 (as unsigned 64-bit values), > 0 if ctr1 > ctr2. */
otrl_dh_cmpctr(const unsigned char * ctr1,const unsigned char * ctr2)468 int otrl_dh_cmpctr(const unsigned char *ctr1, const unsigned char *ctr2)
469 {
470 int i;
471 for (i=0;i<8;++i) {
472 int c = ctr1[i] - ctr2[i];
473 if (c) return c;
474 }
475 return 0;
476 }
477