blob: 89eb699d7ab265c1610f6e69d0c558f017ae9f1a [file] [log] [blame]
Alexandre Lision51140e12013-12-02 10:54:09 -05001/*
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -05002 Copyright (C) 2006 - 2012 Werner Dittmann
3
Alexandre Lision51140e12013-12-02 10:54:09 -05004 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
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050019/*
20 * @author Werner Dittmann <Werner.Dittmann@t-online.de>
Alexandre Lision51140e12013-12-02 10:54:09 -050021 */
22
23#include <string.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050024#include <stdio.h>
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050025#include <stdint.h>
26
27#include <common/osSpecifics.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050028
29#include <CryptoContext.h>
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050030#include <crypto/SrtpSymCrypto.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050031#include <crypto/hmac.h>
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050032#include <cryptcommon/macSkein.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050033
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
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050048 ssrcCtx(ssrc),using_mki(false),mkiLength(0),mki(NULL), roc(roc),guessed_roc(0),
49 s_l(0),key_deriv_rate(key_deriv_rate), replay_window(0), master_key_srtp_use_nb(0),
50 master_key_srtcp_use_nb(0), labelBase(0), seqNumSet(false), macCtx(NULL), cipher(NULL),
51 f8Cipher(NULL)
Alexandre Lision51140e12013-12-02 10:54:09 -050052{
53 this->ealg = ealg;
54 this->aalg = aalg;
55 this->ekeyl = ekeyl;
56 this->akeyl = akeyl;
57 this->skeyl = skeyl;
58
59 this->master_key_length = master_key_length;
60 this->master_key = new uint8_t[master_key_length];
61 memcpy(this->master_key, master_key, master_key_length);
62
63 this->master_salt_length = master_salt_length;
64 this->master_salt = new uint8_t[master_salt_length];
65 memcpy(this->master_salt, master_salt, master_salt_length);
66
67 switch (ealg) {
68 case SrtpEncryptionNull:
69 n_e = 0;
70 k_e = NULL;
71 n_s = 0;
72 k_s = NULL;
73 break;
74
75 case SrtpEncryptionTWOF8:
76 f8Cipher = new SrtpSymCrypto(SrtpEncryptionTWOF8);
77
78 case SrtpEncryptionTWOCM:
79 n_e = ekeyl;
80 k_e = new uint8_t[n_e];
81 n_s = skeyl;
82 k_s = new uint8_t[n_s];
83 cipher = new SrtpSymCrypto(SrtpEncryptionTWOCM);
84 break;
85
86 case SrtpEncryptionAESF8:
87 f8Cipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
88
89 case SrtpEncryptionAESCM:
90 n_e = ekeyl;
91 k_e = new uint8_t[n_e];
92 n_s = skeyl;
93 k_s = new uint8_t[n_s];
94 cipher = new SrtpSymCrypto(SrtpEncryptionAESCM);
95 break;
96 }
97
98 switch (aalg ) {
99 case SrtpAuthenticationNull:
100 n_a = 0;
101 k_a = NULL;
102 this->tagLength = 0;
103 break;
104
105 case SrtpAuthenticationSha1Hmac:
106 case SrtpAuthenticationSkeinHmac:
107 n_a = akeyl;
108 k_a = new uint8_t[n_a];
109 this->tagLength = tagLength;
110 break;
111 }
112}
113
114CryptoContext::~CryptoContext() {
115
116 if (mki)
117 delete [] mki;
118
119 if (master_key_length > 0) {
120 memset(master_key, 0, master_key_length);
121 master_key_length = 0;
122 delete [] master_key;
123 }
124 if (master_salt_length > 0) {
125 memset(master_salt, 0, master_salt_length);
126 master_salt_length = 0;
127 delete [] master_salt;
128 }
129 if (n_e > 0) {
130 memset(k_e, 0, n_e);
131 n_e = 0;
132 delete [] k_e;
133 }
134 if (n_s > 0) {
135 memset(k_s, 0, n_s);
136 n_s = 0;
137 delete [] k_s;
138 }
139 if (n_a > 0) {
140 memset(k_a, 0, n_a);
141 n_a = 0;
142 delete [] k_a;
143 }
144 if (cipher != NULL) {
145 delete cipher;
146 cipher = NULL;
147 }
148 if (f8Cipher != NULL) {
149 delete f8Cipher;
150 f8Cipher = NULL;
151 }
152 if (macCtx != NULL) {
153 switch(aalg) {
154 case SrtpAuthenticationSha1Hmac:
155 freeSha1HmacContext(macCtx);
156 break;
157
158 case SrtpAuthenticationSkeinHmac:
159 freeSkeinMacContext(macCtx);
160 break;
161 }
162 }
163 ealg = SrtpEncryptionNull;
164 aalg = SrtpAuthenticationNull;
165}
166
167void CryptoContext::srtpEncrypt(uint8_t* pkt, uint8_t* payload, uint32_t paylen, uint64_t index, uint32_t ssrc ) {
168
169 if (ealg == SrtpEncryptionNull) {
170 return;
171 }
172 if (ealg == SrtpEncryptionAESCM || ealg == SrtpEncryptionTWOCM) {
173
174 /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711):
175 *
176 * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX
177 * SSRC XX XX XX XX
178 * index XX XX XX XX XX XX
179 * ------------------------------------------------------XOR
180 * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
181 */
182
183 unsigned char iv[16];
184 memcpy(iv, k_s, 4);
185
186 int i;
187 for (i = 4; i < 8; i++ ) {
188 iv[i] = (0xFF & (ssrc >> ((7-i)*8))) ^ k_s[i];
189 }
190 for (i = 8; i < 14; i++ ) {
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500191 iv[i] = (0xFF & (unsigned char)(index >> ((13-i)*8) ) ) ^ k_s[i];
Alexandre Lision51140e12013-12-02 10:54:09 -0500192 }
193 iv[14] = iv[15] = 0;
194
195 cipher->ctr_encrypt(payload, paylen, iv);
196 }
197
198 if (ealg == SrtpEncryptionAESF8 || ealg == SrtpEncryptionTWOF8) {
199
200 /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
201 *
202 * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
203 * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
204 * ------------\ /--------------------------------------------------
205 * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
206 */
207
208 unsigned char iv[16];
209 uint32_t *ui32p = (uint32_t *)iv;
210
211 memcpy(iv, pkt, 12);
212 iv[0] = 0;
213
214 // set ROC in network order into IV
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500215 ui32p[3] = zrtpHtonl(roc);
Alexandre Lision51140e12013-12-02 10:54:09 -0500216
217 cipher->f8_encrypt(payload, paylen, iv, f8Cipher);
218 }
219}
220
221/* Warning: tag must have been initialized */
222void CryptoContext::srtpAuthenticate(uint8_t* pkt, uint32_t pktlen, uint32_t roc, uint8_t* tag )
223{
224
225 if (aalg == SrtpAuthenticationNull) {
226 return;
227 }
228 int32_t macL;
229
230 unsigned char temp[20];
231 const unsigned char* chunks[3];
232 unsigned int chunkLength[3];
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500233 uint32_t beRoc = zrtpHtonl(roc);
Alexandre Lision51140e12013-12-02 10:54:09 -0500234
235 chunks[0] = pkt;
236 chunkLength[0] = pktlen;
237
238 chunks[1] = (unsigned char *)&beRoc;
239 chunkLength[1] = 4;
240 chunks[2] = NULL;
241
242 switch (aalg) {
243 case SrtpAuthenticationSha1Hmac:
244 hmacSha1Ctx(macCtx,
245 chunks, // data chunks to hash
246 chunkLength, // length of the data to hash
247 temp, &macL);
248 /* truncate the result */
249 memcpy(tag, temp, getTagLength());
250 break;
251 case SrtpAuthenticationSkeinHmac:
252 macSkeinCtx(macCtx,
253 chunks, // data chunks to hash
254 chunkLength, // length of the data to hash
255 temp);
256 /* truncate the result */
257 memcpy(tag, temp, getTagLength());
258 break;
259 }
260}
261
262/* used by the key derivation method */
263static void computeIv(unsigned char* iv, uint64_t label, uint64_t index,
264 int64_t kdv, unsigned char* master_salt)
265{
266
267 uint64_t key_id;
268
269 if (kdv == 0) {
270 key_id = label << 48;
271 }
272 else {
273 key_id = ((label << 48) | (index / kdv));
274 }
275
276 //printf( "Key_ID: %llx\n", key_id );
277
278 /* compute the IV
279 key_id: XX XX XX XX XX XX XX
280 master_salt: XX XX XX XX XX XX XX XX XX XX XX XX XX XX
281 ------------------------------------------------------------ XOR
282 IV: XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
283 */
284
285 int i;
286 for (i = 0; i < 7 ; i++ ) {
287 iv[i] = master_salt[i];
288 }
289
290 for (i = 7; i < 14 ; i++ ) {
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500291 iv[i] = (unsigned char)(0xFF & (key_id >> (8*(13-i)))) ^ master_salt[i];
Alexandre Lision51140e12013-12-02 10:54:09 -0500292 }
Alexandre Lision51140e12013-12-02 10:54:09 -0500293 iv[14] = iv[15] = 0;
294}
295
296/* Derive the srtp session keys from the master key */
297void CryptoContext::deriveSrtpKeys(uint64_t index)
298{
299 uint8_t iv[16];
300
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500301 // prepare cipher to compute derived keys.
Alexandre Lision51140e12013-12-02 10:54:09 -0500302 cipher->setNewKey(master_key, master_key_length);
303 memset(master_key, 0, master_key_length);
304
305 // compute the session encryption key
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500306 uint64_t label = labelBase + 0;
Alexandre Lision51140e12013-12-02 10:54:09 -0500307 computeIv(iv, label, index, key_deriv_rate, master_salt);
308 cipher->get_ctr_cipher_stream(k_e, n_e, iv);
309
310 // compute the session authentication key
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500311 label = labelBase + 0x01;
Alexandre Lision51140e12013-12-02 10:54:09 -0500312 computeIv(iv, label, index, key_deriv_rate, master_salt);
313 cipher->get_ctr_cipher_stream(k_a, n_a, iv);
314
315 // Initialize MAC context with the derived key
316 switch (aalg) {
317 case SrtpAuthenticationSha1Hmac:
318 macCtx = createSha1HmacContext(k_a, n_a);
319 break;
320 case SrtpAuthenticationSkeinHmac:
321 // Skein MAC uses number of bits as MAC size, not just bytes
322 macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
323 break;
324 }
325 memset(k_a, 0, n_a);
326
327 // compute the session salt
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500328 label = labelBase + 0x02;
Alexandre Lision51140e12013-12-02 10:54:09 -0500329 computeIv(iv, label, index, key_deriv_rate, master_salt);
330 cipher->get_ctr_cipher_stream(k_s, n_s, iv);
331 memset(master_salt, 0, master_salt_length);
332
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500333 // as last step prepare cipher with derived key.
Alexandre Lision51140e12013-12-02 10:54:09 -0500334 cipher->setNewKey(k_e, n_e);
335 if (f8Cipher != NULL)
336 cipher->f8_deriveForIV(f8Cipher, k_e, n_e, k_s, n_s);
337 memset(k_e, 0, n_e);
338}
339
340/* Based on the algorithm provided in Appendix A - draft-ietf-srtp-05.txt */
341uint64_t CryptoContext::guessIndex(uint16_t new_seq_nb )
342{
343 /*
344 * Initialize the sequences number on first call that uses the
345 * sequence number. Either GuessIndex() or checkReplay().
346 */
347 if (!seqNumSet) {
348 seqNumSet = true;
349 s_l = new_seq_nb;
350 }
351 if (s_l < 32768) {
352 if (new_seq_nb - s_l > 32768) {
353 guessed_roc = roc - 1;
354 }
355 else {
356 guessed_roc = roc;
357 }
358 }
359 else {
360 if (s_l - 32768 > new_seq_nb) {
361 guessed_roc = roc + 1;
362 }
363 else {
364 guessed_roc = roc;
365 }
366 }
367
368 return ((uint64_t)guessed_roc) << 16 | new_seq_nb;
369}
370
371bool CryptoContext::checkReplay( uint16_t new_seq_nb )
372{
373 if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
374 /* No security policy, don't use the replay protection */
375 return true;
376 }
377
378 /*
379 * Initialize the sequences number on first call that uses the
380 * sequence number. Either guessIndex() or checkReplay().
381 */
382 if (!seqNumSet) {
383 seqNumSet = true;
384 s_l = new_seq_nb;
385 }
386 uint64_t guessed_index = guessIndex( new_seq_nb );
387 uint64_t local_index = (((uint64_t)roc) << 16) | s_l;
388
389 int64_t delta = guessed_index - local_index;
390 if (delta > 0) {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500391 return true; /* Packet not yet received*/
Alexandre Lision51140e12013-12-02 10:54:09 -0500392 }
393 else {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500394 if ( -delta >= REPLAY_WINDOW_SIZE ) {
395 return false; /* Packet too old */
Alexandre Lision51140e12013-12-02 10:54:09 -0500396 }
397 else {
398 if ((replay_window >> (-delta)) & 0x1) {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500399 return false; /* Packet already received ! */
Alexandre Lision51140e12013-12-02 10:54:09 -0500400 }
401 else {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500402 return true; /* Packet not yet received */
Alexandre Lision51140e12013-12-02 10:54:09 -0500403 }
404 }
405 }
406}
407
408void CryptoContext::update(uint16_t new_seq_nb)
409{
410 int64_t delta = guessIndex(new_seq_nb) - (((uint64_t)roc) << 16 | s_l );
411
412 /* update the replay bitmask */
413 if ( delta > 0 ) {
414 replay_window = replay_window << delta;
415 replay_window |= 1;
416 }
417 else {
418 replay_window |= ( 1 << delta );
419 }
420
421 /* update the locally stored ROC and highest sequence number */
422 if ( new_seq_nb > s_l ) {
423 s_l = new_seq_nb;
424 }
425 if ( guessed_roc > roc ) {
426 roc = guessed_roc;
427 s_l = new_seq_nb;
428 }
429}
430
431CryptoContext* CryptoContext::newCryptoContextForSSRC(uint32_t ssrc, int roc, int64_t keyDerivRate)
432{
433 CryptoContext* pcc = new CryptoContext(
434 ssrc,
435 roc, // Roll over Counter,
436 keyDerivRate, // keyderivation << 48,
437 this->ealg, // encryption algo
438 this->aalg, // authentication algo
439 this->master_key, // Master Key
440 this->master_key_length, // Master Key length
441 this->master_salt, // Master Salt
442 this->master_salt_length, // Master Salt length
443 this->ekeyl, // encryption keyl
444 this->akeyl, // authentication key len
445 this->skeyl, // session salt len
446 this->tagLength); // authentication tag len
447
448 return pcc;
449}