Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: cipher_funcs.c
5 : : *
6 : : * Purpose: Cipher functions used by fwknop
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This library is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include <stdio.h>
32 : : #include <string.h>
33 : :
34 : : #ifdef WIN32
35 : : #include <sys/timeb.h>
36 : : #include <time.h>
37 : : #include <stdlib.h>
38 : : #else
39 : : #include <sys/time.h>
40 : : #endif
41 : :
42 : : #include "fko_common.h"
43 : : #include "cipher_funcs.h"
44 : : #include "digest.h"
45 : :
46 : : #ifndef WIN32
47 : : #ifndef RAND_FILE
48 : : #define RAND_FILE "/dev/urandom"
49 : : #endif
50 : : #endif
51 : :
52 : : /* Get random data.
53 : : */
54 : : void
55 : 412 : get_random_data(unsigned char *data, const size_t len)
56 : : {
57 : : uint32_t i;
58 : : #ifdef WIN32
59 : : int rnum;
60 : : struct _timeb tb;
61 : :
62 : : _ftime_s(&tb);
63 : :
64 : : srand((uint32_t)(tb.time*1000)+tb.millitm);
65 : :
66 : : for(i=0; i<len; i++)
67 : : {
68 : : rnum = rand();
69 : : *(data+i) = rnum % 0xff;
70 : : }
71 : : #else
72 : : FILE *rfd;
73 : : struct timeval tv;
74 : 412 : int do_time = 0;
75 : : size_t amt_read;
76 : :
77 : : /* Attempt to read seed data from /dev/urandom. If that does not
78 : : * work, then fall back to a time-based method (less secure, but
79 : : * probably more portable).
80 : : */
81 [ + - ]: 412 : if((rfd = fopen(RAND_FILE, "r")) == NULL)
82 : : {
83 : : do_time = 1;
84 : : }
85 : : else
86 : : {
87 : : /* Read seed from /dev/urandom
88 : : */
89 : 412 : amt_read = fread(data, len, 1, rfd);
90 : 412 : fclose(rfd);
91 : :
92 [ - + ]: 412 : if (amt_read != 1)
93 : 0 : do_time = 1;
94 : : }
95 : :
96 [ - + ]: 412 : if (do_time)
97 : : {
98 : : /* Seed based on time (current usecs).
99 : : */
100 : 0 : gettimeofday(&tv, NULL);
101 : 0 : srand(tv.tv_usec);
102 : :
103 [ # # ]: 0 : for(i=0; i<len; i++)
104 : 0 : *(data+i) = rand() % 0xff;
105 : : }
106 : :
107 : : #endif
108 : :
109 : 412 : }
110 : :
111 : :
112 : : /*** These are Rijndael-specific functions ***/
113 : :
114 : : /* Rijndael function to generate initial salt and initialization vector
115 : : * (iv). This is is done to be compatible with the data produced via OpenSSL
116 : : */
117 : : static void
118 : 412 : rij_salt_and_iv(RIJNDAEL_context *ctx, const char *key,
119 : : const int key_len, const unsigned char *data, const int mode_flag)
120 : : {
121 : 412 : char pw_buf[RIJNDAEL_MAX_KEYSIZE] = {0};
122 : 412 : unsigned char tmp_buf[MD5_DIGEST_LEN+RIJNDAEL_MAX_KEYSIZE+RIJNDAEL_BLOCKSIZE] = {0};
123 : 412 : unsigned char kiv_buf[RIJNDAEL_MAX_KEYSIZE+RIJNDAEL_BLOCKSIZE] = {0}; /* Key and IV buffer */
124 : 412 : unsigned char md5_buf[MD5_DIGEST_LEN] = {0}; /* Buffer for computed md5 hash */
125 : :
126 : 412 : int final_key_len = 0;
127 : 412 : size_t kiv_len = 0;
128 : :
129 [ - + ]: 412 : if(mode_flag == FKO_ENC_MODE_CBC_LEGACY_IV)
130 : : {
131 : : /* Pad the pw with '0' chars up to the minimum Rijndael key size.
132 : : *
133 : : * This maintains compatibility with the old perl code if absolutely
134 : : * necessary in some scenarios, but is not recommended to use since it
135 : : * breaks compatibility with how OpenSSL implements AES and introduces
136 : : * other problems. This code will be removed altogether in a future
137 : : * version of fwknop.
138 : : */
139 [ # # ]: 0 : if(key_len < RIJNDAEL_MIN_KEYSIZE)
140 : : {
141 : 0 : memcpy(pw_buf, key, key_len);
142 : 0 : memset(pw_buf+key_len, '0', RIJNDAEL_MIN_KEYSIZE - key_len);
143 : : final_key_len = RIJNDAEL_MIN_KEYSIZE;
144 : : }
145 : : else
146 : : {
147 : 0 : memcpy(pw_buf, key, key_len);
148 : 0 : final_key_len = key_len;
149 : : }
150 : : }
151 : : else
152 : : {
153 : 412 : memcpy(pw_buf, key, key_len);
154 : 412 : final_key_len = key_len;
155 : : }
156 : :
157 : : /* If we are decrypting, data will contain the salt. Otherwise,
158 : : * for encryption, we generate a random salt.
159 : : */
160 [ - + ]: 412 : if(data != NULL)
161 : : {
162 : : /* Pull the salt from the data
163 : : */
164 : 0 : memcpy(ctx->salt, (data+SALT_LEN), SALT_LEN);
165 : : }
166 : : else
167 : : {
168 : : /* Generate a random 8-byte salt.
169 : : */
170 : 412 : get_random_data(ctx->salt, SALT_LEN);
171 : : }
172 : :
173 : : /* Now generate the key and initialization vector.
174 : : * (again it is the perl Crypt::CBC way, with a touch of
175 : : * fwknop).
176 : : */
177 : 412 : memcpy(tmp_buf+MD5_DIGEST_LEN, pw_buf, final_key_len);
178 : 412 : memcpy(tmp_buf+MD5_DIGEST_LEN+final_key_len, ctx->salt, SALT_LEN);
179 : :
180 [ + + ]: 1648 : while(kiv_len < sizeof(kiv_buf))
181 : : {
182 [ + + ]: 1236 : if(kiv_len == 0)
183 : 412 : md5(md5_buf, tmp_buf+MD5_DIGEST_LEN, final_key_len+SALT_LEN);
184 : : else
185 : 824 : md5(md5_buf, tmp_buf, MD5_DIGEST_LEN+final_key_len+SALT_LEN);
186 : :
187 : : memcpy(tmp_buf, md5_buf, MD5_DIGEST_LEN);
188 : :
189 : 1236 : memcpy(kiv_buf + kiv_len, md5_buf, MD5_DIGEST_LEN);
190 : :
191 : 1236 : kiv_len += MD5_DIGEST_LEN;
192 : : }
193 : :
194 : 412 : memcpy(ctx->key, kiv_buf, RIJNDAEL_MAX_KEYSIZE);
195 : 412 : memcpy(ctx->iv, kiv_buf+RIJNDAEL_MAX_KEYSIZE, RIJNDAEL_BLOCKSIZE);
196 : 412 : }
197 : :
198 : : /* Initialization entry point.
199 : : */
200 : : static void
201 : 412 : rijndael_init(RIJNDAEL_context *ctx, const char *key,
202 : : const int key_len, const unsigned char *data,
203 : : int encryption_mode)
204 : : {
205 : :
206 : : /* The default is Rijndael in CBC mode
207 : : */
208 [ + + ]: 412 : if(encryption_mode == FKO_ENC_MODE_CBC
209 : 412 : || encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV)
210 : 387 : ctx->mode = MODE_CBC;
211 [ + + ]: 25 : else if(encryption_mode == FKO_ENC_MODE_CTR)
212 : 4 : ctx->mode = MODE_CTR;
213 [ - + ]: 21 : else if(encryption_mode == FKO_ENC_MODE_PCBC)
214 : 0 : ctx->mode = MODE_PCBC;
215 [ + + ]: 21 : else if(encryption_mode == FKO_ENC_MODE_OFB)
216 : 2 : ctx->mode = MODE_OFB;
217 [ + + ]: 19 : else if(encryption_mode == FKO_ENC_MODE_CFB)
218 : 1 : ctx->mode = MODE_CFB;
219 [ + - ]: 18 : else if(encryption_mode == FKO_ENC_MODE_ECB)
220 : 18 : ctx->mode = MODE_ECB;
221 : : else /* shouldn't get this far */
222 : 0 : ctx->mode = encryption_mode;
223 : :
224 : : /* Generate the salt and initialization vector.
225 : : */
226 : 412 : rij_salt_and_iv(ctx, key, key_len, data, encryption_mode);
227 : :
228 : : /* Intialize our Rijndael context.
229 : : */
230 : 412 : rijndael_setup(ctx, RIJNDAEL_MAX_KEYSIZE, ctx->key);
231 : 412 : }
232 : :
233 : : /* Take a chunk of data, encrypt it in the same way OpenSSL would
234 : : * (with a default of AES in CBC mode).
235 : : */
236 : : size_t
237 : 412 : rij_encrypt(unsigned char *in, size_t in_len,
238 : : const char *key, const int key_len,
239 : : unsigned char *out, int encryption_mode)
240 : : {
241 : : RIJNDAEL_context ctx;
242 : : int i, pad_val;
243 : 412 : unsigned char *ondx = out;
244 : :
245 : 412 : rijndael_init(&ctx, key, key_len, NULL, encryption_mode);
246 : :
247 : : /* Prepend the salt to the ciphertext...
248 : : */
249 : : memcpy(ondx, "Salted__", SALT_LEN);
250 : 412 : ondx+=SALT_LEN;
251 : : memcpy(ondx, ctx.salt, SALT_LEN);
252 : 412 : ondx+=SALT_LEN;
253 : :
254 : : /* Add padding to the original plaintext to ensure that it is a
255 : : * multiple of the Rijndael block size
256 : : */
257 : 412 : pad_val = RIJNDAEL_BLOCKSIZE - (in_len % RIJNDAEL_BLOCKSIZE);
258 [ + + ]: 3333 : for (i = (int)in_len; i < ((int)in_len+pad_val); i++)
259 : 2921 : in[i] = pad_val;
260 : :
261 : 412 : block_encrypt(&ctx, in, in_len+pad_val, ondx, ctx.iv);
262 : :
263 : 412 : ondx += in_len+pad_val;
264 : :
265 : 412 : zero_buf((char *)ctx.key, RIJNDAEL_MAX_KEYSIZE);
266 : 412 : zero_buf((char *)ctx.iv, RIJNDAEL_BLOCKSIZE);
267 : 412 : zero_buf((char *)ctx.salt, SALT_LEN);
268 : :
269 : 412 : return(ondx - out);
270 : : }
271 : :
272 : : /* Decrypt the given data.
273 : : */
274 : : size_t
275 : 0 : rij_decrypt(unsigned char *in, size_t in_len,
276 : : const char *key, const int key_len,
277 : : unsigned char *out, int encryption_mode)
278 : : {
279 : : RIJNDAEL_context ctx;
280 : 0 : int i, pad_val, pad_err = 0;
281 : : unsigned char *pad_s;
282 : 0 : unsigned char *ondx = out;
283 : :
284 [ # # ][ # # ]: 0 : if(in == NULL || key == NULL || out == NULL)
285 : : return 0;
286 : :
287 : 0 : rijndael_init(&ctx, key, key_len, in, encryption_mode);
288 : :
289 : : /* Remove the first block since it contains the salt (it was consumed
290 : : * by the rijndael_init() function above).
291 : : */
292 : 0 : in_len -= RIJNDAEL_BLOCKSIZE;
293 : 0 : memmove(in, in+RIJNDAEL_BLOCKSIZE, in_len);
294 : :
295 : 0 : block_decrypt(&ctx, in, in_len, out, ctx.iv);
296 : :
297 : 0 : ondx += in_len;
298 : :
299 : : /* Find and remove padding.
300 : : */
301 : 0 : pad_val = *(ondx-1);
302 : :
303 [ # # ]: 0 : if(pad_val >= 0 && pad_val <= RIJNDAEL_BLOCKSIZE)
304 : : {
305 : 0 : pad_s = ondx - pad_val;
306 : :
307 [ # # ]: 0 : for(i=0; i < (ondx-pad_s); i++)
308 : : {
309 [ # # ]: 0 : if(*(pad_s+i) != pad_val)
310 : 0 : pad_err++;
311 : : }
312 : :
313 [ # # ]: 0 : if(pad_err == 0)
314 : 0 : ondx -= pad_val;
315 : : }
316 : :
317 : 0 : *ondx = '\0';
318 : :
319 : 0 : zero_buf((char *)ctx.key, RIJNDAEL_MAX_KEYSIZE);
320 : 0 : zero_buf((char *)ctx.iv, RIJNDAEL_BLOCKSIZE);
321 : 0 : zero_buf((char *)ctx.salt, SALT_LEN);
322 : :
323 : 0 : return(ondx - out);
324 : : }
325 : :
326 : : /* See if we need to add the "Salted__" string to the front of the
327 : : * encrypted data.
328 : : */
329 : : int
330 : 411 : add_salted_str(fko_ctx_t ctx)
331 : : {
332 : : char *tbuf;
333 : :
334 : : #if AFL_FUZZING
335 : 411 : ctx->added_salted_str = 1;
336 : : return(FKO_SUCCESS);
337 : : #endif
338 : :
339 : : /* We only add the base64 encoded salt to data that is already base64
340 : : * encoded
341 : : */
342 : : if(is_base64((unsigned char *)ctx->encrypted_msg,
343 : : ctx->encrypted_msg_len) == 0)
344 : : return(FKO_ERROR_INVALID_DATA_ENCODE_NOTBASE64);
345 : :
346 : : if(constant_runtime_cmp(ctx->encrypted_msg,
347 : : B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN) != 0)
348 : : {
349 : : /* We need to realloc space for the salt.
350 : : */
351 : : tbuf = realloc(ctx->encrypted_msg, ctx->encrypted_msg_len
352 : : + B64_RIJNDAEL_SALT_STR_LEN+1);
353 : : if(tbuf == NULL)
354 : : return(FKO_ERROR_MEMORY_ALLOCATION);
355 : :
356 : : memmove(tbuf+B64_RIJNDAEL_SALT_STR_LEN, tbuf, ctx->encrypted_msg_len);
357 : :
358 : : ctx->encrypted_msg = memcpy(tbuf,
359 : : B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN);
360 : :
361 : : /* Adjust the encoded msg len for added SALT value and Make sure we
362 : : * are still a properly NULL-terminated string (Ubuntu was one system
363 : : * for which this was an issue).
364 : : */
365 : : ctx->encrypted_msg_len += B64_RIJNDAEL_SALT_STR_LEN;
366 : : tbuf[ctx->encrypted_msg_len] = '\0';
367 : :
368 : : ctx->added_salted_str = 1;
369 : : }
370 : :
371 : : return(FKO_SUCCESS);
372 : : }
373 : :
374 : : /* See if we need to add the "hQ" string to the front of the
375 : : * encrypted data.
376 : : */
377 : : int
378 : 0 : add_gpg_prefix(fko_ctx_t ctx)
379 : : {
380 : : char *tbuf;
381 : :
382 : : /* We only add the base64 encoded salt to data that is already base64
383 : : * encoded
384 : : */
385 [ # # ]: 0 : if(is_base64((unsigned char *)ctx->encrypted_msg,
386 : 0 : ctx->encrypted_msg_len) == 0)
387 : : return(FKO_ERROR_INVALID_DATA_ENCODE_NOTBASE64);
388 : :
389 [ # # ]: 0 : if(constant_runtime_cmp(ctx->encrypted_msg,
390 : : B64_GPG_PREFIX, B64_GPG_PREFIX_STR_LEN) != 0)
391 : : {
392 : : /* We need to realloc space for the prefix.
393 : : */
394 : 0 : tbuf = realloc(ctx->encrypted_msg, ctx->encrypted_msg_len
395 : 0 : + B64_GPG_PREFIX_STR_LEN+1);
396 [ # # ]: 0 : if(tbuf == NULL)
397 : : return(FKO_ERROR_MEMORY_ALLOCATION);
398 : :
399 : 0 : memmove(tbuf+B64_GPG_PREFIX_STR_LEN, tbuf, ctx->encrypted_msg_len);
400 : :
401 : 0 : ctx->encrypted_msg = memcpy(tbuf,
402 : : B64_GPG_PREFIX, B64_GPG_PREFIX_STR_LEN);
403 : :
404 : : /* Adjust the encoded msg len for added SALT value and Make sure we
405 : : * are still a properly NULL-terminated string (Ubuntu was one system
406 : : * for which this was an issue).
407 : : */
408 : 0 : ctx->encrypted_msg_len += B64_GPG_PREFIX_STR_LEN;
409 : 0 : tbuf[ctx->encrypted_msg_len] = '\0';
410 : :
411 : 0 : ctx->added_gpg_prefix = 1;
412 : : }
413 : :
414 : : return(FKO_SUCCESS);
415 : : }
416 : :
417 : : /***EOF***/
|