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