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 : 2402540 : 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 : 2402540 : 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 [ + + ]: 2402540 : if((rfd = fopen(RAND_FILE, "r")) == NULL)
82 : : {
83 : : do_time = 1;
84 : : }
85 : : else
86 : : {
87 : : /* Read seed from /dev/urandom
88 : : */
89 : 2402514 : amt_read = fread(data, len, 1, rfd);
90 : 2402514 : fclose(rfd);
91 : :
92 [ - + ]: 2402514 : if (amt_read != 1)
93 : 0 : do_time = 1;
94 : : }
95 : :
96 [ + + ]: 2402540 : if (do_time)
97 : : {
98 : : /* Seed based on time (current usecs).
99 : : */
100 : 26 : gettimeofday(&tv, NULL);
101 : 26 : srand(tv.tv_usec);
102 : :
103 [ + + ]: 234 : for(i=0; i<len; i++)
104 : 208 : *(data+i) = rand() % 0xff;
105 : : }
106 : :
107 : : #endif
108 : :
109 : 2402540 : }
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 : 4893035 : 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 : 4893035 : char pw_buf[RIJNDAEL_MAX_KEYSIZE] = {0};
122 : 4893035 : unsigned char tmp_buf[MD5_DIGEST_LEN+RIJNDAEL_MAX_KEYSIZE+RIJNDAEL_BLOCKSIZE] = {0};
123 : 4893035 : unsigned char kiv_buf[RIJNDAEL_MAX_KEYSIZE+RIJNDAEL_BLOCKSIZE] = {0}; /* Key and IV buffer */
124 : 4893035 : unsigned char md5_buf[MD5_DIGEST_LEN] = {0}; /* Buffer for computed md5 hash */
125 : :
126 : 4893035 : int final_key_len = 0;
127 : 4893035 : size_t kiv_len = 0;
128 : :
129 [ + + ]: 4893035 : 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 [ + + ]: 1210852 : if(key_len < RIJNDAEL_MIN_KEYSIZE)
140 : : {
141 : 1210840 : memcpy(pw_buf, key, key_len);
142 : 1210840 : memset(pw_buf+key_len, '0', RIJNDAEL_MIN_KEYSIZE - key_len);
143 : : final_key_len = RIJNDAEL_MIN_KEYSIZE;
144 : : }
145 : : else
146 : : {
147 : 12 : memcpy(pw_buf, key, key_len);
148 : 12 : final_key_len = key_len;
149 : : }
150 : : }
151 : : else
152 : : {
153 : 3682183 : memcpy(pw_buf, key, key_len);
154 : 3682183 : 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 [ + + ]: 4893035 : if(data != NULL)
161 : : {
162 : : /* Pull the salt from the data
163 : : */
164 : 2490723 : memcpy(ctx->salt, (data+SALT_LEN), SALT_LEN);
165 : : }
166 : : else
167 : : {
168 : : /* Generate a random 8-byte salt.
169 : : */
170 : 2402312 : 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 : 4893035 : memcpy(tmp_buf+MD5_DIGEST_LEN, pw_buf, final_key_len);
178 : 4893035 : memcpy(tmp_buf+MD5_DIGEST_LEN+final_key_len, ctx->salt, SALT_LEN);
179 : :
180 [ + + ]: 19572140 : while(kiv_len < sizeof(kiv_buf))
181 : : {
182 [ + + ]: 14679105 : if(kiv_len == 0)
183 : 4893035 : md5(md5_buf, tmp_buf+MD5_DIGEST_LEN, final_key_len+SALT_LEN);
184 : : else
185 : 9786070 : 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 : 14679105 : memcpy(kiv_buf + kiv_len, md5_buf, MD5_DIGEST_LEN);
190 : :
191 : 14679105 : kiv_len += MD5_DIGEST_LEN;
192 : : }
193 : :
194 : 4893035 : memcpy(ctx->key, kiv_buf, RIJNDAEL_MAX_KEYSIZE);
195 : 4893035 : memcpy(ctx->iv, kiv_buf+RIJNDAEL_MAX_KEYSIZE, RIJNDAEL_BLOCKSIZE);
196 : 4893035 : }
197 : :
198 : : /* Initialization entry point.
199 : : */
200 : : static void
201 : 4893035 : 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 [ + + ]: 4893035 : if(encryption_mode == FKO_ENC_MODE_CBC
209 : 4893035 : || encryption_mode == FKO_ENC_MODE_CBC_LEGACY_IV)
210 : 4892716 : ctx->mode = MODE_CBC;
211 [ + + ]: 319 : else if(encryption_mode == FKO_ENC_MODE_CTR)
212 : 54 : ctx->mode = MODE_CTR;
213 [ + + ]: 265 : else if(encryption_mode == FKO_ENC_MODE_PCBC)
214 : 50 : ctx->mode = MODE_PCBC;
215 [ + + ]: 215 : else if(encryption_mode == FKO_ENC_MODE_OFB)
216 : 54 : ctx->mode = MODE_OFB;
217 [ + + ]: 161 : else if(encryption_mode == FKO_ENC_MODE_CFB)
218 : 54 : ctx->mode = MODE_CFB;
219 [ + + ]: 107 : else if(encryption_mode == FKO_ENC_MODE_ECB)
220 : 57 : ctx->mode = MODE_ECB;
221 : : else /* shouldn't get this far */
222 : 50 : ctx->mode = encryption_mode;
223 : :
224 : : /* Generate the salt and initialization vector.
225 : : */
226 : 4893035 : rij_salt_and_iv(ctx, key, key_len, data, encryption_mode);
227 : :
228 : : /* Intialize our Rijndael context.
229 : : */
230 : 4893035 : rijndael_setup(ctx, RIJNDAEL_MAX_KEYSIZE, ctx->key);
231 : 4893035 : }
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 : 2402312 : 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 : 2402312 : unsigned char *ondx = out;
244 : :
245 : 2402312 : 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 : 2402312 : ondx+=SALT_LEN;
251 : : memcpy(ondx, ctx.salt, SALT_LEN);
252 : 2402312 : 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 : 2402312 : pad_val = RIJNDAEL_BLOCKSIZE - (in_len % RIJNDAEL_BLOCKSIZE);
258 [ + + ]: 22022227 : for (i = (int)in_len; i < ((int)in_len+pad_val); i++)
259 : 19619915 : in[i] = pad_val;
260 : :
261 : 2402312 : block_encrypt(&ctx, in, in_len+pad_val, ondx, ctx.iv);
262 : :
263 : 2402312 : ondx += in_len+pad_val;
264 : :
265 : 2402312 : zero_buf((char *)ctx.key, RIJNDAEL_MAX_KEYSIZE);
266 : 2402312 : zero_buf((char *)ctx.iv, RIJNDAEL_BLOCKSIZE);
267 : 2402312 : zero_buf((char *)ctx.salt, SALT_LEN);
268 : :
269 : 2402312 : return(ondx - out);
270 : : }
271 : :
272 : : /* Decrypt the given data.
273 : : */
274 : : size_t
275 : 2490723 : 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 : 2490723 : int i, pad_val, pad_err = 0;
281 : : unsigned char *pad_s;
282 : 2490723 : unsigned char *ondx = out;
283 : :
284 [ + - ][ + - ]: 2490723 : if(in == NULL || key == NULL || out == NULL)
285 : : return 0;
286 : :
287 : 2490723 : 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 : 2490723 : in_len -= RIJNDAEL_BLOCKSIZE;
293 : 2490723 : memmove(in, in+RIJNDAEL_BLOCKSIZE, in_len);
294 : :
295 : 2490723 : block_decrypt(&ctx, in, in_len, out, ctx.iv);
296 : :
297 : 2490723 : ondx += in_len;
298 : :
299 : : /* Find and remove padding.
300 : : */
301 : 2490723 : pad_val = *(ondx-1);
302 : :
303 [ + + ]: 2490723 : if(pad_val >= 0 && pad_val <= RIJNDAEL_BLOCKSIZE)
304 : : {
305 : 2311992 : pad_s = ondx - pad_val;
306 : :
307 [ + + ]: 20973679 : for(i=0; i < (ondx-pad_s); i++)
308 : : {
309 [ + + ]: 18661687 : if(*(pad_s+i) != pad_val)
310 : 87817 : pad_err++;
311 : : }
312 : :
313 [ + + ]: 2311992 : if(pad_err == 0)
314 : 2300420 : ondx -= pad_val;
315 : : }
316 : :
317 : 2490723 : *ondx = '\0';
318 : :
319 : 2490723 : zero_buf((char *)ctx.key, RIJNDAEL_MAX_KEYSIZE);
320 : 2490723 : zero_buf((char *)ctx.iv, RIJNDAEL_BLOCKSIZE);
321 : 2490723 : zero_buf((char *)ctx.salt, SALT_LEN);
322 : :
323 : 2490723 : 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 : 2713409 : add_salted_str(fko_ctx_t ctx)
331 : : {
332 : : char *tbuf;
333 : :
334 : : /* We only add the base64 encoded salt to data that is already base64
335 : : * encoded
336 : : */
337 [ + - ]: 2713409 : if(is_base64((unsigned char *)ctx->encrypted_msg,
338 : 2713409 : ctx->encrypted_msg_len) == 0)
339 : : return(FKO_ERROR_INVALID_DATA_ENCODE_NOTBASE64);
340 : :
341 [ + - ]: 2713409 : if(constant_runtime_cmp(ctx->encrypted_msg,
342 : : B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN) != 0)
343 : : {
344 : : /* We need to realloc space for the salt.
345 : : */
346 : 5426818 : tbuf = realloc(ctx->encrypted_msg, ctx->encrypted_msg_len
347 : 2713409 : + B64_RIJNDAEL_SALT_STR_LEN+1);
348 [ + + ]: 2713409 : if(tbuf == NULL)
349 : : return(FKO_ERROR_MEMORY_ALLOCATION);
350 : :
351 : 2713327 : memmove(tbuf+B64_RIJNDAEL_SALT_STR_LEN, tbuf, ctx->encrypted_msg_len);
352 : :
353 : 2713327 : ctx->encrypted_msg = memcpy(tbuf,
354 : : B64_RIJNDAEL_SALT, B64_RIJNDAEL_SALT_STR_LEN);
355 : :
356 : : /* Adjust the encoded msg len for added SALT value and Make sure we
357 : : * are still a properly NULL-terminated string (Ubuntu was one system
358 : : * for which this was an issue).
359 : : */
360 : 2713327 : ctx->encrypted_msg_len += B64_RIJNDAEL_SALT_STR_LEN;
361 : 2713327 : tbuf[ctx->encrypted_msg_len] = '\0';
362 : :
363 : 2713327 : ctx->added_salted_str = 1;
364 : : }
365 : :
366 : : return(FKO_SUCCESS);
367 : : }
368 : :
369 : : /* See if we need to add the "hQ" string to the front of the
370 : : * encrypted data.
371 : : */
372 : : int
373 : 66 : add_gpg_prefix(fko_ctx_t ctx)
374 : : {
375 : : char *tbuf;
376 : :
377 : : /* We only add the base64 encoded salt to data that is already base64
378 : : * encoded
379 : : */
380 [ + - ]: 66 : if(is_base64((unsigned char *)ctx->encrypted_msg,
381 : 66 : ctx->encrypted_msg_len) == 0)
382 : : return(FKO_ERROR_INVALID_DATA_ENCODE_NOTBASE64);
383 : :
384 [ + - ]: 66 : if(constant_runtime_cmp(ctx->encrypted_msg,
385 : : B64_GPG_PREFIX, B64_GPG_PREFIX_STR_LEN) != 0)
386 : : {
387 : : /* We need to realloc space for the prefix.
388 : : */
389 : 132 : tbuf = realloc(ctx->encrypted_msg, ctx->encrypted_msg_len
390 : 66 : + B64_GPG_PREFIX_STR_LEN+1);
391 [ + - ]: 66 : if(tbuf == NULL)
392 : : return(FKO_ERROR_MEMORY_ALLOCATION);
393 : :
394 : 66 : memmove(tbuf+B64_GPG_PREFIX_STR_LEN, tbuf, ctx->encrypted_msg_len);
395 : :
396 : 66 : ctx->encrypted_msg = memcpy(tbuf,
397 : : B64_GPG_PREFIX, B64_GPG_PREFIX_STR_LEN);
398 : :
399 : : /* Adjust the encoded msg len for added SALT value and Make sure we
400 : : * are still a properly NULL-terminated string (Ubuntu was one system
401 : : * for which this was an issue).
402 : : */
403 : 66 : ctx->encrypted_msg_len += B64_GPG_PREFIX_STR_LEN;
404 : 66 : tbuf[ctx->encrypted_msg_len] = '\0';
405 : :
406 : 66 : ctx->added_gpg_prefix = 1;
407 : : }
408 : :
409 : : return(FKO_SUCCESS);
410 : : }
411 : :
412 : : /***EOF***/
|