blob: 1b596c8ba1619ea4ded695576e20a3346e852e2b [file] [log] [blame]
Alexandre Lision51140e12013-12-02 10:54:09 -05001/*
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
52typedef 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 */
77class SrtpSymCrypto {
78public:
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
245private:
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)
252int 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#include <arpa/inet.h>
262
263using namespace std;
264
265static void hexdump(const char* title, const unsigned char *s, int l)
266{
267 int n=0;
268
269 if (s == NULL) return;
270
271 fprintf(stderr, "%s",title);
272 for( ; n < l ; ++n) {
273 if((n%16) == 0)
274 fprintf(stderr, "\n%04x",n);
275 fprintf(stderr, " %02x",s[n]);
276 }
277 fprintf(stderr, "\n");
278}
279
280/*
281 * The F8 test vectors according to RFC3711
282 */
283static unsigned char salt[] = {0x32, 0xf2, 0x87, 0x0d};
284
285static unsigned char iv[] = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
286 0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a};
287
288static unsigned char key[]= { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18,
289 0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c};
290
291static unsigned char payload[] = {
292 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61,
293 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
294 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
295 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
296 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; // 39 bytes
297
298static unsigned char cipherText[] = {
299 0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01,
300 0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd,
301 0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4,
302 0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f,
303 0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02}; // 39 bytes
304
305// static unsigned char rtpPacketHeader[] = {
306// 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
307// 0x5c, 0x62, 0x15, 0x99};
308
309static unsigned char rtpPacket[] = {
310 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
311 0x5c, 0x62, 0x15, 0x99, // header
312 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, // payload
313 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
314 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
315 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
316 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67};
317static uint32_t ROC = 0xd462564a;
318
319int testF8()
320{
321 SrtpSymCrypto* aesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
322 SrtpSymCrypto* f8AesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
323
324 aesCipher->setNewKey(key, sizeof(key));
325
326 /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
327 *
328 * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
329 * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
330 * ------------\ /--------------------------------------------------
331 * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
332 */
333
334 unsigned char derivedIv[16];
335 uint32_t* ui32p = (uint32_t*)derivedIv;
336
337 memcpy(derivedIv, rtpPacket, 12);
338 derivedIv[0] = 0;
339
340 // set ROC in network order into IV
341 ui32p[3] = htonl(ROC);
342
343 int32_t pad = 0;
344
345 if (memcmp(iv, derivedIv, 16) != 0) {
346 cerr << "Wrong IV constructed" << endl;
347 hexdump("derivedIv", derivedIv, 16);
348 hexdump("test vector Iv", iv, 16);
349 return -1;
350 }
351
352 aesCipher->f8_deriveForIV(f8AesCipher, key, sizeof(key), salt, sizeof(salt));
353
354 // now encrypt the RTP payload data
355 aesCipher->f8_encrypt(rtpPacket + 12, sizeof(rtpPacket)-12+pad,
356 derivedIv, f8AesCipher);
357
358 // compare with test vector cipher data
359 if (memcmp(rtpPacket+12, cipherText, sizeof(rtpPacket)-12+pad) != 0) {
360 cerr << "cipher data mismatch" << endl;
361 hexdump("computed cipher data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
362 hexdump("Test vcetor cipher data", cipherText, sizeof(cipherText));
363 return -1;
364 }
365
366 // Now decrypt the data to get the payload data again
367 aesCipher->f8_encrypt(rtpPacket+12, sizeof(rtpPacket)-12+pad, derivedIv, f8AesCipher);
368
369 // compare decrypted data with test vector payload data
370 if (memcmp(rtpPacket+12, payload, sizeof(rtpPacket)-12+pad) != 0) {
371 cerr << "payload data mismatch" << endl;
372 hexdump("computed payload data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
373 hexdump("Test vector payload data", payload, sizeof(payload));
374 return -1;
375 }
376 return 0;
377}
378#endif
379
380/**
381 * @}
382 */
383
384#endif
385
386/** EMACS **
387 * Local variables:
388 * mode: c++
389 * c-default-style: ellemtel
390 * c-basic-offset: 4
391 * End:
392 */
393