blob: caf5746d269a122e54ba1fb5bf65e68fc46edb85 [file] [log] [blame]
Alexandre Lision51140e12013-12-02 10:54:09 -05001/*
Alexandre Lisione24852d2014-02-04 13:13:02 -05002 Copyright (C) 2004-2006 the Minisip Team
Alexandre Lision51140e12013-12-02 10:54:09 -05003
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
Alexandre Lisione24852d2014-02-04 13:13:02 -050019/* 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>
Alexandre Lision51140e12013-12-02 10:54:09 -050026 */
27
28#include <string.h>
Alexandre Lisione24852d2014-02-04 13:13:02 -050029#include <arpa/inet.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050030#include <stdio.h>
31
32#include <CryptoContextCtrl.h>
33#include <CryptoContext.h>
34
35#include <crypto/hmac.h>
Alexandre Lisione24852d2014-02-04 13:13:02 -050036#include <crypto/macSkein.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050037
38
39CryptoContextCtrl::CryptoContextCtrl(uint32_t ssrc,
40 const int32_t ealg,
41 const int32_t aalg,
42 uint8_t* master_key,
43 int32_t master_key_length,
44 uint8_t* master_salt,
45 int32_t master_salt_length,
46 int32_t ekeyl,
47 int32_t akeyl,
48 int32_t skeyl,
49 int32_t tagLength):
Alexandre Lisione24852d2014-02-04 13:13:02 -050050ssrcCtx(ssrc),using_mki(false),mkiLength(0),mki(NULL),
51replay_window(0), macCtx(NULL), cipher(NULL), 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
114CryptoContextCtrl::~CryptoContextCtrl(){
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 n_a = 0;
141 memset(k_a, 0, n_a);
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
Alexandre Lisione24852d2014-02-04 13:13:02 -0500167void CryptoContextCtrl::srtcpEncrypt( uint8_t* rtp, int32_t len, uint64_t index, uint32_t ssrc )
Alexandre Lision51140e12013-12-02 10:54:09 -0500168{
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
179 * ------------------------------------------------------XOR
180 * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
181 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
182 */
183 unsigned char iv[16];
184
185 iv[0] = k_s[0];
186 iv[1] = k_s[1];
187 iv[2] = k_s[2];
188 iv[3] = k_s[3];
189
190 // The shifts transform the ssrc and index into network order
191 iv[4] = ((ssrc >> 24) & 0xff) ^ k_s[4];
192 iv[5] = ((ssrc >> 16) & 0xff) ^ k_s[5];
193 iv[6] = ((ssrc >> 8) & 0xff) ^ k_s[6];
194 iv[7] = (ssrc & 0xff) ^ k_s[7];
195
196 iv[8] = k_s[8];
197 iv[9] = k_s[9];
198
199 iv[10] = ((index >> 24) & 0xff) ^ k_s[10];
200 iv[11] = ((index >> 16) & 0xff) ^ k_s[11];
201 iv[12] = ((index >> 8) & 0xff) ^ k_s[12];
202 iv[13] = (index & 0xff) ^ k_s[13];
203
204 iv[14] = iv[15] = 0;
205
206 cipher->ctr_encrypt(rtp, len, iv);
207 }
208
209 if (ealg == SrtpEncryptionAESF8 || ealg == SrtpEncryptionTWOF8) {
210
211 unsigned char iv[16];
212
213 // 4 bytes of the iv are zero
214 // the first byte of the RTP header is not used.
215 iv[0] = 0;
216 iv[1] = 0;
217 iv[2] = 0;
218 iv[3] = 0;
219
220 // Need the encryption flag
221 index = index | 0x80000000;
222
223 // set the index and the encrypt flag in network order into IV
224 iv[4] = index >> 24;
225 iv[5] = index >> 16;
226 iv[6] = index >> 8;
227 iv[7] = index;
228
229 // The fixed header follows and fills the rest of the IV
230 memcpy(iv+8, rtp, 8);
231
232 cipher->f8_encrypt(rtp, len, iv, f8Cipher);
233 }
234}
235
236/* Warning: tag must have been initialized */
237void CryptoContextCtrl::srtcpAuthenticate(uint8_t* rtp, int32_t len, uint32_t index, uint8_t* tag )
238{
239 if (aalg == SrtpAuthenticationNull) {
240 return;
241 }
242 int32_t macL;
243
244 unsigned char temp[20];
245 const unsigned char* chunks[3];
246 unsigned int chunkLength[3];
Alexandre Lisione24852d2014-02-04 13:13:02 -0500247 uint32_t beIndex = htonl(index);
Alexandre Lision51140e12013-12-02 10:54:09 -0500248
249 chunks[0] = rtp;
250 chunkLength[0] = len;
251
252 chunks[1] = (unsigned char *)&beIndex;
253 chunkLength[1] = 4;
254 chunks[2] = NULL;
255
256 switch (aalg) {
257 case SrtpAuthenticationSha1Hmac:
258 hmacSha1Ctx(macCtx,
259 chunks, // data chunks to hash
260 chunkLength, // length of the data to hash
261 temp, &macL);
262 /* truncate the result */
263 memcpy(tag, temp, getTagLength());
264 break;
265 case SrtpAuthenticationSkeinHmac:
266 macSkeinCtx(macCtx,
267 chunks, // data chunks to hash
268 chunkLength, // length of the data to hash
269 temp);
270 /* truncate the result */
271 memcpy(tag, temp, getTagLength());
272 break;
273 }
274}
275
276/* used by the key derivation method */
277static void computeIv(unsigned char* iv, uint8_t label, uint8_t* master_salt)
278{
279 //printf( "Key_ID: %llx\n", key_id );
280
281 /* compute the IV
282 key_id: XX XX XX XX XX XX XX
283 master_salt: XX XX XX XX XX XX XX XX XX XX XX XX XX XX
284 ------------------------------------------------------------ XOR
285 IV: XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
286 */
287
288 memcpy(iv, master_salt, 14);
289 iv[7] ^= label;
290
291 iv[14] = iv[15] = 0;
292}
293
294/* Derives the srtp session keys from the master key */
295void CryptoContextCtrl::deriveSrtcpKeys()
296{
297 uint8_t iv[16];
298
Alexandre Lisione24852d2014-02-04 13:13:02 -0500299 // prepare AES cipher to compute derived keys.
Alexandre Lision51140e12013-12-02 10:54:09 -0500300 cipher->setNewKey(master_key, master_key_length);
301 memset(master_key, 0, master_key_length);
302
303 // compute the session encryption key
Alexandre Lisione24852d2014-02-04 13:13:02 -0500304 uint8_t label = 3;
Alexandre Lision51140e12013-12-02 10:54:09 -0500305 computeIv(iv, label, master_salt);
306 cipher->get_ctr_cipher_stream(k_e, n_e, iv);
307
308 // compute the session authentication key
Alexandre Lisione24852d2014-02-04 13:13:02 -0500309 label = 4;
Alexandre Lision51140e12013-12-02 10:54:09 -0500310 computeIv(iv, label, master_salt);
311 cipher->get_ctr_cipher_stream(k_a, n_a, iv);
312
313 // Initialize MAC context with the derived key
314 switch (aalg) {
315 case SrtpAuthenticationSha1Hmac:
316 macCtx = createSha1HmacContext(k_a, n_a);
317 break;
318 case SrtpAuthenticationSkeinHmac:
319 // Skein MAC uses number of bits as MAC size, not just bytes
320 macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
321 break;
322 }
323 memset(k_a, 0, n_a);
324
325 // compute the session salt
Alexandre Lisione24852d2014-02-04 13:13:02 -0500326 label = 5;
Alexandre Lision51140e12013-12-02 10:54:09 -0500327 computeIv(iv, label, master_salt);
328 cipher->get_ctr_cipher_stream(k_s, n_s, iv);
329 memset(master_salt, 0, master_salt_length);
330
Alexandre Lisione24852d2014-02-04 13:13:02 -0500331 // as last step prepare AES cipher with derived key.
Alexandre Lision51140e12013-12-02 10:54:09 -0500332 cipher->setNewKey(k_e, n_e);
333 if (f8Cipher != NULL)
334 cipher->f8_deriveForIV(f8Cipher, k_e, n_e, k_s, n_s);
335 memset(k_e, 0, n_e);
336}
337
338bool CryptoContextCtrl::checkReplay( uint32_t index )
339{
340 if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
341 /* No security policy, don't use the replay protection */
342 return true;
343 }
344
Alexandre Lisione24852d2014-02-04 13:13:02 -0500345 int64_t delta = s_l - index;
Alexandre Lision51140e12013-12-02 10:54:09 -0500346 if (delta > 0) {
347 /* Packet not yet received*/
348 return true;
349 }
350 else {
Alexandre Lisione24852d2014-02-04 13:13:02 -0500351 if( -delta > REPLAY_WINDOW_SIZE ) {
352 /* Packet too old */
353 return false;
Alexandre Lision51140e12013-12-02 10:54:09 -0500354 }
355 else {
356 if((replay_window >> (-delta)) & 0x1) {
Alexandre Lisione24852d2014-02-04 13:13:02 -0500357 /* Packet already received ! */
358 return false;
Alexandre Lision51140e12013-12-02 10:54:09 -0500359 }
360 else {
Alexandre Lisione24852d2014-02-04 13:13:02 -0500361 /* Packet not yet received */
362 return true;
Alexandre Lision51140e12013-12-02 10:54:09 -0500363 }
364 }
365 }
366}
367
368void CryptoContextCtrl::update(uint32_t index)
369{
370 int64_t delta = index - s_l;
371
372 /* update the replay bitmask */
373 if( delta > 0 ){
374 replay_window = replay_window << delta;
375 replay_window |= 1;
376 }
377 else {
378 replay_window |= ( 1 << delta );
379 }
Alexandre Lisione24852d2014-02-04 13:13:02 -0500380 s_l = index;
Alexandre Lision51140e12013-12-02 10:54:09 -0500381}
382
383CryptoContextCtrl* CryptoContextCtrl::newCryptoContextForSSRC(uint32_t ssrc)
384{
385 CryptoContextCtrl* pcc = new CryptoContextCtrl(
386 ssrc,
387 this->ealg, // encryption algo
388 this->aalg, // authentication algo
389 this->master_key, // Master Key
390 this->master_key_length, // Master Key length
391 this->master_salt, // Master Salt
392 this->master_salt_length, // Master Salt length
393 this->ekeyl, // encryption keyl
394 this->akeyl, // authentication key len
395 this->skeyl, // session salt len
396 this->tagLength); // authentication tag len
397
398 return pcc;
399}
Alexandre Lisione24852d2014-02-04 13:13:02 -0500400
401/** EMACS **
402 * Local variables:
403 * mode: c++
404 * c-default-style: ellemtel
405 * c-basic-offset: 4
406 * End:
407 */
408