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