1 /*
2 Copyright (C) 2005, 2004, 2010, 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
32
33
34 #ifndef SRTPSYMCRYPTO_H
35 #define SRTPSYMCRYPTO_H
36
37 /**
38 * @file SrtpSymCrypto.h
39 * @brief Class which implements SRTP AES cryptographic functions
40 *
41 * @ingroup GNU_ZRTP
42 * @{
43 */
44
45 #include <stdint.h>
46 #include <CryptoContext.h>
47
48 #ifndef SRTP_BLOCK_SIZE
49 #define SRTP_BLOCK_SIZE 16
50 #endif
51
52 typedef struct _f8_ctx {
53 unsigned char *S; ///< Intermetiade buffer
54 unsigned char *ivAccent; ///< second IV
55 uint32_t J; ///< Counter
56 } F8_CIPHER_CTX;
57
58 /**
59 * Implments the SRTP encryption modes as defined in RFC3711
60 *
61 * The SRTP specification defines two encryption modes, AES-CTR
62 * (AES Counter mode) and AES-F8 mode. The AES-CTR is required,
63 * AES-F8 is optional.
64 *
65 * Both modes are desinged to encrypt/decrypt data of arbitrary length
66 * (with a specified upper limit, refer to RFC 3711). These modes do
67 * <em>not</em> require that the amount of data to encrypt is a multiple
68 * of the AES blocksize (16 bytes), no padding is necessary.
69 *
70 * The implementation uses the openSSL library as its cryptographic
71 * backend.
72 *
73 * @author Erik Eliasson <eliasson@it.kth.se>
74 * @author Johan Bilien <jobi@via.ecp.fr>
75 * @author Werner Dittmann <Werner.Dittmann@t-online.de>
76 */
77 class SrtpSymCrypto {
78 public:
79 SrtpSymCrypto(int algo = SrtpEncryptionAESCM);
80
81 /**
82 * Constructor that initializes key data
83 *
84 * @param key
85 * Pointer to key bytes.
86 * @param key_length
87 * Number of key bytes.
88 */
89 SrtpSymCrypto(uint8_t* key, int32_t key_length, int algo = SrtpEncryptionAESCM);
90
91 ~SrtpSymCrypto();
92
93 /**
94 * Encrypts the inpout to the output.
95 *
96 * Encrypts one input block to one output block. Each block
97 * is 16 bytes according to the AES encryption algorithm used.
98 *
99 * @param input
100 * Pointer to input block, must be 16 bytes
101 *
102 * @param output
103 * Pointer to output block, must be 16 bytes
104 */
105 void encrypt( const uint8_t* input, uint8_t* output );
106
107 /**
108 * Set new key
109 *
110 * @param key
111 * Pointer to key data, must have at least a size of keyLength
112 *
113 * @param keyLength
114 * Length of the key in bytes, must be 16, 24, or 32
115 *
116 * @return
117 * false if key could not set.
118 */
119 bool setNewKey(const uint8_t* key, int32_t keyLength);
120
121 /**
122 * Computes the cipher stream for AES CM mode.
123 *
124 * @param output
125 * Pointer to a buffer that receives the cipher stream. Must be
126 * at least <code>length</code> bytes long.
127 *
128 * @param length
129 * Number of cipher stream bytes to produce. Usually the same
130 * length as the data to be encrypted.
131 *
132 * @param iv
133 * The initialization vector as input to create the cipher stream.
134 * Refer to chapter 4.1.1 in RFC 3711.
135 */
136 void get_ctr_cipher_stream(uint8_t* output, uint32_t length, uint8_t* iv);
137
138 /**
139 * Counter-mode encryption.
140 *
141 * This method performs the AES CM encryption.
142 *
143 * @param input
144 * Pointer to input buffer, must be <code>inputLen</code> bytes.
145 *
146 * @param inputLen
147 * Number of bytes to process.
148 *
149 * @param output
150 * Pointer to output buffer, must be <code>inputLen</code> bytes.
151 *
152 * @param iv
153 * The initialization vector as input to create the cipher stream.
154 * Refer to chapter 4.1.1 in RFC 3711.
155 */
156 void ctr_encrypt(const uint8_t* input, uint32_t inputLen, uint8_t* output, uint8_t* iv );
157
158 /**
159 * Counter-mode encryption, in place.
160 *
161 * This method performs the AES CM encryption.
162 *
163 * @param data
164 * Pointer to input and output block, must be <code>dataLen</code>
165 * bytes.
166 *
167 * @param data_length
168 * Number of bytes to process.
169 *
170 * @param iv
171 * The initialization vector as input to create the cipher stream.
172 * Refer to chapter 4.1.1 in RFC 3711.
173 */
174 void ctr_encrypt(uint8_t* data, uint32_t data_length, uint8_t* iv );
175
176 /**
177 * Derive a AES context to compute the IV'.
178 *
179 * See chapter 4.1.2.1 in RFC 3711.
180 *
181 * @param f8Cipher
182 * Pointer to the AES context that will be used to encrypt IV to IV'
183 *
184 * @param key
185 * The master key
186 *
187 * @param keyLen
188 * Length of the master key.
189 *
190 * @param salt
191 * Master salt.
192 *
193 * @param saltLen
194 * length of master salt.
195 */
196 void f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen, uint8_t* salt, int32_t saltLen);
197
198 /**
199 * AES F8 mode encryption, in place.
200 *
201 * This method performs the AES F8 encryption, see chapter 4.1.2
202 * in RFC 3711.
203 *
204 * @param data
205 * Pointer to input and output block, must be <code>dataLen</code>
206 * bytes.
207 *
208 * @param dataLen
209 * Number of bytes to process.
210 *
211 * @param iv
212 * The initialization vector as input to create the cipher stream.
213 * Refer to chapter 4.1.1 in RFC 3711.
214 *
215 * @param f8Cipher
216 * An AES cipher context used to encrypt IV to IV'.
217 */
218 void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* iv, SrtpSymCrypto* f8Cipher);
219
220 /**
221 * AES F8 mode encryption.
222 *
223 * This method performs the AES F8 encryption, see chapter 4.1.2
224 * in RFC 3711.
225 *
226 * @param data
227 * Pointer to input and output block, must be <code>dataLen</code>
228 * bytes.
229 *
230 * @param dataLen
231 * Number of bytes to process.
232 *
233 * @param out
234 * Pointer to output buffer, must be <code>dataLen</code> bytes.
235 *
236 * @param iv
237 * The initialization vector as input to create the cipher stream.
238 * Refer to chapter 4.1.1 in RFC 3711.
239 *
240 * @param f8Cipher
241 * An AES cipher context used to encrypt IV to IV'.
242 */
243 void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* out, uint8_t* iv, SrtpSymCrypto* f8Cipher);
244
245 private:
246 int processBlock(F8_CIPHER_CTX* f8ctx, const uint8_t* in, int32_t length, uint8_t* out);
247 void* key;
248 int32_t algorithm;
249 };
250
251 #pragma GCC visibility push(default)
252 int testF8();
253 #pragma GCC visibility pop
254
255 /* Only SrtpSymCrypto functions define the MAKE_F8_TEST */
256 #ifdef MAKE_F8_TEST
257
258 #include <cstring>
259 #include <iostream>
260 #include <cstdio>
261
262 #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
263 #include <windows.h>
264 #else
265 #include <arpa/inet.h>
266 #endif
267
268 using namespace std;
269
hexdump(const char * title,const unsigned char * s,int l)270 static void hexdump(const char* title, const unsigned char *s, int l)
271 {
272 int n=0;
273
274 if (s == NULL) return;
275
276 fprintf(stderr, "%s",title);
277 for( ; n < l ; ++n) {
278 if((n%16) == 0)
279 fprintf(stderr, "\n%04x",n);
280 fprintf(stderr, " %02x",s[n]);
281 }
282 fprintf(stderr, "\n");
283 }
284
285 /*
286 * The F8 test vectors according to RFC3711
287 */
288 static unsigned char salt[] = {0x32, 0xf2, 0x87, 0x0d};
289
290 static unsigned char iv[] = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
291 0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a};
292
293 static unsigned char key[]= { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18,
294 0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c};
295
296 static unsigned char payload[] = {
297 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61,
298 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
299 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
300 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
301 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; // 39 bytes
302
303 static unsigned char cipherText[] = {
304 0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01,
305 0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd,
306 0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4,
307 0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f,
308 0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02}; // 39 bytes
309
310 // static unsigned char rtpPacketHeader[] = {
311 // 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
312 // 0x5c, 0x62, 0x15, 0x99};
313
314 static unsigned char rtpPacket[] = {
315 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
316 0x5c, 0x62, 0x15, 0x99, // header
317 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, // payload
318 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
319 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
320 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
321 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67};
322 static uint32_t ROC = 0xd462564a;
323
testF8()324 int testF8()
325 {
326 SrtpSymCrypto* aesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
327 SrtpSymCrypto* f8AesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
328
329 aesCipher->setNewKey(key, sizeof(key));
330
331 /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
332 *
333 * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
334 * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
335 * ------------\ /--------------------------------------------------
336 * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
337 */
338
339 unsigned char derivedIv[16];
340 uint32_t* ui32p = (uint32_t*)derivedIv;
341
342 memcpy(derivedIv, rtpPacket, 12);
343 derivedIv[0] = 0;
344
345 // set ROC in network order into IV
346 ui32p[3] = htonl(ROC);
347
348 int32_t pad = 0;
349
350 if (memcmp(iv, derivedIv, 16) != 0) {
351 cerr << "Wrong IV constructed" << endl;
352 hexdump("derivedIv", derivedIv, 16);
353 hexdump("test vector Iv", iv, 16);
354 return -1;
355 }
356
357 aesCipher->f8_deriveForIV(f8AesCipher, key, sizeof(key), salt, sizeof(salt));
358
359 // now encrypt the RTP payload data
360 aesCipher->f8_encrypt(rtpPacket + 12, sizeof(rtpPacket)-12+pad,
361 derivedIv, f8AesCipher);
362
363 // compare with test vector cipher data
364 if (memcmp(rtpPacket+12, cipherText, sizeof(rtpPacket)-12+pad) != 0) {
365 cerr << "cipher data mismatch" << endl;
366 hexdump("computed cipher data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
367 hexdump("Test vcetor cipher data", cipherText, sizeof(cipherText));
368 return -1;
369 }
370
371 // Now decrypt the data to get the payload data again
372 aesCipher->f8_encrypt(rtpPacket+12, sizeof(rtpPacket)-12+pad, derivedIv, f8AesCipher);
373
374 // compare decrypted data with test vector payload data
375 if (memcmp(rtpPacket+12, payload, sizeof(rtpPacket)-12+pad) != 0) {
376 cerr << "payload data mismatch" << endl;
377 hexdump("computed payload data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
378 hexdump("Test vector payload data", payload, sizeof(payload));
379 return -1;
380 }
381 return 0;
382 }
383 #endif
384
385 /**
386 * @}
387 */
388
389 #endif
390
391 /** EMACS **
392 * Local variables:
393 * mode: c++
394 * c-default-style: ellemtel
395 * c-basic-offset: 4
396 * End:
397 */
398
399