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