blob: 09bdcabe43270bc49e789cb714678ba71b5022d9 [file] [log] [blame]
Alexandre Lision51140e12013-12-02 10:54:09 -05001/*
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -05002 Copyright (C) 2008-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 * 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
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050039 * @brief Class which implements SRTP cryptographic functions
Alexandre Lision51140e12013-12-02 10:54:09 -050040 *
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/**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050059 * @brief Implments the SRTP encryption modes as defined in RFC3711
Alexandre Lision51140e12013-12-02 10:54:09 -050060 *
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 *
Alexandre Lision51140e12013-12-02 10:54:09 -050073 * @author Werner Dittmann <Werner.Dittmann@t-online.de>
74 */
75class SrtpSymCrypto {
76public:
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050077 /**
78 * @brief Constructor that does not initialize key data
79 *
80 * @param algo
81 * The Encryption algorithm to use.Possible values are <code>
82 * SrtpEncryptionNull, SrtpEncryptionAESCM, SrtpEncryptionAESF8
83 * SrtpEncryptionTWOCM, SrtpEncryptionTWOF8</code>. See chapter 4.1.1
84 * for CM (Counter mode) and 4.1.2 for F8 mode.
85 */
Alexandre Lision51140e12013-12-02 10:54:09 -050086 SrtpSymCrypto(int algo = SrtpEncryptionAESCM);
87
88 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050089 * @brief Constructor that initializes key data
Alexandre Lision51140e12013-12-02 10:54:09 -050090 *
91 * @param key
92 * Pointer to key bytes.
93 * @param key_length
94 * Number of key bytes.
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -050095 * @param algo
96 * The Encryption algorithm to use.Possible values are <code>
97 * SrtpEncryptionNull, SrtpEncryptionAESCM, SrtpEncryptionAESF8
98 * SrtpEncryptionTWOCM, SrtpEncryptionTWOF8</code>. See chapter 4.1.1
99 * for CM (Counter mode) and 4.1.2 for F8 mode.
Alexandre Lision51140e12013-12-02 10:54:09 -0500100 */
101 SrtpSymCrypto(uint8_t* key, int32_t key_length, int algo = SrtpEncryptionAESCM);
102
103 ~SrtpSymCrypto();
104
105 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500106 * @brief Encrypts the input to the output.
Alexandre Lision51140e12013-12-02 10:54:09 -0500107 *
108 * Encrypts one input block to one output block. Each block
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500109 * is 16 bytes according to the encryption algorithms used.
Alexandre Lision51140e12013-12-02 10:54:09 -0500110 *
111 * @param input
112 * Pointer to input block, must be 16 bytes
113 *
114 * @param output
115 * Pointer to output block, must be 16 bytes
116 */
117 void encrypt( const uint8_t* input, uint8_t* output );
118
119 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500120 * @brief Set new key
Alexandre Lision51140e12013-12-02 10:54:09 -0500121 *
122 * @param key
123 * Pointer to key data, must have at least a size of keyLength
124 *
125 * @param keyLength
126 * Length of the key in bytes, must be 16, 24, or 32
127 *
128 * @return
129 * false if key could not set.
130 */
131 bool setNewKey(const uint8_t* key, int32_t keyLength);
132
133 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500134 * @brief Computes the cipher stream for AES CM mode.
Alexandre Lision51140e12013-12-02 10:54:09 -0500135 *
136 * @param output
137 * Pointer to a buffer that receives the cipher stream. Must be
138 * at least <code>length</code> bytes long.
139 *
140 * @param length
141 * Number of cipher stream bytes to produce. Usually the same
142 * length as the data to be encrypted.
143 *
144 * @param iv
145 * The initialization vector as input to create the cipher stream.
146 * Refer to chapter 4.1.1 in RFC 3711.
147 */
148 void get_ctr_cipher_stream(uint8_t* output, uint32_t length, uint8_t* iv);
149
150 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500151 * @brief Counter-mode encryption.
Alexandre Lision51140e12013-12-02 10:54:09 -0500152 *
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500153 * This method performs the CM encryption.
Alexandre Lision51140e12013-12-02 10:54:09 -0500154 *
155 * @param input
156 * Pointer to input buffer, must be <code>inputLen</code> bytes.
157 *
158 * @param inputLen
159 * Number of bytes to process.
160 *
161 * @param output
162 * Pointer to output buffer, must be <code>inputLen</code> bytes.
163 *
164 * @param iv
165 * The initialization vector as input to create the cipher stream.
166 * Refer to chapter 4.1.1 in RFC 3711.
167 */
168 void ctr_encrypt(const uint8_t* input, uint32_t inputLen, uint8_t* output, uint8_t* iv );
169
170 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500171 * @brief Counter-mode encryption, in place.
Alexandre Lision51140e12013-12-02 10:54:09 -0500172 *
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500173 * This method performs the CM encryption.
Alexandre Lision51140e12013-12-02 10:54:09 -0500174 *
175 * @param data
176 * Pointer to input and output block, must be <code>dataLen</code>
177 * bytes.
178 *
179 * @param data_length
180 * Number of bytes to process.
181 *
182 * @param iv
183 * The initialization vector as input to create the cipher stream.
184 * Refer to chapter 4.1.1 in RFC 3711.
185 */
186 void ctr_encrypt(uint8_t* data, uint32_t data_length, uint8_t* iv );
187
188 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500189 * @brief Derive a cipher context to compute the IV'.
Alexandre Lision51140e12013-12-02 10:54:09 -0500190 *
191 * See chapter 4.1.2.1 in RFC 3711.
192 *
193 * @param f8Cipher
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500194 * Pointer to the cipher context that will be used to encrypt IV to IV'
Alexandre Lision51140e12013-12-02 10:54:09 -0500195 *
196 * @param key
197 * The master key
198 *
199 * @param keyLen
200 * Length of the master key.
201 *
202 * @param salt
203 * Master salt.
204 *
205 * @param saltLen
206 * length of master salt.
207 */
208 void f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen, uint8_t* salt, int32_t saltLen);
209
210 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500211 * @brief F8 mode encryption, in place.
Alexandre Lision51140e12013-12-02 10:54:09 -0500212 *
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500213 * This method performs the F8 encryption, see chapter 4.1.2 in RFC 3711.
Alexandre Lision51140e12013-12-02 10:54:09 -0500214 *
215 * @param data
216 * Pointer to input and output block, must be <code>dataLen</code>
217 * bytes.
218 *
219 * @param dataLen
220 * Number of bytes to process.
221 *
222 * @param iv
223 * The initialization vector as input to create the cipher stream.
224 * Refer to chapter 4.1.1 in RFC 3711.
225 *
226 * @param f8Cipher
227 * An AES cipher context used to encrypt IV to IV'.
228 */
229 void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* iv, SrtpSymCrypto* f8Cipher);
230
231 /**
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500232 * @brief F8 mode encryption.
Alexandre Lision51140e12013-12-02 10:54:09 -0500233 *
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500234 * This method performs the F8 encryption, see chapter 4.1.2 in RFC 3711.
Alexandre Lision51140e12013-12-02 10:54:09 -0500235 *
236 * @param data
237 * Pointer to input and output block, must be <code>dataLen</code>
238 * bytes.
239 *
240 * @param dataLen
241 * Number of bytes to process.
242 *
243 * @param out
244 * Pointer to output buffer, must be <code>dataLen</code> bytes.
245 *
246 * @param iv
247 * The initialization vector as input to create the cipher stream.
248 * Refer to chapter 4.1.1 in RFC 3711.
249 *
250 * @param f8Cipher
251 * An AES cipher context used to encrypt IV to IV'.
252 */
253 void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* out, uint8_t* iv, SrtpSymCrypto* f8Cipher);
254
255private:
256 int processBlock(F8_CIPHER_CTX* f8ctx, const uint8_t* in, int32_t length, uint8_t* out);
257 void* key;
258 int32_t algorithm;
259};
260
261#pragma GCC visibility push(default)
262int testF8();
263#pragma GCC visibility pop
264
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500265/* Only SrtpSymCrypto functions defines the MAKE_F8_TEST */
Alexandre Lision51140e12013-12-02 10:54:09 -0500266#ifdef MAKE_F8_TEST
267
268#include <cstring>
269#include <iostream>
270#include <cstdio>
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500271#include <common/osSpecifics.h>
Alexandre Lision51140e12013-12-02 10:54:09 -0500272
273using namespace std;
274
275static void hexdump(const char* title, const unsigned char *s, int l)
276{
277 int n=0;
278
279 if (s == NULL) return;
280
281 fprintf(stderr, "%s",title);
282 for( ; n < l ; ++n) {
283 if((n%16) == 0)
284 fprintf(stderr, "\n%04x",n);
285 fprintf(stderr, " %02x",s[n]);
286 }
287 fprintf(stderr, "\n");
288}
289
290/*
291 * The F8 test vectors according to RFC3711
292 */
293static unsigned char salt[] = {0x32, 0xf2, 0x87, 0x0d};
294
295static unsigned char iv[] = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
296 0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a};
297
298static unsigned char key[]= { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18,
299 0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c};
300
301static unsigned char payload[] = {
302 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61,
303 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
304 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
305 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
306 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; // 39 bytes
307
308static unsigned char cipherText[] = {
309 0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01,
310 0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd,
311 0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4,
312 0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f,
313 0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02}; // 39 bytes
314
315// static unsigned char rtpPacketHeader[] = {
316// 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
317// 0x5c, 0x62, 0x15, 0x99};
318
319static unsigned char rtpPacket[] = {
320 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
321 0x5c, 0x62, 0x15, 0x99, // header
322 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, // payload
323 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
324 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
325 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
326 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67};
327static uint32_t ROC = 0xd462564a;
328
329int testF8()
330{
331 SrtpSymCrypto* aesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
332 SrtpSymCrypto* f8AesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
333
334 aesCipher->setNewKey(key, sizeof(key));
335
336 /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
337 *
338 * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
339 * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
340 * ------------\ /--------------------------------------------------
341 * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
342 */
343
344 unsigned char derivedIv[16];
345 uint32_t* ui32p = (uint32_t*)derivedIv;
346
347 memcpy(derivedIv, rtpPacket, 12);
348 derivedIv[0] = 0;
349
350 // set ROC in network order into IV
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -0500351 ui32p[3] = zrtpHtonl(ROC);
Alexandre Lision51140e12013-12-02 10:54:09 -0500352
353 int32_t pad = 0;
354
355 if (memcmp(iv, derivedIv, 16) != 0) {
356 cerr << "Wrong IV constructed" << endl;
357 hexdump("derivedIv", derivedIv, 16);
358 hexdump("test vector Iv", iv, 16);
359 return -1;
360 }
361
362 aesCipher->f8_deriveForIV(f8AesCipher, key, sizeof(key), salt, sizeof(salt));
363
364 // now encrypt the RTP payload data
365 aesCipher->f8_encrypt(rtpPacket + 12, sizeof(rtpPacket)-12+pad,
366 derivedIv, f8AesCipher);
367
368 // compare with test vector cipher data
369 if (memcmp(rtpPacket+12, cipherText, sizeof(rtpPacket)-12+pad) != 0) {
370 cerr << "cipher data mismatch" << endl;
371 hexdump("computed cipher data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
372 hexdump("Test vcetor cipher data", cipherText, sizeof(cipherText));
373 return -1;
374 }
375
376 // Now decrypt the data to get the payload data again
377 aesCipher->f8_encrypt(rtpPacket+12, sizeof(rtpPacket)-12+pad, derivedIv, f8AesCipher);
378
379 // compare decrypted data with test vector payload data
380 if (memcmp(rtpPacket+12, payload, sizeof(rtpPacket)-12+pad) != 0) {
381 cerr << "payload data mismatch" << endl;
382 hexdump("computed payload data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
383 hexdump("Test vector payload data", payload, sizeof(payload));
384 return -1;
385 }
386 return 0;
387}
388#endif
389
390/**
391 * @}
392 */
393
394#endif
395