Fix compiler warnings from -Wold-style-declaration. Fixes bug #5706
[platform/upstream/gcr.git] / egg / egg-openssl.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* egg-openssl.c - OpenSSL compatibility functionality
3
4    Copyright (C) 2007 Stefan Walter
5
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    Author: Stef Walter <stef@memberwebs.com>
22 */
23
24 #include "config.h"
25
26 #include "egg-hex.h"
27 #include "egg-openssl.h"
28 #include "egg-secure-memory.h"
29 #include "egg-symkey.h"
30
31 #include <gcrypt.h>
32 #include <libtasn1.h>
33
34 #include <glib.h>
35
36 #include <ctype.h>
37 #include <string.h>
38
39 /*
40  * PEM looks like:
41  *
42  *      -----BEGIN RSA PRIVATE KEY-----
43  *      Proc-Type: 4,ENCRYPTED
44  *      DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9
45  *
46  *      4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL
47  *      Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F
48  *      u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX
49  *      ....
50  *      -----END RSA PRIVATE KEY-----
51  */
52
53 #define PEM_SUFF          "-----"
54 #define PEM_SUFF_L        5
55 #define PEM_PREF_BEGIN    "-----BEGIN "
56 #define PEM_PREF_BEGIN_L  11
57 #define PEM_PREF_END      "-----END "
58 #define PEM_PREF_END_L    9
59
60 static void
61 parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result)
62 {
63         gchar **lines, **l;
64         gchar *line, *name, *value;
65         gchar *copy;
66
67         copy = g_strndup (hbeg, hend - hbeg);
68         lines = g_strsplit (copy, "\n", 0);
69         g_free (copy);
70
71         for (l = lines; l && *l; ++l) {
72                 line = *l;
73                 g_strstrip (line);
74
75                 /* Look for the break between name: value */
76                 value = strchr (line, ':');
77                 if (value == NULL)
78                         continue;
79
80                 *value = 0;
81                 value = g_strdup (value + 1);
82                 g_strstrip (value);
83
84                 name = g_strdup (line);
85                 g_strstrip (name);
86
87                 if (!*result)
88                         *result = egg_openssl_headers_new ();
89                 g_hash_table_replace (*result, name, value);
90         }
91
92         g_strfreev (lines);
93 }
94
95 static const gchar*
96 pem_find_begin (const gchar *data, gsize n_data, GQuark *type)
97 {
98         const gchar *pref, *suff;
99         gchar *stype;
100
101         /* Look for a prefix */
102         pref = g_strstr_len ((gchar*)data, n_data, PEM_PREF_BEGIN);
103         if (!pref)
104                 return NULL;
105
106         n_data -= (pref - data) + PEM_PREF_BEGIN_L;
107         data = pref + PEM_PREF_BEGIN_L;
108
109         /* Look for the end of that begin */
110         suff = g_strstr_len ((gchar*)data, n_data, PEM_SUFF);
111         if (!suff)
112                 return NULL;
113
114         /* Make sure on the same line */
115         if (memchr (pref, '\n', suff - pref))
116                 return NULL;
117
118         if (type) {
119                 *type = 0;
120                 pref += PEM_PREF_BEGIN_L;
121                 g_assert (suff > pref);
122                 stype = g_alloca (suff - pref + 1);
123                 memcpy (stype, pref, suff - pref);
124                 stype[suff - pref] = 0;
125                 *type = g_quark_from_string (stype);
126         }
127
128         /* The byte after this ---BEGIN--- */
129         return suff + PEM_SUFF_L;
130 }
131
132 static const gchar*
133 pem_find_end (const gchar *data, gsize n_data, GQuark type)
134 {
135         const gchar *stype;
136         const gchar *pref;
137         gsize n_type;
138
139         /* Look for a prefix */
140         pref = g_strstr_len (data, n_data, PEM_PREF_END);
141         if (!pref)
142                 return NULL;
143
144         n_data -= (pref - data) + PEM_PREF_END_L;
145         data = pref + PEM_PREF_END_L;
146
147         /* Next comes the type string */
148         stype = g_quark_to_string (type);
149         n_type = strlen (stype);
150         if (strncmp ((gchar*)data, stype, n_type) != 0)
151                 return NULL;
152
153         n_data -= n_type;
154         data += n_type;
155
156         /* Next comes the suffix */
157         if (strncmp ((gchar*)data, PEM_SUFF, PEM_SUFF_L) != 0)
158                 return NULL;
159
160         /* The beginning of this ---END--- */
161         return pref;
162 }
163
164 static gboolean
165 pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded,
166                  GHashTable **headers)
167 {
168         const gchar *x, *hbeg, *hend;
169         const gchar *p, *end;
170         gint state = 0;
171         guint save = 0;
172
173         g_assert (data);
174         g_assert (n_data);
175
176         g_assert (decoded);
177         g_assert (n_decoded);
178
179         p = data;
180         end = p + n_data;
181
182         hbeg = hend = NULL;
183
184         /* Try and find a pair of blank lines with only white space between */
185         while (hend == NULL) {
186                 x = memchr (p, '\n', end - p);
187                 if (!x)
188                         break;
189                 ++x;
190                 while (isspace (*x)) {
191                         /* Found a second line, with only spaces between */
192                         if (*x == '\n') {
193                                 hbeg = data;
194                                 hend = x;
195                                 break;
196                         /* Found a space between two lines */
197                         } else {
198                                 ++x;
199                         }
200                 }
201
202                 /* Try next line */
203                 p = x;
204         }
205
206         /* Headers found? */
207         if (hbeg && hend) {
208                 data = hend;
209                 n_data = end - data;
210         }
211
212         *n_decoded = (n_data * 3) / 4 + 1;
213         if (egg_secure_check (data))
214                 *decoded = egg_secure_alloc (*n_decoded);
215         else
216                 *decoded = g_malloc0 (*n_decoded);
217         g_return_val_if_fail (*decoded, FALSE);
218
219         *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save);
220         if (!*n_decoded) {
221                 egg_secure_free (*decoded);
222                 return FALSE;
223         }
224
225         if (headers && hbeg && hend)
226                 parse_header_lines (hbeg, hend, headers);
227
228         return TRUE;
229 }
230
231 GHashTable*
232 egg_openssl_headers_new (void)
233 {
234         return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
235 }
236
237 guint
238 egg_openssl_pem_parse (const guchar *data, gsize n_data,
239                        EggOpensslPemCallback callback, gpointer user_data)
240 {
241         const gchar *beg, *end;
242         guint nfound = 0;
243         guchar *decoded = NULL;
244         gsize n_decoded = 0;
245         GHashTable *headers = NULL;
246         GQuark type;
247
248         g_return_val_if_fail (data, 0);
249         g_return_val_if_fail (n_data, 0);
250         g_return_val_if_fail (callback, 0);
251
252         while (n_data > 0) {
253
254                 /* This returns the first character after the PEM BEGIN header */
255                 beg = pem_find_begin ((const gchar*)data, n_data, &type);
256                 if (!beg)
257                         break;
258
259                 g_assert (type);
260
261                 /* This returns the character position before the PEM END header */
262                 end = pem_find_end ((const gchar*)beg, n_data - ((const guchar*)beg - data), type);
263                 if (!end)
264                         break;
265
266                 if (beg != end) {
267                         if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) {
268                                 (callback) (type, decoded, n_decoded, headers, user_data);
269                                 ++nfound;
270                                 egg_secure_free (decoded);
271                                 if (headers)
272                                         g_hash_table_remove_all (headers);
273                         }
274                 }
275
276                 /* Try for another block */
277                 end += PEM_SUFF_L;
278                 n_data -= (const guchar*)end - data;
279                 data = (const guchar*)end;
280         }
281
282         if (headers)
283                 g_hash_table_destroy (headers);
284
285         return nfound;
286 }
287
288 #ifdef UNTESTED_CODE
289
290 static void
291 append_each_header (gpointer key, gpointer value, gpointer user_data)
292 {
293         GString *string = (GString*)user_data;
294
295         g_string_append (string, (gchar*)key);
296         g_string_append (string, ": ");
297         g_string_append (string, (gchar*)value);
298         g_string_append_c (string, '\n');
299 }
300
301 guchar*
302 egg_openssl_pem_write (const guchar *data, gsize n_data, GQuark type,
303                     GHashTable *headers, gsize *n_result)
304 {
305         GString *string;
306         gint state, save;
307         gsize length, n_prefix;
308
309         g_return_val_if_fail (data || !n_data, NULL);
310         g_return_val_if_fail (type, NULL);
311         g_return_val_if_fail (n_result, NULL);
312
313         string = g_string_sized_new (4096);
314
315         /* The prefix */
316         g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L);
317         g_string_append (string, g_quark_to_string (type));
318         g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
319         g_string_append_c (string, '\n');
320
321         /* The headers */
322         if (headers && g_hash_table_size (headers) > 0) {
323                 g_hash_table_foreach (headers, append_each_header, string);
324                 g_string_append_c (string, '\n');
325         }
326
327         /* Resize string to fit the base64 data. Algorithm from Glib reference */
328         length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7;
329         n_prefix = string->len;
330         g_string_set_size (string, n_prefix + length);
331
332         /* The actual base64 data */
333         state = save = 0;
334         length = g_base64_encode_step (data, n_data, TRUE,
335                                        string->str + string->len, &state, &save);
336         g_string_set_size (string, n_prefix + length);
337
338         /* The suffix */
339         g_string_append_c (string, '\n');
340         g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L);
341         g_string_append (string, g_quark_to_string (type));
342         g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
343         g_string_append_c (string, '\n');
344
345         *n_result = string->len;
346         return (guchar*)g_string_free (string, FALSE);
347 }
348
349 #endif /* UNTESTED_CODE */
350
351 /* ----------------------------------------------------------------------------
352  * DEFINITIONS
353  */
354
355 static const struct {
356         const gchar *desc;
357         int algo;
358         int mode;
359 } openssl_algos[] = {
360         { "DES-ECB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB },
361         { "DES-CFB64", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
362         { "DES-CFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
363         /* DES-CFB1 */
364         /* DES-CFB8 */
365         /* DESX-CBC */
366         /* DES-EDE */
367         /* DES-EDE-CBC */
368         /* DES-EDE-ECB */
369         /* DES-EDE-CFB64 DES-EDE-CFB */
370         /* DES-EDE-CFB1 */
371         /* DES-EDE-CFB8 */
372         /* DES-EDE-OFB */
373         /* DES-EDE3 */
374         { "DES-EDE3-ECB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB },
375         { "DES-EDE3-CFB64", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
376         { "DES-EDE3-CFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
377         /* DES-EDE3-CFB1 */
378         /* DES-EDE3-CFB8 */
379         { "DES-OFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB },
380         { "DES-EDE3-OFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB },
381         { "DES-CBC", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC },
382         { "DES-EDE3-CBC", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
383         /* RC2-ECB */
384         /* RC2-CBC */
385         /* RC2-40-CBC */
386         /* RC2-64-CBC */
387         /* RC2-CFB64    RC2-CFB */
388         /* RC2-OFB */
389         { "RC4", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
390         { "RC4-40", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
391         { "IDEA-ECB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_ECB },
392         { "IDEA-CFB64", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CFB },
393         { "IDEA-OFB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_OFB },
394         { "IDEA-CBC", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CBC },
395         { "BF-ECB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB },
396         { "BF-CBC", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
397         { "BF-CFB64", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
398         { "BF-CFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
399         { "BF-OFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB },
400         { "CAST5-ECB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB },
401         { "CAST5-CBC", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
402         { "CAST5-CFB64", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
403         { "CAST5-CFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
404         { "CAST5-OFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB },
405         /* RC5-32-12-16-CBC */
406         /* RC5-32-12-16-ECB */
407         /* RC5-32-12-16-CFB64  RC5-32-12-16-CFB */
408         /* RC5-32-12-16-OFB */
409         { "AES-128-ECB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB },
410         { "AES-128-CBC", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC },
411         /* AES-128-CFB1 */
412         /* AES-128-CFB8 */
413         { "AES-128-CFB128", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
414         { "AES-128-CFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
415         { "AES-128-OFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB },
416         { "AES-128-CTR", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR },
417         { "AES-192-ECB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB },
418         { "AES-192-CBC", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC },
419         /* AES-192-CFB1 */
420         /* AES-192-CFB8 */
421         { "AES-192-CFB128", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
422         { "AES-192-CFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
423         { "AES-192-OFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB },
424         { "AES-192-CTR", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR },
425         { "AES-256-ECB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB },
426         { "AES-256-CBC", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC },
427         /* AES-256-CFB1 */
428         /* AES-256-CFB8 */
429         { "AES-256-CFB128", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
430         { "AES-256-CFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
431         { "AES-256-OFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB },
432         { "AES-256-CTR", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR },
433         /* CAMELLIA-128-ECB */
434         /* CAMELLIA-128-CBC */
435         /* CAMELLIA-128-CFB1 */
436         /* CAMELLIA-128-CFB8 */
437         /* CAMELLIA-128-CFB128   CAMELLIA-128-CFB */
438         /* CAMELLIA-128-OFB */
439         /* CAMELLIA-192-ECB */
440         /* CAMELLIA-192-CBC */
441         /* CAMELLIA-192-CFB1 */
442         /* CAMELLIA-192-CFB8 */
443         /* CAMELLIA-192-CFB128   CAMELLIA-192-CFB */
444         /* CAMELLIA-192_OFB */
445         /* CAMELLIA-256-ECB */
446         /* CAMELLIA-256-CBC */
447         /* CAMELLIA-256-CFB1 */
448         /* CAMELLIA-256-CFB8 */
449         /* CAMELLIA-256-CFB128   CAMELLIA-256-CFB */
450         /* CAMELLIA-256-OFB */
451 };
452
453 /* ------------------------------------------------------------------------- */
454
455 int
456 egg_openssl_parse_algo (const char *name, int *mode)
457 {
458         static GQuark openssl_quarks[G_N_ELEMENTS(openssl_algos)] = { 0, };
459         static gsize openssl_quarks_inited = 0;
460         GQuark q;
461         int i;
462
463         if (g_once_init_enter (&openssl_quarks_inited)) {
464                 for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i)
465                         openssl_quarks[i] = g_quark_from_static_string (openssl_algos[i].desc);
466                 g_once_init_leave (&openssl_quarks_inited, 1);
467         }
468
469         q = g_quark_try_string (name);
470         if (q) {
471                 for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i) {
472                         if (q == openssl_quarks[i]) {
473                                 *mode = openssl_algos[i].mode;
474                                 return openssl_algos[i].algo;
475                         }
476                 }
477         }
478
479         return 0;
480 }
481
482 static gboolean
483 parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
484 {
485         gboolean success = FALSE;
486         gchar **parts = NULL;
487         gcry_error_t gcry;
488         gsize ivlen, len;
489
490         parts = g_strsplit (dek, ",", 2);
491         if (!parts || !parts[0] || !parts[1])
492                 goto done;
493
494         /* Parse the algorithm name */
495         *algo = egg_openssl_parse_algo (parts[0], mode);
496         if (!*algo)
497                 goto done;
498
499         /* Make sure this is usable */
500         gcry = gcry_cipher_test_algo (*algo);
501         if (gcry)
502                 goto done;
503
504         /* Parse the IV */
505         ivlen = gcry_cipher_get_algo_blklen (*algo);
506
507         *iv = egg_hex_decode (parts[1], strlen(parts[1]), &len);
508         if (!*iv || ivlen != len) {
509                 g_free (*iv);
510                 goto done;
511         }
512
513         success = TRUE;
514
515 done:
516         g_strfreev (parts);
517         return success;
518 }
519
520 gboolean
521 egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password,
522                            gssize n_password, const guchar *data, gsize n_data,
523                            guchar **decrypted, gsize *n_decrypted)
524 {
525         gcry_cipher_hd_t ch;
526         guchar *key = NULL;
527         guchar *iv = NULL;
528         int gcry, ivlen;
529         int algo = 0;
530         int mode = 0;
531
532         if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
533                 return FALSE;
534
535         ivlen = gcry_cipher_get_algo_blklen (algo);
536
537         /* We assume the iv is at least as long as at 8 byte salt */
538         g_return_val_if_fail (ivlen >= 8, FALSE);
539
540         /* IV is already set from the DEK info */
541         if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
542                                                 n_password, iv, 8, 1, &key, NULL)) {
543                 g_free (iv);
544                 return FALSE;
545         }
546
547         /* TODO: Use secure memory */
548         gcry = gcry_cipher_open (&ch, algo, mode, 0);
549         g_return_val_if_fail (!gcry, FALSE);
550
551         gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
552         g_return_val_if_fail (!gcry, FALSE);
553         egg_secure_free (key);
554
555         /* 16 = 128 bits */
556         gcry = gcry_cipher_setiv (ch, iv, ivlen);
557         g_return_val_if_fail (!gcry, FALSE);
558         g_free (iv);
559
560         /* Allocate output area */
561         *n_decrypted = n_data;
562         *decrypted = egg_secure_alloc (n_data);
563
564         gcry = gcry_cipher_decrypt (ch, *decrypted, *n_decrypted, (void*)data, n_data);
565         if (gcry) {
566                 egg_secure_free (*decrypted);
567                 g_return_val_if_reached (FALSE);
568         }
569
570         gcry_cipher_close (ch);
571
572         return TRUE;
573 }
574
575 gboolean
576 egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password,
577                                 gssize n_password, const guchar *data, gsize n_data,
578                                 guchar **encrypted, gsize *n_encrypted)
579 {
580         gsize n_overflow, n_batch, n_padding;
581         gcry_cipher_hd_t ch;
582         guchar *key = NULL;
583         guchar *iv = NULL;
584         guchar *padded = NULL;
585         int gcry, ivlen;
586         int algo = 0;
587         int mode = 0;
588
589         if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
590                 g_return_val_if_reached (FALSE);
591
592         ivlen = gcry_cipher_get_algo_blklen (algo);
593
594         /* We assume the iv is at least as long as at 8 byte salt */
595         g_return_val_if_fail (ivlen >= 8, FALSE);
596
597         /* IV is already set from the DEK info */
598         if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
599                                                 n_password, iv, 8, 1, &key, NULL))
600                 g_return_val_if_reached (FALSE);
601
602         gcry = gcry_cipher_open (&ch, algo, mode, 0);
603         g_return_val_if_fail (!gcry, FALSE);
604
605         gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
606         g_return_val_if_fail (!gcry, FALSE);
607         egg_secure_free (key);
608
609         /* 16 = 128 bits */
610         gcry = gcry_cipher_setiv (ch, iv, ivlen);
611         g_return_val_if_fail (!gcry, FALSE);
612         g_free (iv);
613
614         /* Allocate output area */
615         n_overflow = (n_data % ivlen);
616         n_padding = n_overflow ? (ivlen - n_overflow) : 0;
617         n_batch = n_data - n_overflow;
618         *n_encrypted = n_data + n_padding;
619         *encrypted = g_malloc0 (*n_encrypted);
620
621         g_assert (*n_encrypted % ivlen == 0);
622         g_assert (*n_encrypted >= n_data);
623         g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
624
625         /* Encrypt everything but the last bit */
626         gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch);
627         if (gcry) {
628                 g_free (*encrypted);
629                 g_return_val_if_reached (FALSE);
630         }
631
632         /* Encrypt the padded block */
633         if (n_overflow) {
634                 padded = egg_secure_alloc (ivlen);
635                 memset (padded, 0, ivlen);
636                 memcpy (padded, data + n_batch, n_overflow);
637                 gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen);
638                 egg_secure_free (padded);
639                 if (gcry) {
640                         g_free (*encrypted);
641                         g_return_val_if_reached (FALSE);
642                 }
643         }
644
645         gcry_cipher_close (ch);
646         return TRUE;
647 }
648
649 const gchar*
650 egg_openssl_get_dekinfo (GHashTable *headers)
651 {
652         const gchar *val;
653         if (!headers)
654                 return NULL;
655         val = g_hash_table_lookup (headers, "Proc-Type");
656         if (!val || strcmp (val, "4,ENCRYPTED") != 0)
657                 return NULL;
658         val = g_hash_table_lookup (headers, "DEK-Info");
659         g_return_val_if_fail (val, NULL);
660         return val;
661 }
662
663 const gchar*
664 egg_openssl_prep_dekinfo (GHashTable *headers)
665 {
666         gchar *dekinfo, *hex;
667         gsize ivlen;
668         guchar *iv;
669
670         /* Create the iv */
671         ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
672         g_return_val_if_fail (ivlen, NULL);
673         iv = g_malloc (ivlen);
674         gcry_create_nonce (iv, ivlen);
675
676         /* And encode it into the string */
677         hex = egg_hex_encode (iv, ivlen);
678         g_return_val_if_fail (hex, NULL);
679         dekinfo = g_strdup_printf ("DES-EDE3-CBC,%s", hex);
680         g_free (hex);
681
682         g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
683         g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
684
685         return dekinfo;
686 }