blob: bbc11744298bab249f587b4dee2734fcac458043 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/*
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-2006
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 <config.h>
31
32#ifdef SRTP_SUPPORT
33#include <ccrtp/crypto/hmac.h>
34#include <ccrtp/crypto/macSkein.h>
35#endif
36
37#include <ccrtp/CryptoContext.h>
38
39#ifdef CCXX_NAMESPACES
40namespace ost {
41#endif
42
43CryptoContext::CryptoContext( uint32 ssrc ):
44ssrc(ssrc),
45using_mki(false),mkiLength(0),mki(NULL),
46roc(0),guessed_roc(0),s_l(0),key_deriv_rate(0),
47replay_window(0),
48master_key(NULL), master_key_length(0),
49master_key_srtp_use_nb(0), master_key_srtcp_use_nb(0),
50master_salt(NULL), master_salt_length(0),
51n_e(0),k_e(NULL),n_a(0),k_a(NULL),n_s(0),k_s(NULL),
52ealg(SrtpEncryptionNull), aalg(SrtpAuthenticationNull),
53ekeyl(0), akeyl(0), skeyl(0),
54seqNumSet(false), cipher(NULL), f8Cipher(NULL)
55{}
56
57#ifdef SRTP_SUPPORT
58CryptoContext::CryptoContext( uint32 ssrc,
59 int32 roc,
60 int64 key_deriv_rate,
61 const int32 ealg,
62 const int32 aalg,
63 uint8* master_key,
64 int32 master_key_length,
65 uint8* master_salt,
66 int32 master_salt_length,
67 int32 ekeyl,
68 int32 akeyl,
69 int32 skeyl,
70 int32 tagLength):
71
72ssrc(ssrc),using_mki(false),mkiLength(0),mki(NULL),
73roc(roc),guessed_roc(0),s_l(0),key_deriv_rate(key_deriv_rate),
74replay_window(0),
75master_key_srtp_use_nb(0), master_key_srtcp_use_nb(0), seqNumSet(false),
76cipher(NULL), f8Cipher(NULL)
77{
78 this->ealg = ealg;
79 this->aalg = aalg;
80 this->ekeyl = ekeyl;
81 this->akeyl = akeyl;
82 this->skeyl = skeyl;
83
84 this->master_key_length = master_key_length;
85 this->master_key = new uint8[master_key_length];
86 memcpy(this->master_key, master_key, master_key_length);
87
88 this->master_salt_length = master_salt_length;
89 this->master_salt = new uint8[master_salt_length];
90 memcpy(this->master_salt, master_salt, master_salt_length);
91
92 switch( ealg ) {
93 case SrtpEncryptionNull:
94 n_e = 0;
95 k_e = NULL;
96 n_s = 0;
97 k_s = NULL;
98 break;
99
100 case SrtpEncryptionTWOF8:
101 f8Cipher = new AesSrtp(SrtpEncryptionTWOCM);
102
103 case SrtpEncryptionTWOCM:
104 n_e = ekeyl;
105 k_e = new uint8[n_e];
106 n_s = skeyl;
107 k_s = new uint8[n_s];
108 cipher = new AesSrtp(SrtpEncryptionTWOCM);
109 break;
110
111 case SrtpEncryptionAESF8:
112 f8Cipher = new AesSrtp(SrtpEncryptionAESCM);
113
114 case SrtpEncryptionAESCM:
115 n_e = ekeyl;
116 k_e = new uint8[n_e];
117 n_s = skeyl;
118 k_s = new uint8[n_s];
119 cipher = new AesSrtp(SrtpEncryptionAESCM);
120 break;
121 }
122
123 switch( aalg ) {
124 case SrtpAuthenticationNull:
125 n_a = 0;
126 k_a = NULL;
127 this->tagLength = 0;
128 break;
129
130 case SrtpAuthenticationSha1Hmac:
131 case SrtpAuthenticationSkeinHmac:
132 n_a = akeyl;
133 k_a = new uint8[n_a];
134 this->tagLength = tagLength;
135 break;
136 }
137}
138
139#endif
140
141CryptoContext::~CryptoContext(){
142
143 ealg = SrtpEncryptionNull;
144 aalg = SrtpAuthenticationNull;
145
146#ifdef SRTP_SUPPORT
147 if (mki)
148 delete [] mki;
149
150 if (master_key_length > 0) {
151 master_key_length = 0;
152 delete [] master_key;
153 }
154 if (master_salt_length > 0) {
155 master_salt_length = 0;
156 delete [] master_salt;
157 }
158 if (n_e > 0) {
159 n_e = 0;
160 delete [] k_e;
161 }
162 if (n_s > 0) {
163 n_s = 0;
164 delete [] k_s;
165 }
166 if (n_a > 0) {
167 n_a = 0;
168 delete [] k_a;
169 }
170 if (cipher != NULL) {
171 delete cipher;
172 cipher = NULL;
173 }
174 if (f8Cipher != NULL) {
175 delete f8Cipher;
176 f8Cipher = NULL;
177 }
178 if (macCtx != NULL) {
179 switch(aalg) {
180 case SrtpAuthenticationSha1Hmac:
181 freeSha1HmacContext(macCtx);
182 break;
183
184 case SrtpAuthenticationSkeinHmac:
185 freeSkeinMacContext(macCtx);
186 break;
187 }
188 }
189#endif
190}
191
192void CryptoContext::srtpEncrypt( RTPPacket* rtp, uint64 index, uint32 ssrc )
193{
194 if (ealg == SrtpEncryptionNull) {
195 return;
196 }
197#ifdef SRTP_SUPPORT
198 if (ealg == SrtpEncryptionAESCM) {
199
200 /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711):
201 *
202 * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX
203 * SSRC XX XX XX XX
204 * index XX XX XX XX XX XX
205 * ------------------------------------------------------XOR
206 * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
207 */
208
209 unsigned char iv[16];
210 memcpy( iv, k_s, 4 );
211
212 int i;
213 for(i = 4; i < 8; i++ ){
214 iv[i] = ( 0xFF & ( ssrc >> ((7-i)*8) ) ) ^ k_s[i];
215 }
216 for(i = 8; i < 14; i++ ){
217 iv[i] = ( 0xFF & (unsigned char)( index >> ((13-i)*8) ) ) ^ k_s[i];
218 }
219 iv[14] = iv[15] = 0;
220
221 int32 pad = rtp->isPadded() ? rtp->getPaddingSize() : 0;
222 cipher->ctr_encrypt( const_cast<uint8*>(rtp->getPayload()),
223 rtp->getPayloadSize()+pad, iv);
224 }
225
226 if (ealg == SrtpEncryptionAESF8) {
227
228 /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
229 *
230 * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
231 * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
232 * ------------\ /--------------------------------------------------
233 * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
234 */
235
236 unsigned char iv[16];
237 uint32 *ui32p = (uint32 *)iv;
238
239 memcpy(iv, rtp->getRawPacket(), 12);
240 iv[0] = 0;
241
242 // set ROC in network order into IV
243 ui32p[3] = htonl(roc);
244
245 int32 pad = rtp->isPadded() ? rtp->getPaddingSize() : 0;
246 cipher->f8_encrypt(rtp->getPayload(),
247 rtp->getPayloadSize()+pad,
248 iv, k_e, n_e, k_s, n_s, f8Cipher);
249 }
250#endif
251}
252
253/* Warning: tag must have been initialized */
254void CryptoContext::srtpAuthenticate(RTPPacket* rtp, uint32 roc, uint8* tag )
255{
256 if (aalg == SrtpAuthenticationNull) {
257 return;
258 }
259#ifdef SRTP_SUPPORT
260 int32_t macL;
261
262 unsigned char temp[20];
263 const unsigned char* chunks[3];
264 unsigned int chunkLength[3];
265 uint32_t beRoc = htonl(roc);
266
267 chunks[0] = rtp->getRawPacket();
268 chunkLength[0] = rtp->getRawPacketSize();
269
270 chunks[1] = (unsigned char *)&beRoc;
271 chunkLength[1] = 4;
272 chunks[2] = NULL;
273
274 switch (aalg) {
275 case SrtpAuthenticationSha1Hmac:
276 hmacSha1Ctx(macCtx,
277 chunks, // data chunks to hash
278 chunkLength, // length of the data to hash
279 temp, &macL);
280 /* truncate the result */
281 memcpy(tag, temp, getTagLength());
282 break;
283 case SrtpAuthenticationSkeinHmac:
284 macSkeinCtx(macCtx,
285 chunks, // data chunks to hash
286 chunkLength, // length of the data to hash
287 temp);
288 /* truncate the result */
289 memcpy(tag, temp, getTagLength());
290 break;
291 }
292#endif
293}
294
295#ifdef SRTP_SUPPORT
296/* used by the key derivation method */
297static void computeIv(unsigned char* iv, uint64 label, uint64 index,
298 int64 kdv, unsigned char* master_salt)
299{
300
301 uint64 key_id;
302
303 if (kdv == 0) {
304 key_id = label << 48;
305 }
306 else {
307 key_id = ((label << 48) | (index / kdv));
308 }
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 int i;
320 for(i = 0; i < 7 ; i++ ) {
321 iv[i] = master_salt[i];
322 }
323
324 for(i = 7; i < 14 ; i++ ) {
325 iv[i] = (unsigned char)(0xFF & (key_id >> (8*(13-i)))) ^
326 master_salt[i];
327 }
328
329 iv[14] = iv[15] = 0;
330}
331#endif
332
333/* Derives the srtp session keys from the master key */
334void CryptoContext::deriveSrtpKeys(uint64 index)
335{
336#ifdef SRTP_SUPPORT
337 uint8 iv[16];
338
339 // prepare AES cipher to compute derived keys.
340 cipher->setNewKey(master_key, master_key_length);
341
342 // compute the session encryption key
343 uint64 label = 0;
344 computeIv(iv, label, index, key_deriv_rate, master_salt);
345 cipher->get_ctr_cipher_stream(k_e, n_e, iv);
346
347 // compute the session authentication key
348 label = 0x01;
349 computeIv(iv, label, index, key_deriv_rate, master_salt);
350 cipher->get_ctr_cipher_stream(k_a, n_a, iv);
351 // Initialize MAC context with the derived key
352 switch (aalg) {
353 case SrtpAuthenticationSha1Hmac:
354 macCtx = createSha1HmacContext(k_a, n_a);
355 break;
356 case SrtpAuthenticationSkeinHmac:
357 // Skein MAC uses number of bits as MAC size, not just bytes
358 macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
359 break;
360 }
361 // compute the session salt
362 label = 0x02;
363 computeIv(iv, label, index, key_deriv_rate, master_salt);
364 cipher->get_ctr_cipher_stream(k_s, n_s, iv);
365
366 // as last step prepare AES cipher with derived key.
367 cipher->setNewKey(k_e, n_e);
368#endif
369}
370
371/* Based on the algorithm provided in Appendix A - draft-ietf-srtp-05.txt */
372uint64_t CryptoContext::guessIndex(uint16 new_seq_nb )
373{
374 /*
375 * Initialize the sequences number on first call that uses the
376 * sequence number. Either GuessIndex() or checkReplay().
377 */
378 if (!seqNumSet) {
379 seqNumSet = true;
380 s_l = new_seq_nb;
381 }
382 if (s_l < 32768){
383 if (new_seq_nb - s_l > 32768) {
384 guessed_roc = roc - 1;
385 }
386 else {
387 guessed_roc = roc;
388 }
389 }
390 else {
391 if (s_l - 32768 > new_seq_nb) {
392 guessed_roc = roc + 1;
393 }
394 else {
395 guessed_roc = roc;
396 }
397 }
398
399 return ((uint64)guessed_roc) << 16 | new_seq_nb;
400}
401
402bool CryptoContext::checkReplay( uint16 new_seq_nb )
403{
404#ifdef SRTP_SUPPORT
405 if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
406 /* No security policy, don't use the replay protection */
407 return true;
408 }
409
410 /*
411 * Initialize the sequences number on first call that uses the
412 * sequence number. Either guessIndex() or checkReplay().
413 */
414 if (!seqNumSet) {
415 seqNumSet = true;
416 s_l = new_seq_nb;
417 }
418 uint64 guessed_index = guessIndex( new_seq_nb );
419 uint64 local_index = (((uint64_t)roc) << 16) | s_l;
420
421 int64 delta = guessed_index - local_index;
422 if (delta > 0) {
423 /* Packet not yet received*/
424 return true;
425 }
426 else {
427 if( -delta > REPLAY_WINDOW_SIZE ) {
428 /* Packet too old */
429 return false;
430 }
431 else {
432 if((replay_window >> (-delta)) & 0x1) {
433 /* Packet already received ! */
434 return false;
435 }
436 else {
437 /* Packet not yet received */
438 return true;
439 }
440 }
441}
442#else
443 return true;
444#endif
445}
446
447void CryptoContext::update(uint16 new_seq_nb)
448{
449#ifdef SRTP_SUPPORT
450 int64 delta = guessIndex(new_seq_nb) - (((uint64)roc) << 16 | s_l );
451
452 /* update the replay bitmask */
453 if( delta > 0 ){
454 replay_window = replay_window << delta;
455 replay_window |= 1;
456 }
457 else {
458 replay_window |= ( 1 << delta );
459 }
460
461 /* update the locally stored ROC and highest sequence number */
462 if( new_seq_nb > s_l ) {
463 s_l = new_seq_nb;
464 }
465 if( guessed_roc > roc ) {
466 roc = guessed_roc;
467 s_l = new_seq_nb;
468 }
469#endif
470}
471
472CryptoContext* CryptoContext::newCryptoContextForSSRC(uint32 ssrc, int roc, int64 keyDerivRate)
473{
474#ifdef SRTP_SUPPORT
475 CryptoContext* pcc = new CryptoContext(
476 ssrc,
477 roc, // Roll over Counter,
478 keyDerivRate, // keyderivation << 48,
479 this->ealg, // encryption algo
480 this->aalg, // authentication algo
481 this->master_key, // Master Key
482 this->master_key_length, // Master Key length
483 this->master_salt, // Master Salt
484 this->master_salt_length, // Master Salt length
485 this->ekeyl, // encryption keyl
486 this->akeyl, // authentication key len
487 this->skeyl, // session salt len
488 this->tagLength); // authentication tag len
489
490 return pcc;
491#else
492 return NULL;
493#endif
494}
495
496#ifdef CCXX_NAMESPACES
497}
498#endif
499
500/** EMACS **
501 * Local variables:
502 * mode: c++
503 * c-default-style: ellemtel
504 * c-basic-offset: 4
505 * End:
506 */
507