ccRTP 2.1.2
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gcryptSrtpSymCrypto.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2005, 2004, 2012 Erik Eliasson, Johan Bilien, Werner Dittmann
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  * In addition, as a special exception, the copyright holders give
19  * permission to link the code of portions of this program with the
20  * OpenSSL library under certain conditions as described in each
21  * individual source file, and distribute linked combinations
22  * including the two.
23  * You must obey the GNU General Public License in all respects
24  * for all of the code used other than OpenSSL. If you modify
25  * file(s) with this exception, you may extend this exception to your
26  * version of the file(s), but you are not obligated to do so. If you
27  * do not wish to do so, delete this exception statement from your
28  * version. If you delete this exception statement from all source
29  * files in the program, then also delete it here.
30 */
31 
38 extern void initializeGcrypt();
39 
40 #define MAKE_F8_TEST
41 
42 #include <gcrypt.h> // the include of gcrypt
43 #include <stdlib.h>
44 #include <crypto/SrtpSymCrypto.h>
45 #include <crypto/twofish.h>
46 
47 #include <stdio.h>
48 
49 SrtpSymCrypto::SrtpSymCrypto(int algo) : key(NULL), algorithm(algo) {
51 }
52 
53 SrtpSymCrypto::SrtpSymCrypto( uint8_t* k, int32_t keyLength, int algo) :
54  key(NULL), algorithm(algo) {
55 
57  setNewKey(k, keyLength);
58 }
59 
61  if (key) {
63  gcry_cipher_close(static_cast<gcry_cipher_hd_t>(key));
65  memset(key, 0, sizeof(Twofish_key));
66  delete[] (uint8_t*)key;
67  }
68  key = NULL;
69  }
70 }
71 
72 static int twoFishInit = 0;
73 
74 bool SrtpSymCrypto::setNewKey(const uint8_t* k, int32_t keyLength) {
75 
76  // release an existing key before setting a new one
78  if (key != NULL) {
79  gcry_cipher_close(static_cast<gcry_cipher_hd_t>(key));
80  key = NULL;
81  }
82 
83  int algo = 0;
84  if (keyLength == 16) {
85  algo = GCRY_CIPHER_AES;
86  }
87  else if (keyLength == 32) {
88  algo = GCRY_CIPHER_AES256;
89  }
90  else {
91  return false;
92  }
93  gcry_cipher_hd_t tmp;
94  gcry_cipher_open(&tmp, algo, GCRY_CIPHER_MODE_ECB, 0);
95  key = tmp;
96  gcry_cipher_setkey(static_cast<gcry_cipher_hd_t>(key), k, keyLength);
97  }
99  if (!twoFishInit) {
101  twoFishInit = 1;
102  }
103  if (key != NULL)
104  delete[] (uint8_t*)key;
105 
106  key = new uint8_t[sizeof(Twofish_key)];
107  memset(key, 0, sizeof(Twofish_key));
108  Twofish_prepare_key((Twofish_Byte*)k, keyLength, (Twofish_key*)key);
109  }
110  else
111  return false;
112 
113  return true;
114 }
115 
116 
117 void SrtpSymCrypto::encrypt(const uint8_t* input, uint8_t* output) {
118  if (key != NULL) {
120  gcry_cipher_encrypt (static_cast<gcry_cipher_hd_t>(key),
121  output, SRTP_BLOCK_SIZE, input, SRTP_BLOCK_SIZE);
124  (Twofish_Byte*)output);
125  }
126 }
127 
128 void SrtpSymCrypto::get_ctr_cipher_stream( uint8_t* output, uint32_t length,
129  uint8_t* iv ) {
130  uint16_t ctr = 0;
131 
132  unsigned char temp[SRTP_BLOCK_SIZE];
133 
134  for(ctr = 0; ctr < length/SRTP_BLOCK_SIZE; ctr++ ){
135  //compute the cipher stream
136  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
137  iv[15] = (uint8_t)((ctr & 0x00FF));
138 
139  encrypt(iv, &output[ctr*SRTP_BLOCK_SIZE]);
140  }
141  if ((length % SRTP_BLOCK_SIZE) > 0) {
142  // Treat the last bytes:
143  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
144  iv[15] = (uint8_t)((ctr & 0x00FF));
145 
146  encrypt(iv, temp);
147  memcpy(&output[ctr*SRTP_BLOCK_SIZE], temp, length % SRTP_BLOCK_SIZE);
148  }
149 }
150 
151 void SrtpSymCrypto::ctr_encrypt( const uint8_t* input, uint32_t input_length,
152  uint8_t* output, uint8_t* iv ) {
153 
154  if (key == NULL)
155  return;
156 
157  uint16_t ctr = 0;
158  unsigned char temp[SRTP_BLOCK_SIZE];
159 
160  int l = input_length/SRTP_BLOCK_SIZE;
161  for ( ctr = 0; ctr < l; ctr++ ) {
162  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
163  iv[15] = (uint8_t)((ctr & 0x00FF));
164 
165  encrypt(iv, temp);
166  for (int i = 0; i < SRTP_BLOCK_SIZE; i++ ) {
167  *output++ = temp[i] ^ *input++;
168  }
169 
170  }
171  l = input_length % SRTP_BLOCK_SIZE;
172  if (l > 0) {
173  // Treat the last bytes:
174  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
175  iv[15] = (uint8_t)((ctr & 0x00FF));
176 
177  encrypt(iv, temp);
178  for (int i = 0; i < l; i++ ) {
179  *output++ = temp[i] ^ *input++;
180  }
181  }
182 }
183 
184 void SrtpSymCrypto::ctr_encrypt( uint8_t* data, uint32_t data_length, uint8_t* iv ) {
185 
186  if (key == NULL)
187  return;
188 
189  uint16_t ctr = 0;
190  unsigned char temp[SRTP_BLOCK_SIZE];
191 
192  int l = data_length/SRTP_BLOCK_SIZE;
193  for (ctr = 0; ctr < l; ctr++ ) {
194  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
195  iv[15] = (uint8_t)((ctr & 0x00FF));
196 
197  encrypt(iv, temp);
198  for (int i = 0; i < SRTP_BLOCK_SIZE; i++ ) {
199  *data++ ^= temp[i];
200  }
201 
202  }
203  l = data_length % SRTP_BLOCK_SIZE;
204  if (l > 0) {
205  // Treat the last bytes:
206  iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
207  iv[15] = (uint8_t)((ctr & 0x00FF));
208 
209  encrypt(iv, temp);
210  for (int i = 0; i < l; i++ ) {
211  *data++ ^= temp[i];
212  }
213  }
214 
215 }
216 
217 void SrtpSymCrypto::f8_encrypt(const uint8_t* data, uint32_t data_length, uint8_t* iv, SrtpSymCrypto* f8Cipher ) {
218 
219  f8_encrypt(data, data_length, const_cast<uint8_t*>(data), iv, f8Cipher);
220 }
221 
222 #define MAX_KEYLEN 32
223 
224 void SrtpSymCrypto::f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen,
225  uint8_t* salt, int32_t saltLen) {
226 
227  unsigned char *cp_in, *cp_in1, *cp_out;
228 
229  unsigned char maskedKey[MAX_KEYLEN];
230  unsigned char saltMask[MAX_KEYLEN];
231 
232  if (keyLen > MAX_KEYLEN)
233  return;
234 
235  if (saltLen > keyLen)
236  return;
237  /*
238  * First copy the salt into the mask field, then fill with 0x55 to
239  * get a full key.
240  */
241  memcpy(saltMask, salt, saltLen);
242  memset(saltMask+saltLen, 0x55, keyLen-saltLen);
243 
244  /*
245  * XOR the original key with the above created mask to
246  * get the special key.
247  */
248  cp_out = maskedKey;
249  cp_in = key;
250  cp_in1 = saltMask;
251  for (int i = 0; i < keyLen; i++) {
252  *cp_out++ = *cp_in++ ^ *cp_in1++;
253  }
254  /*
255  * Prepare the a new AES cipher with the special key to compute IV'
256  */
257  f8Cipher->setNewKey(maskedKey, keyLen);
258 }
259 
260 void SrtpSymCrypto::f8_encrypt(const uint8_t* in, uint32_t in_length, uint8_t* out,
261  uint8_t* iv, SrtpSymCrypto* f8Cipher ) {
262 
263  int offset = 0;
264 
265  unsigned char ivAccent[SRTP_BLOCK_SIZE];
266  unsigned char S[SRTP_BLOCK_SIZE];
267 
268  F8_CIPHER_CTX f8ctx;
269 
270  if (key == NULL)
271  return;
272 
273  /*
274  * Get memory for the derived IV (IV')
275  */
276  f8ctx.ivAccent = ivAccent;
277  /*
278  * Use the derived IV encryption setup to encrypt the original IV to produce IV'.
279  */
280  f8Cipher->encrypt(iv, f8ctx.ivAccent);
281 
282  f8ctx.J = 0; // initialize the counter
283  f8ctx.S = S; // get the key stream buffer
284 
285  memset(f8ctx.S, 0, SRTP_BLOCK_SIZE); // initial value for key stream
286 
287  while (in_length >= SRTP_BLOCK_SIZE) {
288  processBlock(&f8ctx, in+offset, SRTP_BLOCK_SIZE, out+offset);
289  in_length -= SRTP_BLOCK_SIZE;
290  offset += SRTP_BLOCK_SIZE;
291  }
292  if (in_length > 0) {
293  processBlock(&f8ctx, in+offset, in_length, out+offset);
294  }
295 }
296 
297 int SrtpSymCrypto::processBlock(F8_CIPHER_CTX *f8ctx, const uint8_t* in, int32_t length, uint8_t* out) {
298 
299  int i;
300  const uint8_t *cp_in;
301  uint8_t* cp_in1, *cp_out;
302  uint32_t *ui32p;
303 
304  /*
305  * XOR the previous key stream with IV'
306  * ( S(-1) xor IV' )
307  */
308  cp_in = f8ctx->ivAccent;
309  cp_out = f8ctx->S;
310  for (i = 0; i < SRTP_BLOCK_SIZE; i++) {
311  *cp_out++ ^= *cp_in++;
312  }
313  /*
314  * Now XOR (S(n-1) xor IV') with the current counter, then increment the counter
315  */
316  ui32p = (uint32_t *)f8ctx->S;
317  ui32p[3] ^= htonl(f8ctx->J);
318  f8ctx->J++;
319  /*
320  * Now compute the new key stream using encrypt
321  */
322  encrypt(f8ctx->S, f8ctx->S);
323  /*
324  * as the last step XOR the plain text with the key stream to produce
325  * the ciphertext.
326  */
327  cp_out = out;
328  cp_in = in;
329  cp_in1 = f8ctx->S;
330  for (i = 0; i < length; i++) {
331  *cp_out++ = *cp_in++ ^ *cp_in1++;
332  }
333  return length;
334 }
335 
Implments the SRTP encryption modes as defined in RFC3711.
Definition: SrtpSymCrypto.h:77
bool setNewKey(const uint8_t *key, int32_t keyLength)
Set new key.
Structure that contains a prepared Twofish key.
Definition: twofish.h:95
unsigned char Twofish_Byte
A Twofish_Byte must be an unsigned 8-bit integer.
Definition: twofish.h:40
int Twofish_initialise()
Initialise and test the Twofish implementation.
unsigned char * ivAccent
second IV
Definition: SrtpSymCrypto.h:54
const int SrtpEncryptionAESF8
Definition: CryptoContext.h:36
void get_ctr_cipher_stream(uint8_t *output, uint32_t length, uint8_t *iv)
Computes the cipher stream for AES CM mode.
#define SRTP_BLOCK_SIZE
Definition: SrtpSymCrypto.h:49
void initializeGcrypt()
const int SrtpEncryptionTWOF8
Definition: CryptoContext.h:38
int processBlock(F8_CIPHER_CTX *f8ctx, const uint8_t *in, int32_t length, uint8_t *out)
uint32_t J
Counter.
Definition: SrtpSymCrypto.h:55
int32_t algorithm
const int SrtpEncryptionTWOCM
Definition: CryptoContext.h:37
SrtpSymCrypto(int algo=SrtpEncryptionAESCM)
void ctr_encrypt(const uint8_t *input, uint32_t inputLen, uint8_t *output, uint8_t *iv)
Counter-mode encryption.
void f8_encrypt(const uint8_t *data, uint32_t dataLen, uint8_t *iv, SrtpSymCrypto *f8Cipher)
AES F8 mode encryption, in place.
unsigned char * S
Intermetiade buffer.
Definition: SrtpSymCrypto.h:53
Class which implements SRTP AES cryptographic functions.
void Twofish_encrypt(Twofish_key *xkey, Twofish_Byte p[16], Twofish_Byte c[16])
Encrypt a single block of data.
int Twofish_prepare_key(Twofish_Byte key[], int key_len, Twofish_key *xkey)
Convert a cipher key to the internal form used for encryption and decryption.
void f8_deriveForIV(SrtpSymCrypto *f8Cipher, uint8_t *key, int32_t keyLen, uint8_t *salt, int32_t saltLen)
Derive a AES context to compute the IV'.
const int SrtpEncryptionAESCM
Definition: CryptoContext.h:35
#define MAX_KEYLEN
void encrypt(const uint8_t *input, uint8_t *output)
Encrypts the inpout to the output.