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