ccRTP 2.1.2
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CryptoContext.cpp
Go to the documentation of this file.
1 /*
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-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>
26  */
27 
28 #include <iostream>
29 
30 #include <ccrtp-config.h>
31 
32 #ifdef SRTP_SUPPORT
33 #include <ccrtp/crypto/hmac.h>
34 #include <ccrtp/crypto/macSkein.h>
35 #endif
36 
37 #include <commoncpp/config.h>
38 #include <commoncpp/export.h>
39 #include <ccrtp/CryptoContext.h>
40 
41 NAMESPACE_COMMONCPP
42 
44 ssrcCtx(ssrc),
45 using_mki(false),mkiLength(0),mki(NULL),
46 roc(0),guessed_roc(0),s_l(0),key_deriv_rate(0),
47 replay_window(0),
48 master_key(NULL), master_key_length(0),
49 master_key_srtp_use_nb(0), master_key_srtcp_use_nb(0),
50 master_salt(NULL), master_salt_length(0),
51 n_e(0),k_e(NULL),n_a(0),k_a(NULL),n_s(0),k_s(NULL),
53 ekeyl(0), akeyl(0), skeyl(0),
54 seqNumSet(false), macCtx(NULL), cipher(NULL), f8Cipher(NULL)
55 {}
56 
57 #ifdef SRTP_SUPPORT
58 CryptoContext::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 
72 ssrcCtx(ssrc),using_mki(false),mkiLength(0),mki(NULL),
73 roc(roc),guessed_roc(0),s_l(0),key_deriv_rate(key_deriv_rate),
74 replay_window(0),
75 master_key_srtp_use_nb(0), master_key_srtcp_use_nb(0), seqNumSet(false),
76 macCtx(NULL), cipher(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:
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];
109  break;
110 
111  case SrtpEncryptionAESF8:
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];
120  break;
121  }
122 
123  switch( aalg ) {
125  n_a = 0;
126  k_a = NULL;
127  this->tagLength = 0;
128  break;
129 
132  n_a = akeyl;
133  k_a = new uint8[n_a];
134  this->tagLength = tagLength;
135  break;
136  }
137 }
138 
139 #endif
140 
142 
143 #ifdef SRTP_SUPPORT
144  if (mki)
145  delete [] mki;
146 
147  if (master_key_length > 0) {
148  memset(master_key, 0, master_key_length);
149  master_key_length = 0;
150  delete [] master_key;
151  }
152  if (master_salt_length > 0) {
153  memset(master_salt, 0, master_salt_length);
154  master_salt_length = 0;
155  delete [] master_salt;
156  }
157  if (n_e > 0) {
158  memset(k_e, 0, n_e);
159  n_e = 0;
160  delete [] k_e;
161  }
162  if (n_s > 0) {
163  memset(k_s, 0, n_s);
164  n_s = 0;
165  delete [] k_s;
166  }
167  if (n_a > 0) {
168  memset(k_a, 0, n_a);
169  n_a = 0;
170  delete [] k_a;
171  }
172  if (cipher != NULL) {
173  delete cipher;
174  cipher = NULL;
175  }
176  if (f8Cipher != NULL) {
177  delete f8Cipher;
178  f8Cipher = NULL;
179  }
180  if (macCtx != NULL) {
181  switch(aalg) {
184  break;
185 
188  break;
189  }
190  }
191 #endif
192 
193  ealg = SrtpEncryptionNull;
194  aalg = SrtpAuthenticationNull;
195 }
196 
197 void CryptoContext::srtpEncrypt(RTPPacket* rtp, uint64 index, uint32 ssrc)
198 {
199  if (ealg == SrtpEncryptionNull) {
200  return;
201  }
202 #ifdef SRTP_SUPPORT
203  if (ealg == SrtpEncryptionAESCM || ealg == SrtpEncryptionTWOCM) {
204 
205  /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711):
206  *
207  * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX
208  * SSRC XX XX XX XX
209  * index XX XX XX XX XX XX
210  * ------------------------------------------------------XOR
211  * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
212  */
213 
214  unsigned char iv[16];
215  memcpy( iv, k_s, 4 );
216 
217  int i;
218  for(i = 4; i < 8; i++ ){
219  iv[i] = ( 0xFF & ( ssrc >> ((7-i)*8) ) ) ^ k_s[i];
220  }
221  for(i = 8; i < 14; i++ ){
222  iv[i] = ( 0xFF & (unsigned char)( index >> ((13-i)*8) ) ) ^ k_s[i];
223  }
224  iv[14] = iv[15] = 0;
225 
226  int32 pad = rtp->isPadded() ? rtp->getPaddingSize() : 0;
227  cipher->ctr_encrypt(const_cast<uint8*>(rtp->getPayload()),
228  rtp->getPayloadSize()+pad, iv);
229  }
230 
231  if (ealg == SrtpEncryptionAESF8 || ealg == SrtpEncryptionTWOF8) {
232 
233  /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
234  *
235  * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
236  * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
237  * ------------\ /--------------------------------------------------
238  * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
239  */
240 
241  unsigned char iv[16];
242  uint32 *ui32p = (uint32 *)iv;
243 
244  memcpy(iv, rtp->getRawPacket(), 12);
245  iv[0] = 0;
246 
247  // set ROC in network order into IV
248  ui32p[3] = htonl(roc);
249 
250  int32 pad = rtp->isPadded() ? rtp->getPaddingSize() : 0;
251  cipher->f8_encrypt(rtp->getPayload(), rtp->getPayloadSize()+pad, iv, f8Cipher);
252  }
253 #endif
254 }
255 
256 /* Warning: tag must have been initialized */
257 void CryptoContext::srtpAuthenticate(RTPPacket* rtp, uint32 roc, uint8* tag )
258 {
259  if (aalg == SrtpAuthenticationNull) {
260  return;
261  }
262 #ifdef SRTP_SUPPORT
263  int32_t macL;
264 
265  unsigned char temp[20];
266  const unsigned char* chunks[3];
267  unsigned int chunkLength[3];
268  uint32_t beRoc = htonl(roc);
269 
270  chunks[0] = rtp->getRawPacket();
271  chunkLength[0] = rtp->getRawPacketSize();
272 
273  chunks[1] = (unsigned char *)&beRoc;
274  chunkLength[1] = 4;
275  chunks[2] = NULL;
276 
277  switch (aalg) {
280  chunks, // data chunks to hash
281  chunkLength, // length of the data to hash
282  temp, &macL);
283  /* truncate the result */
284  memcpy(tag, temp, getTagLength());
285  break;
288  chunks, // data chunks to hash
289  chunkLength, // length of the data to hash
290  temp);
291  /* truncate the result */
292  memcpy(tag, temp, getTagLength());
293  break;
294  }
295 #endif
296 }
297 
298 #ifdef SRTP_SUPPORT
299 /* used by the key derivation method */
300 static void computeIv(unsigned char* iv, uint64 label, uint64 index,
301  int64 kdv, unsigned char* master_salt)
302 {
303 
304  uint64 key_id;
305 
306  if (kdv == 0) {
307  key_id = label << 48;
308  }
309  else {
310  key_id = ((label << 48) | (index / kdv));
311  }
312 
313  //printf( "Key_ID: %llx\n", key_id );
314 
315  /* compute the IV
316  key_id: XX XX XX XX XX XX XX
317  master_salt: XX XX XX XX XX XX XX XX XX XX XX XX XX XX
318  ------------------------------------------------------------ XOR
319  IV: XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00
320  */
321 
322  int i;
323  for(i = 0; i < 7 ; i++ ) {
324  iv[i] = master_salt[i];
325  }
326 
327  for(i = 7; i < 14 ; i++ ) {
328  iv[i] = (unsigned char)(0xFF & (key_id >> (8*(13-i)))) ^
329  master_salt[i];
330  }
331 
332  iv[14] = iv[15] = 0;
333 }
334 #endif
335 
336 /* Derives the srtp session keys from the master key */
338 {
339 #ifdef SRTP_SUPPORT
340  uint8 iv[16];
341 
342  // prepare AES cipher to compute derived keys.
343  cipher->setNewKey(master_key, master_key_length);
344  memset(master_key, 0, master_key_length);
345 
346  // compute the session encryption key
347  uint64 label = 0;
348  computeIv(iv, label, index, key_deriv_rate, master_salt);
349  cipher->get_ctr_cipher_stream(k_e, n_e, iv);
350 
351  // compute the session authentication key
352  label = 0x01;
353  computeIv(iv, label, index, key_deriv_rate, master_salt);
354  cipher->get_ctr_cipher_stream(k_a, n_a, iv);
355 
356  // Initialize MAC context with the derived key
357  switch (aalg) {
360  break;
362  // Skein MAC uses number of bits as MAC size, not just bytes
363  macCtx = createSkeinMacContext(k_a, n_a, tagLength*8, Skein512);
364  break;
365  }
366  memset(k_a, 0, n_a);
367 
368  // compute the session salt
369  label = 0x02;
370  computeIv(iv, label, index, key_deriv_rate, master_salt);
371  cipher->get_ctr_cipher_stream(k_s, n_s, iv);
372  memset(master_salt, 0, master_salt_length);
373 
374  // as last step prepare ciphers with derived key.
375  cipher->setNewKey(k_e, n_e);
376  if (f8Cipher != NULL)
377  cipher->f8_deriveForIV(f8Cipher, k_e, n_e, k_s, n_s);
378  memset(k_e, 0, n_e);
379 
380 #endif
381 }
382 
383 /* Based on the algorithm provided in Appendix A - draft-ietf-srtp-05.txt */
384 uint64_t CryptoContext::guessIndex(uint16 new_seq_nb )
385 {
386  /*
387  * Initialize the sequences number on first call that uses the
388  * sequence number. Either GuessIndex() or checkReplay().
389  */
390  if (!seqNumSet) {
391  seqNumSet = true;
392  s_l = new_seq_nb;
393  }
394  if (s_l < 32768){
395  if (new_seq_nb - s_l > 32768) {
396  guessed_roc = roc - 1;
397  }
398  else {
399  guessed_roc = roc;
400  }
401  }
402  else {
403  if (s_l - 32768 > new_seq_nb) {
404  guessed_roc = roc + 1;
405  }
406  else {
407  guessed_roc = roc;
408  }
409  }
410 
411  return ((uint64)guessed_roc) << 16 | new_seq_nb;
412 }
413 
414 bool CryptoContext::checkReplay( uint16 new_seq_nb )
415 {
416 #ifdef SRTP_SUPPORT
417  if ( aalg == SrtpAuthenticationNull && ealg == SrtpEncryptionNull ) {
418  /* No security policy, don't use the replay protection */
419  return true;
420  }
421 
422  /*
423  * Initialize the sequences number on first call that uses the
424  * sequence number. Either guessIndex() or checkReplay().
425  */
426  if (!seqNumSet) {
427  seqNumSet = true;
428  s_l = new_seq_nb;
429  }
430  uint64 guessed_index = guessIndex( new_seq_nb );
431  uint64 local_index = (((uint64_t)roc) << 16) | s_l;
432 
433  int64 delta = guessed_index - local_index;
434  if (delta > 0) {
435  /* Packet not yet received*/
436  return true;
437  }
438  else {
439  if( -delta > REPLAY_WINDOW_SIZE ) {
440  /* Packet too old */
441  return false;
442  }
443  else {
444  if((replay_window >> (-delta)) & 0x1) {
445  /* Packet already received ! */
446  return false;
447  }
448  else {
449  /* Packet not yet received */
450  return true;
451  }
452  }
453 }
454 #else
455  return true;
456 #endif
457 }
458 
459 void CryptoContext::update(uint16 new_seq_nb)
460 {
461 #ifdef SRTP_SUPPORT
462  int64 delta = guessIndex(new_seq_nb) - (((uint64)roc) << 16 | s_l );
463 
464  /* update the replay bitmask */
465  if( delta > 0 ){
466  replay_window = replay_window << delta;
467  replay_window |= 1;
468  }
469  else {
470  replay_window |= ( 1 << delta );
471  }
472 
473  /* update the locally stored ROC and highest sequence number */
474  if( new_seq_nb > s_l ) {
475  s_l = new_seq_nb;
476  }
477  if( guessed_roc > roc ) {
478  roc = guessed_roc;
479  s_l = new_seq_nb;
480  }
481 #endif
482 }
483 
484 CryptoContext* CryptoContext::newCryptoContextForSSRC(uint32 ssrc, int roc, int64 keyDerivRate)
485 {
486 #ifdef SRTP_SUPPORT
487  CryptoContext* pcc = new CryptoContext(
488  ssrc,
489  roc, // Roll over Counter,
490  keyDerivRate, // keyderivation << 48,
491  this->ealg, // encryption algo
492  this->aalg, // authentication algo
493  this->master_key, // Master Key
494  this->master_key_length, // Master Key length
495  this->master_salt, // Master Salt
496  this->master_salt_length, // Master Salt length
497  this->ekeyl, // encryption keyl
498  this->akeyl, // authentication key len
499  this->skeyl, // session salt len
500  this->tagLength); // authentication tag len
501 
502  return pcc;
503 #else
504  return NULL;
505 #endif
506 }
507 
508 END_NAMESPACE
509 
Implments the SRTP encryption modes as defined in RFC3711.
Definition: SrtpSymCrypto.h:77
uint64 replay_window
bool isPadded() const
Ask whether the packet contains padding bytes at the end.
Definition: rtppkt.h:164
A base class for both IncomingRTPPkt and OutgoingRTPPkt.
Definition: rtppkt.h:72
void srtpAuthenticate(RTPPacket *rtp, uint32 roc, uint8 *tag)
Compute the authentication tag.
RTPAudio * rtp
Definition: rtp.cpp:88
#define REPLAY_WINDOW_SIZE
Definition: CryptoContext.h:28
The implementation for a SRTP cryptographic context.
Definition: CryptoContext.h:82
void hmacSha1Ctx(void *ctx, const uint8_t *data, uint32_t data_length, uint8_t *mac, int32_t *mac_length)
Compute SHA1 HMAC.
Definition: gcrypthmac.cpp:79
const int SrtpEncryptionAESF8
Definition: CryptoContext.h:36
void * createSha1HmacContext(uint8_t *key, int32_t key_length)
Create and initialize a SHA1 HMAC context.
Definition: gcrypthmac.cpp:70
void macSkeinCtx(void *ctx, const uint8_t *data, uint32_t data_length, uint8_t *mac)
Compute Skein MAC.
Definition: macSkein.cpp:61
void freeSkeinMacContext(void *ctx)
Free Skein MAC context.
Definition: macSkein.cpp:85
void freeSha1HmacContext(void *ctx)
Free SHA1 HMAC context.
Definition: gcrypthmac.cpp:113
void * createSkeinMacContext(uint8_t *key, int32_t key_length, int32_t mac_length, SkeinSize_t skeinSize)
Create and initialize a Skein MAC context.
Definition: macSkein.cpp:51
const int SrtpEncryptionTWOF8
Definition: CryptoContext.h:38
uint32 master_key_length
Functions to compute SHA1 HAMAC.
bool checkReplay(uint16 newSeqNumber)
Check for packet replay.
void srtpEncrypt(RTPPacket *rtp, uint64 index, uint32 ssrc)
Perform SRTP encryption.
const uint8 *const getPayload() const
Definition: rtppkt.h:121
~CryptoContext()
Destructor.
uint32 master_salt_length
const int SrtpEncryptionTWOCM
Definition: CryptoContext.h:37
CryptoContext * newCryptoContextForSSRC(uint32 ssrc, int roc, int64 keyDerivRate)
Derive a new Crypto Context for use with a new SSRC.
Function that provide Skein MAC support.
uint32 getRawPacketSize() const
Get the raw packet length, including header, extension, payload and padding.
Definition: rtppkt.h:278
const int SrtpAuthenticationSkeinHmac
Definition: CryptoContext.h:32
uint32 guessed_roc
const unsigned char *const getRawPacket() const
Get the raw packet as it will be sent through the network.
Definition: rtppkt.h:268
uint8 getPaddingSize() const
Get the number of octets padding the end of the payload section.
Definition: rtppkt.h:174
CryptoContext(uint32 ssrc)
Constructor for empty SRTP cryptographic context.
void update(uint16 newSeqNumber)
Update the SRTP packet index.
uint8 * master_key
uint32 getPayloadSize() const
Definition: rtppkt.h:128
const int SrtpEncryptionNull
Definition: CryptoContext.h:34
int32 getTagLength() const
Get the length of the SRTP authentication tag in bytes.
const int SrtpAuthenticationSha1Hmac
Definition: CryptoContext.h:31
void deriveSrtpKeys(uint64 index)
Perform key derivation according to SRTP specification.
uint64 guessIndex(uint16 newSeqNumber)
Compute (guess) the new SRTP index based on the sequence number of a received RTP packet...
uint8 * master_salt
const int SrtpAuthenticationNull
Definition: CryptoContext.h:30
const int SrtpEncryptionAESCM
Definition: CryptoContext.h:35