blob: 5eb34051b04306387367a77446823a96923cc537 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001/*
2 Copyright (C) 2004-2006 the Minisip Team
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18
19/* Copyright (C) 2004-2012
20 *
21 * Authors: Israel Abad <i_abad@terra.es>
22 * Erik Eliasson <eliasson@it.kth.se>
23 * Johan Bilien <jobi@via.ecp.fr>
24 * Joachim Orrblad <joachim@orrblad.com>
25 * Werner Dittmann <Werner.Dittmann@t-online.de>
26 */
27
28#include <iostream>
29
30#include <ccrtp-config.h>
31
32#ifdef SRTP_SUPPORT
33#include <ccrtp/crypto/hmac.h>
34#include <ccrtp/crypto/macSkein.h>
35#endif
36
37#include <commoncpp/config.h>
38#include <commoncpp/export.h>
39#include <ccrtp/CryptoContextCtrl.h>
40#include <ccrtp/base.h>
41
42NAMESPACE_COMMONCPP
43
44CryptoContextCtrl::CryptoContextCtrl(uint32 ssrc ):
45ssrcCtx(ssrc),
46using_mki(false),mkiLength(0),mki(NULL), s_l(0),
47replay_window(0),
48master_key(NULL), master_key_length(0),
49master_salt(NULL), master_salt_length(0),
50n_e(0),k_e(NULL),n_a(0),k_a(NULL),n_s(0),k_s(NULL),
51ealg(SrtpEncryptionNull), aalg(SrtpAuthenticationNull),
52ekeyl(0), akeyl(0), skeyl(0),
53macCtx(NULL), cipher(NULL), f8Cipher(NULL)
54{}
55
56#ifdef SRTP_SUPPORT
57CryptoContextCtrl::CryptoContextCtrl(uint32 ssrc,
58 const int32 ealg,
59 const int32 aalg,
60 uint8* master_key,
61 int32 master_key_length,
62 uint8* master_salt,
63 int32 master_salt_length,
64 int32 ekeyl,
65 int32 akeyl,
66 int32 skeyl,
67 int32 tagLength):
68
69ssrcCtx(ssrc),using_mki(false),mkiLength(0),mki(NULL),
70replay_window(0), macCtx(NULL), cipher(NULL), f8Cipher(NULL)
71{
72 this->ealg = ealg;
73 this->aalg = aalg;
74 this->ekeyl = ekeyl;
75 this->akeyl = akeyl;
76 this->skeyl = skeyl;
77
78 this->master_key_length = master_key_length;
79 this->master_key = new uint8[master_key_length];
80 memcpy(this->master_key, master_key, master_key_length);
81
82 this->master_salt_length = master_salt_length;
83 this->master_salt = new uint8[master_salt_length];
84 memcpy(this->master_salt, master_salt, master_salt_length);
85
86 switch( ealg ) {
87 case SrtpEncryptionNull:
88 n_e = 0;
89 k_e = NULL;
90 n_s = 0;
91 k_s = NULL;
92 break;
93
94 case SrtpEncryptionTWOF8:
95 f8Cipher = new SrtpSymCrypto(SrtpEncryptionTWOF8);
96 // fall through
97
98 case SrtpEncryptionTWOCM:
99 n_e = ekeyl;
100 k_e = new uint8[n_e];
101 n_s = skeyl;
102 k_s = new uint8[n_s];
103 cipher = new SrtpSymCrypto(SrtpEncryptionTWOCM);
104 break;
105
106 case SrtpEncryptionAESF8:
107 f8Cipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
108 // fall through
109
110 case SrtpEncryptionAESCM:
111 n_e = ekeyl;
112 k_e = new uint8[n_e];
113 n_s = skeyl;
114 k_s = new uint8[n_s];
115 cipher = new SrtpSymCrypto(SrtpEncryptionAESCM);
116 break;
117 }
118
119 switch( aalg ) {
120 case SrtpAuthenticationNull:
121 n_a = 0;
122 k_a = NULL;
123 this->tagLength = 0;
124 break;
125
126 case SrtpAuthenticationSha1Hmac:
127 case SrtpAuthenticationSkeinHmac:
128 n_a = akeyl;
129 k_a = new uint8[n_a];
130 this->tagLength = tagLength;
131 break;
132 }
133}
134
135#endif
136
137CryptoContextCtrl::~CryptoContextCtrl(){
138
139#ifdef SRTP_SUPPORT
140 if (mki)
141 delete [] mki;
142
143 if (master_key_length > 0) {
144 memset(master_key, 0, master_key_length);
145 master_key_length = 0;
146 delete [] master_key;
147 }
148 if (master_salt_length > 0) {
149 memset(master_salt, 0, master_salt_length);
150 master_salt_length = 0;
151 delete [] master_salt;
152 }
153 if (n_e > 0) {
154 memset(k_e, 0, n_e);
155 n_e = 0;
156 delete [] k_e;
157 }
158 if (n_s > 0) {
159 memset(k_s, 0, n_s);
160 n_s = 0;
161 delete [] k_s;
162 }
163 if (n_a > 0) {
164 memset(k_a, 0, n_a);
165 n_a = 0;
166 delete [] k_a;
167 }
168 if (cipher != NULL) {
169 delete cipher;
170 cipher = NULL;
171 }
172 if (f8Cipher != NULL) {
173 delete f8Cipher;
174 f8Cipher = NULL;
175 }
176 if (macCtx != NULL) {
177 switch(aalg) {
178 case SrtpAuthenticationSha1Hmac:
179 freeSha1HmacContext(macCtx);
180 break;
181
182 case SrtpAuthenticationSkeinHmac:
183 freeSkeinMacContext(macCtx);
184 break;
185 }
186 }
187#endif
188
189 ealg = SrtpEncryptionNull;
190 aalg = SrtpAuthenticationNull;
191}
192
193void CryptoContextCtrl::srtcpEncrypt( uint8* rtp, size_t len, uint64 index, uint32 ssrc )
194{
195 if (ealg == SrtpEncryptionNull) {
196 return;
197 }
198#ifdef SRTP_SUPPORT
199 if (ealg == SrtpEncryptionAESCM || ealg == SrtpEncryptionTWOCM) {
200
201 /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711):
202 *
203 * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX
204 * SSRC XX XX XX XX
205 * index XX XX XX XX
206 * ------------------------------------------------------XOR
207 * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
208 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
209 */
210 unsigned char iv[16];
211
212 iv[0] = k_s[0];
213 iv[1] = k_s[1];
214 iv[2] = k_s[2];
215 iv[3] = k_s[3];
216
217 // The shifts transform the ssrc and index into network order
218 iv[4] = ((ssrc >> 24) & 0xff) ^ k_s[4];
219 iv[5] = ((ssrc >> 16) & 0xff) ^ k_s[5];
220 iv[6] = ((ssrc >> 8) & 0xff) ^ k_s[6];
221 iv[7] = (ssrc & 0xff) ^ k_s[7];
222
223 iv[8] = k_s[8];
224 iv[9] = k_s[9];
225
226 iv[10] = ((index >> 24) & 0xff) ^ k_s[10];
227 iv[11] = ((index >> 16) & 0xff) ^ k_s[11];
228 iv[12] = ((index >> 8) & 0xff) ^ k_s[12];
229 iv[13] = (index & 0xff) ^ k_s[13];
230
231 iv[14] = iv[15] = 0;
232
233 cipher->ctr_encrypt(rtp, len, iv);
234 }
235
236 if (ealg == SrtpEncryptionAESF8 || ealg == SrtpEncryptionTWOF8) {
237
238 unsigned char iv[16];
239
240 // 4 bytes of the iv are zero
241 // the first byte of the RTP header is not used.
242 iv[0] = 0;
243 iv[1] = 0;
244 iv[2] = 0;
245 iv[3] = 0;
246
247 // Need the encryption flag
248 index = index | 0x80000000;
249
250 // set the index and the encrypt flag in network order into IV
251 iv[4] = index >> 24;
252 iv[5] = index >> 16;
253 iv[6] = index >> 8;
254 iv[7] = index;
255
256 // The fixed header follows and fills the rest of the IV
257 memcpy(iv+8, rtp, 8);
258
259 cipher->f8_encrypt(rtp, len, iv, f8Cipher);
260 }
261#endif
262}
263
264/* Warning: tag must have been initialized */
265void CryptoContextCtrl::srtcpAuthenticate(uint8* rtp, size_t len, uint32 index, uint8* tag )
266{
267 if (aalg == SrtpAuthenticationNull) {
268 return;
269 }
270#ifdef SRTP_SUPPORT
271 int32_t macL;
272
273 unsigned char temp[20];
274 const unsigned char* chunks[3];
275 unsigned int chunkLength[3];
276 uint32_t beIndex = htonl(index);
277
278 chunks[0] = rtp;
279 chunkLength[0] = len;
280
281 chunks[1] = (unsigned char *)&beIndex;
282 chunkLength[1] = 4;
283 chunks[2] = NULL;
284
285 switch (aalg) {
286 case SrtpAuthenticationSha1Hmac:
287 hmacSha1Ctx(macCtx,
288 chunks, // data chunks to hash
289 chunkLength, // length of the data to hash
290 temp, &macL);
291 /* truncate the result */
292 memcpy(tag, temp, getTagLength());
293 break;
294 case SrtpAuthenticationSkeinHmac:
295 macSkeinCtx(macCtx,
296 chunks, // data chunks to hash
297 chunkLength, // length of the data to hash
298 temp);
299 /* truncate the result */
300 memcpy(tag, temp, getTagLength());
301 break;
302 }
303#endif
304}
305
306#ifdef SRTP_SUPPORT
307/* used by the key derivation method */
308static void computeIv(unsigned char* iv, uint8 label, uint8* master_salt)
309{
310 //printf( "Key_ID: %llx\n", key_id );
311
312 /* compute the IV
313 key_id: XX XX XX XX XX XX XX
314 master_salt: XX XX XX XX XX XX XX XX XX XX XX XX XX XX
315 ------------------------------------------------------------ XOR
316 IV: XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
317 */
318
319 memcpy(iv, master_salt, 14);
320 iv[7] ^= label;
321
322 iv[14] = iv[15] = 0;
323}
324#endif
325
326/* Derives the srtp session keys from the master key */
327void CryptoContextCtrl::deriveSrtcpKeys()
328{
329#ifdef SRTP_SUPPORT
330 uint8 iv[16];
331
332 // prepare AES cipher to compute derived keys.
333 cipher->setNewKey(master_key, master_key_length);
334 memset(master_key, 0, master_key_length);
335
336 // compute the session encryption key
337 uint8 label = 3;
338 computeIv(iv, label, master_salt);
339 cipher->get_ctr_cipher_stream(k_e, n_e, iv);
340
341 // compute the session authentication key
342 label = 4;
343 computeIv(iv, label, master_salt);
344 cipher->get_ctr_cipher_stream(k_a, n_a, iv);
345
346 // Initialize MAC context with the derived key
347 switch (aalg) {
348 case SrtpAuthenticationSha1Hmac:
349 macCtx = createSha1HmacContext(k_a, n_a);
350 break;
351 case SrtpAuthenticationSkeinHmac:
352 // Skein MAC uses number of bits as MAC size, not just bytes
353 macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
354 break;
355 }
356 memset(k_a, 0, n_a);
357
358 // compute the session salt
359 label = 5;
360 computeIv(iv, label, master_salt);
361 cipher->get_ctr_cipher_stream(k_s, n_s, iv);
362 memset(master_salt, 0, master_salt_length);
363
364 // as last step prepare ciphers with derived key.
365 cipher->setNewKey(k_e, n_e);
366 if (f8Cipher != NULL)
367 cipher->f8_deriveForIV(f8Cipher, k_e, n_e, k_s, n_s);
368 memset(k_e, 0, n_e);
369#endif
370}
371
372bool CryptoContextCtrl::checkReplay( uint32 index )
373{
374#ifdef SRTP_SUPPORT
375 if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
376 /* No security policy, don't use the replay protection */
377 return true;
378 }
379
380 int64 delta = s_l - index;
381 if (delta > 0) {
382 /* Packet not yet received*/
383 return true;
384 }
385 else {
386 if( -delta > REPLAY_WINDOW_SIZE ) {
387 /* Packet too old */
388 return false;
389 }
390 else {
391 if((replay_window >> (-delta)) & 0x1) {
392 /* Packet already received ! */
393 return false;
394 }
395 else {
396 /* Packet not yet received */
397 return true;
398 }
399 }
400}
401#else
402 return true;
403#endif
404}
405
406void CryptoContextCtrl::update(uint32 index)
407{
408#ifdef SRTP_SUPPORT
409 int64 delta = index - s_l;
410
411 /* update the replay bitmask */
412 if( delta > 0 ){
413 replay_window = replay_window << delta;
414 replay_window |= 1;
415 }
416 else {
417 replay_window |= ( 1 << delta );
418 }
419 s_l = index;
420
421#endif
422}
423
424CryptoContextCtrl* CryptoContextCtrl::newCryptoContextForSSRC(uint32 ssrc)
425{
426#ifdef SRTP_SUPPORT
427 CryptoContextCtrl* pcc = new CryptoContextCtrl(
428 ssrc,
429 this->ealg, // encryption algo
430 this->aalg, // authentication algo
431 this->master_key, // Master Key
432 this->master_key_length, // Master Key length
433 this->master_salt, // Master Salt
434 this->master_salt_length, // Master Salt length
435 this->ekeyl, // encryption keyl
436 this->akeyl, // authentication key len
437 this->skeyl, // session salt len
438 this->tagLength); // authentication tag len
439
440 return pcc;
441#else
442 return NULL;
443#endif
444}
445
446END_NAMESPACE
447
448/** EMACS **
449 * Local variables:
450 * mode: c++
451 * c-default-style: ellemtel
452 * c-basic-offset: 4
453 * End:
454 */
455