blob: 952a82304c367c269b3c03f15de06f28f370acfe [file] [log] [blame]
Alexandre Lision51140e12013-12-02 10:54:09 -05001/*
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -05002 Copyright (C) 2011 - 2012 Werner Dittmann
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 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 <CryptoContextCtrl.h>
30#include <CryptoContext.h>
31
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050032#include <crypto/SrtpSymCrypto.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050033#include <crypto/hmac.h>
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050034#include <cryptcommon/macSkein.h>
Alexandre Lision51140e12013-12-02 10:54:09 -050035
36
37CryptoContextCtrl::CryptoContextCtrl(uint32_t ssrc,
38 const int32_t ealg,
39 const int32_t aalg,
40 uint8_t* master_key,
41 int32_t master_key_length,
42 uint8_t* master_salt,
43 int32_t master_salt_length,
44 int32_t ekeyl,
45 int32_t akeyl,
46 int32_t skeyl,
47 int32_t tagLength):
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050048ssrcCtx(ssrc),using_mki(false),mkiLength(0),mki(NULL), replay_window(0), srtcpIndex(0),
49labelBase(3), macCtx(NULL), cipher(NULL), f8Cipher(NULL) // SRTCP labels start at 3
50
Alexandre Lision51140e12013-12-02 10:54:09 -050051{
52 this->ealg = ealg;
53 this->aalg = aalg;
54 this->ekeyl = ekeyl;
55 this->akeyl = akeyl;
56 this->skeyl = skeyl;
57
58 this->master_key_length = master_key_length;
59 this->master_key = new uint8_t[master_key_length];
60 memcpy(this->master_key, master_key, master_key_length);
61
62 this->master_salt_length = master_salt_length;
63 this->master_salt = new uint8_t[master_salt_length];
64 memcpy(this->master_salt, master_salt, master_salt_length);
65
66 switch (ealg) {
67 case SrtpEncryptionNull:
68 n_e = 0;
69 k_e = NULL;
70 n_s = 0;
71 k_s = NULL;
72 break;
73
74 case SrtpEncryptionTWOF8:
75 f8Cipher = new SrtpSymCrypto(SrtpEncryptionTWOF8);
76
77 case SrtpEncryptionTWOCM:
78 n_e = ekeyl;
79 k_e = new uint8_t[n_e];
80 n_s = skeyl;
81 k_s = new uint8_t[n_s];
82 cipher = new SrtpSymCrypto(SrtpEncryptionTWOCM);
83 break;
84
85 case SrtpEncryptionAESF8:
86 f8Cipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
87
88 case SrtpEncryptionAESCM:
89 n_e = ekeyl;
90 k_e = new uint8_t[n_e];
91 n_s = skeyl;
92 k_s = new uint8_t[n_s];
93 cipher = new SrtpSymCrypto(SrtpEncryptionAESCM);
94 break;
95 }
96
97 switch (aalg) {
98 case SrtpAuthenticationNull:
99 n_a = 0;
100 k_a = NULL;
101 this->tagLength = 0;
102 break;
103
104 case SrtpAuthenticationSha1Hmac:
105 case SrtpAuthenticationSkeinHmac:
106 n_a = akeyl;
107 k_a = new uint8_t[n_a];
108 this->tagLength = tagLength;
109 break;
110 }
111}
112
113CryptoContextCtrl::~CryptoContextCtrl(){
114
115 if (mki)
116 delete [] mki;
117
118 if (master_key_length > 0) {
119 memset(master_key, 0, master_key_length);
120 master_key_length = 0;
121 delete [] master_key;
122 }
123 if (master_salt_length > 0) {
124 memset(master_salt, 0, master_salt_length);
125 master_salt_length = 0;
126 delete [] master_salt;
127 }
128 if (n_e > 0) {
129 memset(k_e, 0, n_e);
130 n_e = 0;
131 delete [] k_e;
132 }
133 if (n_s > 0) {
134 memset(k_s, 0, n_s);
135 n_s = 0;
136 delete [] k_s;
137 }
138 if (n_a > 0) {
139 n_a = 0;
140 memset(k_a, 0, n_a);
141 delete [] k_a;
142 }
143 if (cipher != NULL) {
144 delete cipher;
145 cipher = NULL;
146 }
147 if (f8Cipher != NULL) {
148 delete f8Cipher;
149 f8Cipher = NULL;
150 }
151 if (macCtx != NULL) {
152 switch(aalg) {
153 case SrtpAuthenticationSha1Hmac:
154 freeSha1HmacContext(macCtx);
155 break;
156
157 case SrtpAuthenticationSkeinHmac:
158 freeSkeinMacContext(macCtx);
159 break;
160 }
161 }
162 ealg = SrtpEncryptionNull;
163 aalg = SrtpAuthenticationNull;
164}
165
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500166void CryptoContextCtrl::srtcpEncrypt( uint8_t* rtp, int32_t len, uint32_t index, uint32_t ssrc )
Alexandre Lision51140e12013-12-02 10:54:09 -0500167{
168 if (ealg == SrtpEncryptionNull) {
169 return;
170 }
171 if (ealg == SrtpEncryptionAESCM || ealg == SrtpEncryptionTWOCM) {
172
173 /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711):
174 *
175 * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX
176 * SSRC XX XX XX XX
177 * index XX XX XX XX
178 * ------------------------------------------------------XOR
179 * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
180 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
181 */
182 unsigned char iv[16];
183
184 iv[0] = k_s[0];
185 iv[1] = k_s[1];
186 iv[2] = k_s[2];
187 iv[3] = k_s[3];
188
189 // The shifts transform the ssrc and index into network order
190 iv[4] = ((ssrc >> 24) & 0xff) ^ k_s[4];
191 iv[5] = ((ssrc >> 16) & 0xff) ^ k_s[5];
192 iv[6] = ((ssrc >> 8) & 0xff) ^ k_s[6];
193 iv[7] = (ssrc & 0xff) ^ k_s[7];
194
195 iv[8] = k_s[8];
196 iv[9] = k_s[9];
197
198 iv[10] = ((index >> 24) & 0xff) ^ k_s[10];
199 iv[11] = ((index >> 16) & 0xff) ^ k_s[11];
200 iv[12] = ((index >> 8) & 0xff) ^ k_s[12];
201 iv[13] = (index & 0xff) ^ k_s[13];
202
203 iv[14] = iv[15] = 0;
204
205 cipher->ctr_encrypt(rtp, len, iv);
206 }
207
208 if (ealg == SrtpEncryptionAESF8 || ealg == SrtpEncryptionTWOF8) {
209
210 unsigned char iv[16];
211
212 // 4 bytes of the iv are zero
213 // the first byte of the RTP header is not used.
214 iv[0] = 0;
215 iv[1] = 0;
216 iv[2] = 0;
217 iv[3] = 0;
218
219 // Need the encryption flag
220 index = index | 0x80000000;
221
222 // set the index and the encrypt flag in network order into IV
223 iv[4] = index >> 24;
224 iv[5] = index >> 16;
225 iv[6] = index >> 8;
226 iv[7] = index;
227
228 // The fixed header follows and fills the rest of the IV
229 memcpy(iv+8, rtp, 8);
230
231 cipher->f8_encrypt(rtp, len, iv, f8Cipher);
232 }
233}
234
235/* Warning: tag must have been initialized */
236void CryptoContextCtrl::srtcpAuthenticate(uint8_t* rtp, int32_t len, uint32_t index, uint8_t* tag )
237{
238 if (aalg == SrtpAuthenticationNull) {
239 return;
240 }
241 int32_t macL;
242
243 unsigned char temp[20];
244 const unsigned char* chunks[3];
245 unsigned int chunkLength[3];
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500246 uint32_t beIndex = zrtpHtonl(index);
Alexandre Lision51140e12013-12-02 10:54:09 -0500247
248 chunks[0] = rtp;
249 chunkLength[0] = len;
250
251 chunks[1] = (unsigned char *)&beIndex;
252 chunkLength[1] = 4;
253 chunks[2] = NULL;
254
255 switch (aalg) {
256 case SrtpAuthenticationSha1Hmac:
257 hmacSha1Ctx(macCtx,
258 chunks, // data chunks to hash
259 chunkLength, // length of the data to hash
260 temp, &macL);
261 /* truncate the result */
262 memcpy(tag, temp, getTagLength());
263 break;
264 case SrtpAuthenticationSkeinHmac:
265 macSkeinCtx(macCtx,
266 chunks, // data chunks to hash
267 chunkLength, // length of the data to hash
268 temp);
269 /* truncate the result */
270 memcpy(tag, temp, getTagLength());
271 break;
272 }
273}
274
275/* used by the key derivation method */
276static void computeIv(unsigned char* iv, uint8_t label, uint8_t* master_salt)
277{
278 //printf( "Key_ID: %llx\n", key_id );
279
280 /* compute the IV
281 key_id: XX XX XX XX XX XX XX
282 master_salt: XX XX XX XX XX XX XX XX XX XX XX XX XX XX
283 ------------------------------------------------------------ XOR
284 IV: XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
285 */
286
287 memcpy(iv, master_salt, 14);
288 iv[7] ^= label;
289
290 iv[14] = iv[15] = 0;
291}
292
293/* Derives the srtp session keys from the master key */
294void CryptoContextCtrl::deriveSrtcpKeys()
295{
296 uint8_t iv[16];
297
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500298 // prepare cipher to compute derived keys.
Alexandre Lision51140e12013-12-02 10:54:09 -0500299 cipher->setNewKey(master_key, master_key_length);
300 memset(master_key, 0, master_key_length);
301
302 // compute the session encryption key
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500303 uint8_t label = labelBase;
Alexandre Lision51140e12013-12-02 10:54:09 -0500304 computeIv(iv, label, master_salt);
305 cipher->get_ctr_cipher_stream(k_e, n_e, iv);
306
307 // compute the session authentication key
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500308 label = labelBase + 1;
Alexandre Lision51140e12013-12-02 10:54:09 -0500309 computeIv(iv, label, master_salt);
310 cipher->get_ctr_cipher_stream(k_a, n_a, iv);
311
312 // Initialize MAC context with the derived key
313 switch (aalg) {
314 case SrtpAuthenticationSha1Hmac:
315 macCtx = createSha1HmacContext(k_a, n_a);
316 break;
317 case SrtpAuthenticationSkeinHmac:
318 // Skein MAC uses number of bits as MAC size, not just bytes
319 macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
320 break;
321 }
322 memset(k_a, 0, n_a);
323
324 // compute the session salt
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500325 label = labelBase + 2;
Alexandre Lision51140e12013-12-02 10:54:09 -0500326 computeIv(iv, label, master_salt);
327 cipher->get_ctr_cipher_stream(k_s, n_s, iv);
328 memset(master_salt, 0, master_salt_length);
329
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500330 // as last step prepare cipher with derived key.
Alexandre Lision51140e12013-12-02 10:54:09 -0500331 cipher->setNewKey(k_e, n_e);
332 if (f8Cipher != NULL)
333 cipher->f8_deriveForIV(f8Cipher, k_e, n_e, k_s, n_s);
334 memset(k_e, 0, n_e);
335}
336
337bool CryptoContextCtrl::checkReplay( uint32_t index )
338{
339 if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
340 /* No security policy, don't use the replay protection */
341 return true;
342 }
343
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500344 int64_t delta = index - s_l;
Alexandre Lision51140e12013-12-02 10:54:09 -0500345 if (delta > 0) {
346 /* Packet not yet received*/
347 return true;
348 }
349 else {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500350 if( -delta >= REPLAY_WINDOW_SIZE ) {
351 return false; /* Packet too old */
Alexandre Lision51140e12013-12-02 10:54:09 -0500352 }
353 else {
354 if((replay_window >> (-delta)) & 0x1) {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500355 return false; /* Packet already received ! */
Alexandre Lision51140e12013-12-02 10:54:09 -0500356 }
357 else {
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500358 return true; /* Packet not yet received */
Alexandre Lision51140e12013-12-02 10:54:09 -0500359 }
360 }
361 }
362}
363
364void CryptoContextCtrl::update(uint32_t index)
365{
366 int64_t delta = index - s_l;
367
368 /* update the replay bitmask */
369 if( delta > 0 ){
370 replay_window = replay_window << delta;
371 replay_window |= 1;
372 }
373 else {
374 replay_window |= ( 1 << delta );
375 }
Alexandre Lision907ed2e2014-02-04 10:33:09 -0500376 if (index > s_l)
377 s_l = index;
Alexandre Lision51140e12013-12-02 10:54:09 -0500378}
379
380CryptoContextCtrl* CryptoContextCtrl::newCryptoContextForSSRC(uint32_t ssrc)
381{
382 CryptoContextCtrl* pcc = new CryptoContextCtrl(
383 ssrc,
384 this->ealg, // encryption algo
385 this->aalg, // authentication algo
386 this->master_key, // Master Key
387 this->master_key_length, // Master Key length
388 this->master_salt, // Master Salt
389 this->master_salt_length, // Master Salt length
390 this->ekeyl, // encryption keyl
391 this->akeyl, // authentication key len
392 this->skeyl, // session salt len
393 this->tagLength); // authentication tag len
394
395 return pcc;
396}