Branch data Line data Source code
1 : : /* low-crypto.c --- Shishi crypto wrappers around generic crypto.
2 : : * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of Shishi.
5 : : *
6 : : * Shishi is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * Shishi is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with Shishi; if not, see http://www.gnu.org/licenses or write
18 : : * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA
20 : : *
21 : : */
22 : :
23 : : #include "internal.h"
24 : : #include "gc.h"
25 : : #include "arcfour.h"
26 : : #include <gcrypt.h>
27 : : #include "crc.h"
28 : : #include "low-crypto.h"
29 : :
30 : : int
31 : 14 : _shishi_crypto_init (Shishi * handle)
32 : : {
33 : 14 : int rc = gc_init ();
34 : :
35 [ - + ]: 14 : if (rc != GC_OK)
36 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
37 : :
38 : 14 : return SHISHI_OK;
39 : : }
40 : :
41 : : void
42 : 0 : _shishi_quick_random (void)
43 : : {
44 : 0 : gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
45 : 0 : }
46 : :
47 : : /**
48 : : * shishi_randomize:
49 : : * @handle: shishi handle as allocated by shishi_init().
50 : : * @strong: 0 iff operation should not block, non-0 for very strong randomness.
51 : : * @data: output array to be filled with random data.
52 : : * @datalen: size of output array.
53 : : *
54 : : * Store cryptographically random data of given size in the provided
55 : : * buffer.
56 : : *
57 : : * Return value: Returns %SHISHI_OK iff successful.
58 : : **/
59 : : int
60 : 321 : shishi_randomize (Shishi * handle, int strong, void *data, size_t datalen)
61 : : {
62 : : Gc_rc rc;
63 : :
64 [ - + ]: 321 : if (strong)
65 : 0 : rc = gc_random (data, datalen);
66 : : else
67 : 321 : rc = gc_pseudo_random (data, datalen);
68 : :
69 [ - + ]: 321 : if (rc != GC_OK)
70 : 0 : return SHISHI_FILE_ERROR;
71 : :
72 : 321 : return SHISHI_OK;
73 : : }
74 : :
75 : : /**
76 : : * shishi_crc:
77 : : * @handle: shishi handle as allocated by shishi_init().
78 : : * @in: input character array of data to checksum.
79 : : * @inlen: length of input character array of data to checksum.
80 : : * @out: newly allocated character array with checksum of data.
81 : : *
82 : : * Compute checksum of data using CRC32 modified according to RFC
83 : : * 1510. The @out buffer must be deallocated by the caller.
84 : : *
85 : : * The modifications compared to standard CRC32 is that no initial and
86 : : * final XOR is performed, and that the output is returned in
87 : : * LSB-first order.
88 : : *
89 : : * Return value: Returns SHISHI_OK iff successful.
90 : : **/
91 : : int
92 : 17 : shishi_crc (Shishi * handle, const char *in, size_t inlen, char *out[4])
93 : : {
94 : 17 : uint32_t crc = crc32_update_no_xor (0, in, inlen);
95 : :
96 : 17 : *out = xmalloc (4);
97 : 17 : (*out)[0] = crc & 0xFF;
98 : 17 : (*out)[1] = (crc >> 8) & 0xFF;
99 : 17 : (*out)[2] = (crc >> 16) & 0xFF;
100 : 17 : (*out)[3] = (crc >> 24) & 0xFF;
101 : :
102 : 17 : return SHISHI_OK;
103 : : }
104 : :
105 : : /**
106 : : * shishi_md4:
107 : : * @handle: shishi handle as allocated by shishi_init().
108 : : * @in: input character array of data to hash.
109 : : * @inlen: length of input character array of data to hash.
110 : : * @out: newly allocated character array with hash of data.
111 : : *
112 : : * Compute hash of data using MD4. The @out buffer must be
113 : : * deallocated by the caller.
114 : : *
115 : : * Return value: Returns SHISHI_OK iff successful.
116 : : **/
117 : : int
118 : 20 : shishi_md4 (Shishi * handle, const char *in, size_t inlen, char *out[16])
119 : : {
120 : : Gc_rc rc;
121 : :
122 : 20 : *out = xmalloc (GC_MD4_DIGEST_SIZE);
123 : 20 : rc = gc_md4 (in, inlen, *out);
124 [ - + ]: 20 : if (rc != GC_OK)
125 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
126 : :
127 : 20 : return SHISHI_OK;
128 : : }
129 : :
130 : : /**
131 : : * shishi_md5:
132 : : * @handle: shishi handle as allocated by shishi_init().
133 : : * @in: input character array of data to hash.
134 : : * @inlen: length of input character array of data to hash.
135 : : * @out: newly allocated character array with hash of data.
136 : : *
137 : : * Compute hash of data using MD5. The @out buffer must be
138 : : * deallocated by the caller.
139 : : *
140 : : * Return value: Returns SHISHI_OK iff successful.
141 : : **/
142 : : int
143 : 19 : shishi_md5 (Shishi * handle, const char *in, size_t inlen, char *out[16])
144 : : {
145 : : Gc_rc rc;
146 : :
147 : 19 : *out = xmalloc (GC_MD5_DIGEST_SIZE);
148 : 19 : rc = gc_md5 (in, inlen, *out);
149 [ - + ]: 19 : if (rc != GC_OK)
150 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
151 : :
152 : 19 : return SHISHI_OK;
153 : : }
154 : :
155 : : /**
156 : : * shishi_hmac_md5:
157 : : * @handle: shishi handle as allocated by shishi_init().
158 : : * @key: input character array with key to use.
159 : : * @keylen: length of input character array with key to use.
160 : : * @in: input character array of data to hash.
161 : : * @inlen: length of input character array of data to hash.
162 : : * @outhash: newly allocated character array with keyed hash of data.
163 : : *
164 : : * Compute keyed checksum of data using HMAC-MD5. The @outhash buffer
165 : : * must be deallocated by the caller.
166 : : *
167 : : * Return value: Returns SHISHI_OK iff successful.
168 : : **/
169 : : int
170 : 865 : shishi_hmac_md5 (Shishi * handle,
171 : : const char *key, size_t keylen,
172 : : const char *in, size_t inlen, char *outhash[16])
173 : : {
174 : : Gc_rc rc;
175 : :
176 : 865 : *outhash = xmalloc (GC_MD5_DIGEST_SIZE);
177 : 865 : rc = gc_hmac_md5 (key, keylen, in, inlen, *outhash);
178 [ - + ]: 865 : if (rc != GC_OK)
179 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
180 : :
181 : 865 : return SHISHI_OK;
182 : : }
183 : :
184 : : /**
185 : : * shishi_hmac_sha1:
186 : : * @handle: shishi handle as allocated by shishi_init().
187 : : * @key: input character array with key to use.
188 : : * @keylen: length of input character array with key to use.
189 : : * @in: input character array of data to hash.
190 : : * @inlen: length of input character array of data to hash.
191 : : * @outhash: newly allocated character array with keyed hash of data.
192 : : *
193 : : * Compute keyed checksum of data using HMAC-SHA1. The @outhash
194 : : * buffer must be deallocated by the caller.
195 : : *
196 : : * Return value: Returns SHISHI_OK iff successful.
197 : : **/
198 : : int
199 : 301 : shishi_hmac_sha1 (Shishi * handle,
200 : : const char *key, size_t keylen,
201 : : const char *in, size_t inlen, char *outhash[20])
202 : : {
203 : : Gc_rc rc;
204 : :
205 : 301 : *outhash = xmalloc (GC_SHA1_DIGEST_SIZE);
206 : 301 : rc = gc_hmac_sha1 (key, keylen, in, inlen, *outhash);
207 [ - + ]: 301 : if (rc != GC_OK)
208 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
209 : :
210 : 301 : return SHISHI_OK;
211 : : }
212 : :
213 : : /**
214 : : * shishi_des_cbc_mac:
215 : : * @handle: shishi handle as allocated by shishi_init().
216 : : * @key: input character array with key to use.
217 : : * @iv: input character array with initialization vector to use, can be NULL.
218 : : * @in: input character array of data to hash.
219 : : * @inlen: length of input character array of data to hash.
220 : : * @out: newly allocated character array with keyed hash of data.
221 : : *
222 : : * Computed keyed checksum of data using DES-CBC-MAC. The @out buffer
223 : : * must be deallocated by the caller.
224 : : *
225 : : * Return value: Returns SHISHI_OK iff successful.
226 : : **/
227 : : int
228 : 8 : shishi_des_cbc_mac (Shishi * handle,
229 : : const char key[8],
230 : : const char iv[8],
231 : : const char *in, size_t inlen, char *out[8])
232 : : {
233 : : gcry_cipher_hd_t ch;
234 : : gpg_error_t err;
235 : 8 : int res = SHISHI_CRYPTO_INTERNAL_ERROR;
236 : :
237 : 8 : err = gcry_cipher_open (&ch, GCRY_CIPHER_DES,
238 : : GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_MAC);
239 [ - + ]: 8 : if (err != GPG_ERR_NO_ERROR)
240 : : {
241 : 0 : shishi_error_printf (handle, "DES-CBC-MAC not available in libgcrypt");
242 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
243 : : }
244 : :
245 : 8 : err = gcry_cipher_setkey (ch, key, 8);
246 [ - + ]: 8 : if (err != GPG_ERR_NO_ERROR)
247 : : {
248 : 0 : shishi_error_printf (handle, "DES setkey failed");
249 : 0 : shishi_error_set (handle, gpg_strerror (err));
250 : 0 : goto done;
251 : : }
252 : :
253 : 8 : err = gcry_cipher_setiv (ch, iv, 8);
254 [ - + ]: 8 : if (err != GPG_ERR_NO_ERROR)
255 : : {
256 : 0 : shishi_error_printf (handle, "DES setiv failed");
257 : 0 : shishi_error_set (handle, gpg_strerror (err));
258 : 0 : goto done;
259 : : }
260 : :
261 : 8 : *out = xmalloc (8);
262 : :
263 : 8 : err = gcry_cipher_encrypt (ch, *out, 8, in, inlen);
264 [ - + ]: 8 : if (err != GPG_ERR_NO_ERROR)
265 : : {
266 : 0 : shishi_error_printf (handle, "DES encrypt failed");
267 : 0 : shishi_error_set (handle, gpg_strerror (err));
268 : 0 : goto done;
269 : : }
270 : :
271 : 8 : res = SHISHI_OK;
272 : :
273 : : done:
274 : 8 : gcry_cipher_close (ch);
275 : 8 : return res;
276 : : }
277 : :
278 : : static int
279 : 1486 : libgcrypt_dencrypt (Shishi * handle, int algo, int flags, int mode,
280 : : int decryptp,
281 : : const char *key, size_t keylen,
282 : : const char *iv,
283 : : char **ivout, const char *in, size_t inlen, char **out)
284 : : {
285 : 1486 : size_t ivlen = gcry_cipher_get_algo_blklen (algo);
286 : : gcry_cipher_hd_t ch;
287 : : gpg_error_t err;
288 : :
289 : 1486 : err = gcry_cipher_open (&ch, algo, mode, flags);
290 [ - + ]: 1486 : if (err != GPG_ERR_NO_ERROR)
291 : : {
292 : 0 : shishi_error_printf (handle, "Libgcrypt cipher open failed");
293 : 0 : shishi_error_set (handle, gpg_strerror (err));
294 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
295 : : }
296 : :
297 : 1486 : err = gcry_cipher_setkey (ch, key, keylen);
298 [ - + ]: 1486 : if (err != GPG_ERR_NO_ERROR)
299 : : {
300 : 0 : shishi_error_printf (handle, "Libgcrypt setkey failed");
301 : 0 : shishi_error_set (handle, gpg_strerror (err));
302 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
303 : : }
304 : :
305 : 1486 : err = gcry_cipher_setiv (ch, iv, ivlen);
306 [ - + ]: 1486 : if (err != GPG_ERR_NO_ERROR)
307 : : {
308 : 0 : shishi_error_printf (handle, "Libgcrypt setiv failed");
309 : 0 : shishi_error_set (handle, gpg_strerror (err));
310 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
311 : : }
312 : :
313 : 1486 : *out = xmalloc (inlen);
314 : :
315 [ + + ]: 1486 : if (decryptp)
316 : 192 : err = gcry_cipher_decrypt (ch, (unsigned char *) *out, inlen,
317 : : (const unsigned char *) in, inlen);
318 : : else
319 : 1294 : err = gcry_cipher_encrypt (ch, (unsigned char *) *out, inlen,
320 : : (const unsigned char *) in, inlen);
321 [ - + ]: 1486 : if (err != GPG_ERR_NO_ERROR)
322 : : {
323 : 0 : shishi_error_printf (handle, "Libgcrypt ciphering failed");
324 : 0 : shishi_error_set (handle, gpg_strerror (err));
325 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
326 : : }
327 : :
328 [ + + ]: 1486 : if (ivout)
329 : : {
330 : 396 : size_t ivdiff, ivpos = 0;
331 : :
332 : 396 : *ivout = xmalloc (ivlen);
333 : :
334 [ + + ]: 396 : if (flags & GCRY_CIPHER_CBC_CTS)
335 : : {
336 : : /* XXX what is the output iv for CBC-CTS mode?
337 : : but is this value useful at all for that mode anyway?
338 : : Mostly it is DES apps that want the updated iv, so this is ok. */
339 : :
340 [ + + ]: 294 : if (inlen % ivlen)
341 : 274 : ivdiff = ivlen + inlen % ivlen;
342 : : else
343 : 20 : ivdiff = ivlen + ivlen;
344 : :
345 [ + + ]: 294 : if (inlen >= ivdiff)
346 : 294 : ivpos = inlen - ivdiff;
347 : : }
348 : : else
349 : 102 : ivpos = inlen - ivlen;
350 : :
351 [ + + ]: 396 : if (decryptp)
352 : 192 : memcpy (*ivout, in + ivpos, inlen >= ivlen ? ivlen : inlen);
353 : : else
354 : 204 : memcpy (*ivout, *out + ivpos, inlen >= ivlen ? ivlen : inlen);
355 : : }
356 : :
357 : 1486 : gcry_cipher_close (ch);
358 : :
359 : 1486 : return SHISHI_OK;
360 : : }
361 : :
362 : : /**
363 : : * shishi_arcfour:
364 : : * @handle: shishi handle as allocated by shishi_init().
365 : : * @decryptp: 0 to indicate encryption, non-0 to indicate decryption.
366 : : * @key: input character array with key to use.
367 : : * @keylen: length of input key array.
368 : : * @iv: input character array with initialization vector to use, or NULL.
369 : : * @ivout: output character array with updated initialization vector, or NULL.
370 : : * @in: input character array of data to encrypt/decrypt.
371 : : * @inlen: length of input character array of data to encrypt/decrypt.
372 : : * @out: newly allocated character array with encrypted/decrypted data.
373 : : *
374 : : * Encrypt or decrypt data (depending on @decryptp) using ARCFOUR.
375 : : * The @out buffer must be deallocated by the caller.
376 : : *
377 : : * The "initialization vector" used here is the concatenation of the
378 : : * sbox and i and j, and is thus always of size 256 + 1 + 1. This is
379 : : * a slight abuse of terminology, and assumes you know what you are
380 : : * doing. Don't use it if you can avoid to.
381 : : *
382 : : * Return value: Returns SHISHI_OK iff successful.
383 : : **/
384 : : int
385 : 290 : shishi_arcfour (Shishi * handle, int decryptp,
386 : : const char *key, size_t keylen,
387 : : const char iv[258], char *ivout[258],
388 : : const char *in, size_t inlen, char **out)
389 : : {
390 : : arcfour_context ctx;
391 : :
392 : 290 : *out = xmalloc (inlen);
393 : :
394 [ + + ]: 290 : if (iv)
395 : 284 : memcpy (&ctx, iv, sizeof (ctx));
396 : : else
397 : 6 : arcfour_setkey (&ctx, key, keylen);
398 : :
399 : 290 : arcfour_stream (&ctx, in, *out, inlen);
400 : :
401 [ + + ]: 290 : if (ivout)
402 : : {
403 : 289 : *ivout = xmalloc (sizeof (ctx));
404 : 289 : memcpy (*ivout, &ctx, sizeof (ctx));
405 : : }
406 : :
407 : 290 : return SHISHI_OK;
408 : : }
409 : :
410 : : /**
411 : : * shishi_des:
412 : : * @handle: shishi handle as allocated by shishi_init().
413 : : * @decryptp: 0 to indicate encryption, non-0 to indicate decryption.
414 : : * @key: input character array with key to use.
415 : : * @iv: input character array with initialization vector to use, or NULL.
416 : : * @ivout: output character array with updated initialization vector, or NULL.
417 : : * @in: input character array of data to encrypt/decrypt.
418 : : * @inlen: length of input character array of data to encrypt/decrypt.
419 : : * @out: newly allocated character array with encrypted/decrypted data.
420 : : *
421 : : * Encrypt or decrypt data (depending on @decryptp) using DES in CBC
422 : : * mode. The @out buffer must be deallocated by the caller.
423 : : *
424 : : * Return value: Returns SHISHI_OK iff successful.
425 : : **/
426 : : int
427 : 71 : shishi_des (Shishi * handle, int decryptp,
428 : : const char key[8],
429 : : const char iv[8],
430 : : char *ivout[8], const char *in, size_t inlen, char **out)
431 : : {
432 : 71 : return libgcrypt_dencrypt (handle, GCRY_CIPHER_DES, 0, GCRY_CIPHER_MODE_CBC,
433 : : decryptp, key, 8, iv, ivout, in, inlen, out);
434 : : }
435 : :
436 : : /**
437 : : * shishi_3des:
438 : : * @handle: shishi handle as allocated by shishi_init().
439 : : * @decryptp: 0 to indicate encryption, non-0 to indicate decryption.
440 : : * @key: input character array with key to use.
441 : : * @iv: input character array with initialization vector to use, or NULL.
442 : : * @ivout: output character array with updated initialization vector, or NULL.
443 : : * @in: input character array of data to encrypt/decrypt.
444 : : * @inlen: length of input character array of data to encrypt/decrypt.
445 : : * @out: newly allocated character array with encrypted/decrypted data.
446 : : *
447 : : * Encrypt or decrypt data (depending on @decryptp) using 3DES in CBC
448 : : * mode. The @out buffer must be deallocated by the caller.
449 : : *
450 : : * Return value: Returns SHISHI_OK iff successful.
451 : : **/
452 : : int
453 : 248 : shishi_3des (Shishi * handle, int decryptp,
454 : : const char key[8],
455 : : const char iv[8],
456 : : char *ivout[8], const char *in, size_t inlen, char **out)
457 : : {
458 : 248 : return libgcrypt_dencrypt (handle, GCRY_CIPHER_3DES, 0,
459 : : GCRY_CIPHER_MODE_CBC, decryptp, key, 24, iv,
460 : : ivout, in, inlen, out);
461 : : }
462 : :
463 : : /**
464 : : * shishi_aes_cts:
465 : : * @handle: shishi handle as allocated by shishi_init().
466 : : * @decryptp: 0 to indicate encryption, non-0 to indicate decryption.
467 : : * @key: input character array with key to use.
468 : : * @keylen: length of input character array with key to use.
469 : : * @iv: input character array with initialization vector to use, or NULL.
470 : : * @ivout: output character array with updated initialization vector, or NULL.
471 : : * @in: input character array of data to encrypt/decrypt.
472 : : * @inlen: length of input character array of data to encrypt/decrypt.
473 : : * @out: newly allocated character array with encrypted/decrypted data.
474 : : *
475 : : * Encrypt or decrypt data (depending on @decryptp) using AES in
476 : : * CBC-CTS mode. The length of the key, @keylen, decide if AES 128 or
477 : : * AES 256 should be used. The @out buffer must be deallocated by the
478 : : * caller.
479 : : *
480 : : * Return value: Returns SHISHI_OK iff successful.
481 : : **/
482 : : int
483 : 1167 : shishi_aes_cts (Shishi * handle, int decryptp,
484 : : const char *key, size_t keylen,
485 : : const char iv[16],
486 : : char *ivout[16], const char *in, size_t inlen, char **out)
487 : : {
488 : 1167 : return libgcrypt_dencrypt (handle, GCRY_CIPHER_AES, GCRY_CIPHER_CBC_CTS,
489 : : GCRY_CIPHER_MODE_CBC, decryptp,
490 : : key, keylen, iv, ivout, in, inlen, out);
491 : : }
492 : :
493 : : /**
494 : : * shishi_pbkdf2_sha1:
495 : : * @handle: shishi handle as allocated by shishi_init().
496 : : * @P: input password, an octet string
497 : : * @Plen: length of password, an octet string
498 : : * @S: input salt, an octet string
499 : : * @Slen: length of salt, an octet string
500 : : * @c: iteration count, a positive integer
501 : : * @dkLen: intended length in octets of the derived key, a positive integer,
502 : : * at most (2^32 - 1) * hLen. The DK array must have room for this many
503 : : * characters.
504 : : * @DK: output derived key, a dkLen-octet string
505 : : *
506 : : * Derive key using the PBKDF2 defined in PKCS5. PBKDF2 applies a
507 : : * pseudorandom function to derive keys. The length of the derived key
508 : : * is essentially unbounded. (However, the maximum effective search
509 : : * space for the derived key may be limited by the structure of the
510 : : * underlying pseudorandom function, which is this function is always
511 : : * SHA1.)
512 : : *
513 : : * Return value: Returns SHISHI_OK iff successful.
514 : : **/
515 : : int
516 : 28 : shishi_pbkdf2_sha1 (Shishi * handle,
517 : : const char *P, size_t Plen,
518 : : const char *S, size_t Slen,
519 : : unsigned int c, unsigned int dkLen, char *DK)
520 : : {
521 : : Gc_rc rc;
522 : :
523 : 28 : rc = gc_pbkdf2_sha1 (P, Plen, S, Slen, c, DK, dkLen);
524 : :
525 [ - + ]: 28 : if (rc == GC_PKCS5_INVALID_ITERATION_COUNT)
526 : 0 : return SHISHI_PKCS5_INVALID_ITERATION_COUNT;
527 : :
528 [ - + ]: 28 : if (rc == GC_PKCS5_INVALID_DERIVED_KEY_LENGTH)
529 : 0 : return SHISHI_PKCS5_INVALID_DERIVED_KEY_LENGTH;
530 : :
531 [ - + ]: 28 : if (rc == GC_PKCS5_DERIVED_KEY_TOO_LONG)
532 : 0 : return SHISHI_PKCS5_DERIVED_KEY_TOO_LONG;
533 : :
534 [ - + ]: 28 : if (rc != GC_OK)
535 : 0 : return SHISHI_CRYPTO_INTERNAL_ERROR;
536 : :
537 : 28 : return SHISHI_OK;
538 : : }
|