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