blob: 569e540c0e0c154160e61f5991bf7a64e14f2278 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001/*
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
32/**
33 * @author Erik Eliasson <eliasson@it.kth.se>
34 * @author Johan Bilien <jobi@via.ecp.fr>
35 * @author Werner Dittmann <Werner.Dittmann@t-online.de>
36 */
37
38#define MAKE_F8_TEST
39
40#include <stdlib.h>
41#include <openssl/aes.h> // the include of openSSL
42#include <crypto/SrtpSymCrypto.h>
43#include <crypto/twofish.h>
44#include <string.h>
45#include <stdio.h>
46
47#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
48#include <windows.h>
49#else
50#include <arpa/inet.h>
51#endif
52
53SrtpSymCrypto::SrtpSymCrypto(int algo):key(NULL), algorithm(algo) {
54}
55
56SrtpSymCrypto::SrtpSymCrypto( uint8_t* k, int32_t keyLength, int algo ):
57 key(NULL), algorithm(algo) {
58
59 setNewKey(k, keyLength);
60}
61
62SrtpSymCrypto::~SrtpSymCrypto() {
63 if (key != NULL) {
64 if (algorithm == SrtpEncryptionAESCM || algorithm == SrtpEncryptionAESF8) {
65 memset(key, 0, sizeof(AES_KEY) );
66 }
67 else if (algorithm == SrtpEncryptionTWOCM || algorithm == SrtpEncryptionTWOF8) {
68 memset(key, 0, sizeof(Twofish_key));
69 }
70 delete[] (uint8_t*)key;
71 key = NULL;
72 }
73}
74
75static int twoFishInit = 0;
76
77bool SrtpSymCrypto::setNewKey(const uint8_t* k, int32_t keyLength) {
78 // release an existing key before setting a new one
79 if (key != NULL)
80 delete[] (uint8_t*)key;
81
82 if (!(keyLength == 16 || keyLength == 32)) {
83 return false;
84 }
85 if (algorithm == SrtpEncryptionAESCM || algorithm == SrtpEncryptionAESF8) {
86 key = new uint8_t[sizeof(AES_KEY)];
87 memset(key, 0, sizeof(AES_KEY) );
88 AES_set_encrypt_key(k, keyLength*8, (AES_KEY *)key);
89 }
90 else if (algorithm == SrtpEncryptionTWOCM || algorithm == SrtpEncryptionTWOF8) {
91 if (!twoFishInit) {
92 Twofish_initialise();
93 twoFishInit = 1;
94 }
95 key = new uint8_t[sizeof(Twofish_key)];
96 memset(key, 0, sizeof(Twofish_key));
97 Twofish_prepare_key((Twofish_Byte*)k, keyLength, (Twofish_key*)key);
98 }
99 else
100 return false;
101
102 return true;
103}
104
105
106void SrtpSymCrypto::encrypt(const uint8_t* input, uint8_t* output ) {
107 if (algorithm == SrtpEncryptionAESCM || algorithm == SrtpEncryptionAESF8) {
108 AES_encrypt(input, output, (AES_KEY *)key);
109 }
110 else if (algorithm == SrtpEncryptionTWOCM || algorithm == SrtpEncryptionTWOF8) {
111 Twofish_encrypt((Twofish_key*)key, (Twofish_Byte*)input,
112 (Twofish_Byte*)output);
113 }
114}
115
116void SrtpSymCrypto::get_ctr_cipher_stream(uint8_t* output, uint32_t length,
117 uint8_t* iv ) {
118 uint16_t ctr = 0;
119 unsigned char temp[SRTP_BLOCK_SIZE];
120
121 for(ctr = 0; ctr < length/SRTP_BLOCK_SIZE; ctr++) {
122 //compute the cipher stream
123 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
124 iv[15] = (uint8_t)((ctr & 0x00FF));
125
126 encrypt(iv, &output[ctr*SRTP_BLOCK_SIZE]);
127 }
128 if ((length % SRTP_BLOCK_SIZE) > 0) {
129 // Treat the last bytes:
130 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
131 iv[15] = (uint8_t)((ctr & 0x00FF));
132
133 encrypt(iv, temp);
134 memcpy(&output[ctr*SRTP_BLOCK_SIZE], temp, length % SRTP_BLOCK_SIZE );
135 }
136}
137
138void SrtpSymCrypto::ctr_encrypt(const uint8_t* input, uint32_t input_length,
139 uint8_t* output, uint8_t* iv ) {
140
141 if (key == NULL)
142 return;
143
144 uint16_t ctr = 0;
145 unsigned char temp[SRTP_BLOCK_SIZE];
146
147 int l = input_length/SRTP_BLOCK_SIZE;
148 for (ctr = 0; ctr < l; ctr++ ) {
149 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
150 iv[15] = (uint8_t)((ctr & 0x00FF));
151
152 encrypt(iv, temp);
153 for (int i = 0; i < SRTP_BLOCK_SIZE; i++ ) {
154 *output++ = temp[i] ^ *input++;
155 }
156
157 }
158 l = input_length % SRTP_BLOCK_SIZE;
159 if (l > 0) {
160 // Treat the last bytes:
161 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
162 iv[15] = (uint8_t)((ctr & 0x00FF));
163
164 encrypt(iv, temp);
165 for (int i = 0; i < l; i++ ) {
166 *output++ = temp[i] ^ *input++;
167 }
168 }
169}
170
171void SrtpSymCrypto::ctr_encrypt( uint8_t* data, uint32_t data_length, uint8_t* iv ) {
172
173 if (key == NULL)
174 return;
175
176 uint16_t ctr = 0;
177 unsigned char temp[SRTP_BLOCK_SIZE];
178
179 int l = data_length/SRTP_BLOCK_SIZE;
180 for (ctr = 0; ctr < l; ctr++ ) {
181 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
182 iv[15] = (uint8_t)((ctr & 0x00FF));
183
184 encrypt(iv, temp);
185 for (int i = 0; i < SRTP_BLOCK_SIZE; i++ ) {
186 *data++ ^= temp[i];
187 }
188
189 }
190 l = data_length % SRTP_BLOCK_SIZE;
191 if (l > 0) {
192 // Treat the last bytes:
193 iv[14] = (uint8_t)((ctr & 0xFF00) >> 8);
194 iv[15] = (uint8_t)((ctr & 0x00FF));
195
196 encrypt(iv, temp);
197 for (int i = 0; i < l; i++ ) {
198 *data++ ^= temp[i];
199 }
200 }
201}
202
203void SrtpSymCrypto::f8_encrypt(const uint8_t* data, uint32_t data_length,
204 uint8_t* iv, SrtpSymCrypto* f8Cipher ) {
205
206 f8_encrypt(data, data_length, const_cast<uint8_t*>(data), iv, f8Cipher);
207}
208
209#define MAX_KEYLEN 32
210
211void SrtpSymCrypto::f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen,
212 uint8_t* salt, int32_t saltLen) {
213
214 unsigned char *cp_in, *cp_in1, *cp_out;
215
216 unsigned char maskedKey[MAX_KEYLEN];
217 unsigned char saltMask[MAX_KEYLEN];
218
219 if (keyLen > MAX_KEYLEN)
220 return;
221
222 if (saltLen > keyLen)
223 return;
224 /*
225 * First copy the salt into the mask field, then fill with 0x55 to
226 * get a full key.
227 */
228 memcpy(saltMask, salt, saltLen);
229 memset(saltMask+saltLen, 0x55, keyLen-saltLen);
230
231 /*
232 * XOR the original key with the above created mask to
233 * get the special key.
234 */
235 cp_out = maskedKey;
236 cp_in = key;
237 cp_in1 = saltMask;
238 for (int i = 0; i < keyLen; i++) {
239 *cp_out++ = *cp_in++ ^ *cp_in1++;
240 }
241 /*
242 * Prepare the a new AES cipher with the special key to compute IV'
243 */
244 f8Cipher->setNewKey(maskedKey, keyLen);
245}
246
247void SrtpSymCrypto::f8_encrypt(const uint8_t* in, uint32_t in_length, uint8_t* out,
248 uint8_t* iv, SrtpSymCrypto* f8Cipher ) {
249
250
251 int offset = 0;
252
253 unsigned char ivAccent[SRTP_BLOCK_SIZE];
254 unsigned char S[SRTP_BLOCK_SIZE];
255
256 F8_CIPHER_CTX f8ctx;
257
258 if (key == NULL)
259 return;
260 /*
261 * Get memory for the derived IV (IV')
262 */
263 f8ctx.ivAccent = ivAccent;
264 /*
265 * Use the derived IV encryption setup to encrypt the original IV to produce IV'.
266 */
267 f8Cipher->encrypt(iv, f8ctx.ivAccent);
268
269 f8ctx.J = 0; // initialize the counter
270 f8ctx.S = S; // get the key stream buffer
271
272 memset(f8ctx.S, 0, SRTP_BLOCK_SIZE); // initial value for key stream
273
274 while (in_length >= SRTP_BLOCK_SIZE) {
275 processBlock(&f8ctx, in+offset, SRTP_BLOCK_SIZE, out+offset);
276 in_length -= SRTP_BLOCK_SIZE;
277 offset += SRTP_BLOCK_SIZE;
278 }
279 if (in_length > 0) {
280 processBlock(&f8ctx, in+offset, in_length, out+offset);
281 }
282}
283
284int SrtpSymCrypto::processBlock(F8_CIPHER_CTX *f8ctx, const uint8_t* in, int32_t length, uint8_t* out) {
285
286 int i;
287 const uint8_t *cp_in;
288 uint8_t* cp_in1, *cp_out;
289 uint32_t *ui32p;
290
291 /*
292 * XOR the previous key stream with IV'
293 * ( S(-1) xor IV' )
294 */
295 cp_in = f8ctx->ivAccent;
296 cp_out = f8ctx->S;
297 for (i = 0; i < SRTP_BLOCK_SIZE; i++) {
298 *cp_out++ ^= *cp_in++;
299 }
300 /*
301 * Now XOR (S(n-1) xor IV') with the current counter, then increment the counter
302 */
303 ui32p = (uint32_t *)f8ctx->S;
304 ui32p[3] ^= htonl(f8ctx->J);
305 f8ctx->J++;
306 /*
307 * Now compute the new key stream using AES encrypt
308 */
309 encrypt(f8ctx->S, f8ctx->S);
310 /*
311 * as the last step XOR the plain text with the key stream to produce
312 * the ciphertext.
313 */
314 cp_out = out;
315 cp_in = in;
316 cp_in1 = f8ctx->S;
317 for (i = 0; i < length; i++) {
318 *cp_out++ = *cp_in++ ^ *cp_in1++;
319 }
320 return length;
321}
322
323
324/** EMACS **
325 * Local variables:
326 * mode: c++
327 * c-default-style: ellemtel
328 * c-basic-offset: 4
329 * End:
330 */
331