gcr: Use GBytes immutable ref counted byte buffers
[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 EGG_SECURE_DECLARE (openssl);
39
40 static const struct {
41         const gchar *desc;
42         int algo;
43         int mode;
44 } openssl_algos[] = {
45         { "DES-ECB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB },
46         { "DES-CFB64", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
47         { "DES-CFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
48         /* DES-CFB1 */
49         /* DES-CFB8 */
50         /* DESX-CBC */
51         /* DES-EDE */
52         /* DES-EDE-CBC */
53         /* DES-EDE-ECB */
54         /* DES-EDE-CFB64 DES-EDE-CFB */
55         /* DES-EDE-CFB1 */
56         /* DES-EDE-CFB8 */
57         /* DES-EDE-OFB */
58         /* DES-EDE3 */
59         { "DES-EDE3-ECB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB },
60         { "DES-EDE3-CFB64", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
61         { "DES-EDE3-CFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
62         /* DES-EDE3-CFB1 */
63         /* DES-EDE3-CFB8 */
64         { "DES-OFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB },
65         { "DES-EDE3-OFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB },
66         { "DES-CBC", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC },
67         { "DES-EDE3-CBC", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
68         /* RC2-ECB */
69         /* RC2-CBC */
70         /* RC2-40-CBC */
71         /* RC2-64-CBC */
72         /* RC2-CFB64    RC2-CFB */
73         /* RC2-OFB */
74         { "RC4", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
75         { "RC4-40", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
76         { "IDEA-ECB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_ECB },
77         { "IDEA-CFB64", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CFB },
78         { "IDEA-OFB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_OFB },
79         { "IDEA-CBC", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CBC },
80         { "BF-ECB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB },
81         { "BF-CBC", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
82         { "BF-CFB64", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
83         { "BF-CFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
84         { "BF-OFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB },
85         { "CAST5-ECB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB },
86         { "CAST5-CBC", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
87         { "CAST5-CFB64", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
88         { "CAST5-CFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
89         { "CAST5-OFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB },
90         /* RC5-32-12-16-CBC */
91         /* RC5-32-12-16-ECB */
92         /* RC5-32-12-16-CFB64  RC5-32-12-16-CFB */
93         /* RC5-32-12-16-OFB */
94         { "AES-128-ECB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB },
95         { "AES-128-CBC", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC },
96         /* AES-128-CFB1 */
97         /* AES-128-CFB8 */
98         { "AES-128-CFB128", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
99         { "AES-128-CFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
100         { "AES-128-OFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB },
101         { "AES-128-CTR", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR },
102         { "AES-192-ECB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB },
103         { "AES-192-CBC", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC },
104         /* AES-192-CFB1 */
105         /* AES-192-CFB8 */
106         { "AES-192-CFB128", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
107         { "AES-192-CFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
108         { "AES-192-OFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB },
109         { "AES-192-CTR", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR },
110         { "AES-256-ECB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB },
111         { "AES-256-CBC", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC },
112         /* AES-256-CFB1 */
113         /* AES-256-CFB8 */
114         { "AES-256-CFB128", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
115         { "AES-256-CFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
116         { "AES-256-OFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB },
117         { "AES-256-CTR", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR },
118         /* CAMELLIA-128-ECB */
119         /* CAMELLIA-128-CBC */
120         /* CAMELLIA-128-CFB1 */
121         /* CAMELLIA-128-CFB8 */
122         /* CAMELLIA-128-CFB128   CAMELLIA-128-CFB */
123         /* CAMELLIA-128-OFB */
124         /* CAMELLIA-192-ECB */
125         /* CAMELLIA-192-CBC */
126         /* CAMELLIA-192-CFB1 */
127         /* CAMELLIA-192-CFB8 */
128         /* CAMELLIA-192-CFB128   CAMELLIA-192-CFB */
129         /* CAMELLIA-192_OFB */
130         /* CAMELLIA-256-ECB */
131         /* CAMELLIA-256-CBC */
132         /* CAMELLIA-256-CFB1 */
133         /* CAMELLIA-256-CFB8 */
134         /* CAMELLIA-256-CFB128   CAMELLIA-256-CFB */
135         /* CAMELLIA-256-OFB */
136 };
137
138 /* ------------------------------------------------------------------------- */
139
140 int
141 egg_openssl_parse_algo (const char *name, int *mode)
142 {
143         static GQuark openssl_quarks[G_N_ELEMENTS(openssl_algos)] = { 0, };
144         static gsize openssl_quarks_inited = 0;
145         GQuark q;
146         int i;
147
148         if (g_once_init_enter (&openssl_quarks_inited)) {
149                 for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i)
150                         openssl_quarks[i] = g_quark_from_static_string (openssl_algos[i].desc);
151                 g_once_init_leave (&openssl_quarks_inited, 1);
152         }
153
154         q = g_quark_try_string (name);
155         if (q) {
156                 for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i) {
157                         if (q == openssl_quarks[i]) {
158                                 *mode = openssl_algos[i].mode;
159                                 return openssl_algos[i].algo;
160                         }
161                 }
162         }
163
164         return 0;
165 }
166
167 static gboolean
168 parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
169 {
170         gboolean success = FALSE;
171         gchar **parts = NULL;
172         gcry_error_t gcry;
173         gsize ivlen, len;
174
175         parts = g_strsplit (dek, ",", 2);
176         if (!parts || !parts[0] || !parts[1])
177                 goto done;
178
179         /* Parse the algorithm name */
180         *algo = egg_openssl_parse_algo (parts[0], mode);
181         if (!*algo)
182                 goto done;
183
184         /* Make sure this is usable */
185         gcry = gcry_cipher_test_algo (*algo);
186         if (gcry)
187                 goto done;
188
189         /* Parse the IV */
190         ivlen = gcry_cipher_get_algo_blklen (*algo);
191
192         *iv = egg_hex_decode (parts[1], strlen(parts[1]), &len);
193         if (!*iv || ivlen != len) {
194                 g_free (*iv);
195                 goto done;
196         }
197
198         success = TRUE;
199
200 done:
201         g_strfreev (parts);
202         return success;
203 }
204
205 guchar *
206 egg_openssl_decrypt_block (const gchar *dekinfo,
207                            const gchar *password,
208                            gssize n_password,
209                            EggBytes *data,
210                            gsize *n_decrypted)
211 {
212         gcry_cipher_hd_t ch;
213         guchar *key = NULL;
214         guchar *iv = NULL;
215         int gcry, ivlen;
216         int algo = 0;
217         int mode = 0;
218         guchar *decrypted;
219
220         if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
221                 return FALSE;
222
223         ivlen = gcry_cipher_get_algo_blklen (algo);
224
225         /* We assume the iv is at least as long as at 8 byte salt */
226         g_return_val_if_fail (ivlen >= 8, FALSE);
227
228         /* IV is already set from the DEK info */
229         if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
230                                          n_password, iv, 8, 1, &key, NULL)) {
231                 g_free (iv);
232                 return NULL;
233         }
234
235         gcry = gcry_cipher_open (&ch, algo, mode, 0);
236         g_return_val_if_fail (!gcry, NULL);
237
238         gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
239         g_return_val_if_fail (!gcry, NULL);
240         egg_secure_free (key);
241
242         /* 16 = 128 bits */
243         gcry = gcry_cipher_setiv (ch, iv, ivlen);
244         g_return_val_if_fail (!gcry, NULL);
245         g_free (iv);
246
247         /* Allocate output area */
248         *n_decrypted = egg_bytes_get_size (data);
249         decrypted = egg_secure_alloc (*n_decrypted);
250
251         gcry = gcry_cipher_decrypt (ch, decrypted, *n_decrypted,
252                                     egg_bytes_get_data (data),
253                                     egg_bytes_get_size (data));
254         if (gcry) {
255                 egg_secure_free (decrypted);
256                 g_return_val_if_reached (NULL);
257         }
258
259         gcry_cipher_close (ch);
260
261         return decrypted;
262 }
263
264 guchar *
265 egg_openssl_encrypt_block (const gchar *dekinfo,
266                            const gchar *password,
267                            gssize n_password,
268                            EggBytes *data,
269                            gsize *n_encrypted)
270 {
271         gsize n_overflow, n_batch, n_padding;
272         gcry_cipher_hd_t ch;
273         guchar *key = NULL;
274         guchar *iv = NULL;
275         guchar *padded = NULL;
276         int gcry, ivlen;
277         int algo = 0;
278         int mode = 0;
279         gsize n_data;
280         guchar *encrypted;
281         const guchar *dat;
282
283         if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
284                 g_return_val_if_reached (NULL);
285
286         ivlen = gcry_cipher_get_algo_blklen (algo);
287
288         /* We assume the iv is at least as long as at 8 byte salt */
289         g_return_val_if_fail (ivlen >= 8, NULL);
290
291         /* IV is already set from the DEK info */
292         if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password,
293                                                 n_password, iv, 8, 1, &key, NULL))
294                 g_return_val_if_reached (NULL);
295
296         gcry = gcry_cipher_open (&ch, algo, mode, 0);
297         g_return_val_if_fail (!gcry, NULL);
298
299         gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
300         g_return_val_if_fail (!gcry, NULL);
301         egg_secure_free (key);
302
303         /* 16 = 128 bits */
304         gcry = gcry_cipher_setiv (ch, iv, ivlen);
305         g_return_val_if_fail (!gcry, NULL);
306         g_free (iv);
307
308         dat = egg_bytes_get_data (data);
309         n_data = egg_bytes_get_size (data);
310
311         /* Allocate output area */
312         n_overflow = (n_data % ivlen);
313         n_padding = n_overflow ? (ivlen - n_overflow) : 0;
314         n_batch = n_data - n_overflow;
315         *n_encrypted = n_data + n_padding;
316         encrypted = g_malloc0 (*n_encrypted);
317
318         g_assert (*n_encrypted % ivlen == 0);
319         g_assert (*n_encrypted >= n_data);
320         g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
321
322         /* Encrypt everything but the last bit */
323         gcry = gcry_cipher_encrypt (ch, encrypted, n_batch, dat, n_batch);
324         if (gcry) {
325                 g_free (encrypted);
326                 g_return_val_if_reached (NULL);
327         }
328
329         /* Encrypt the padded block */
330         if (n_overflow) {
331                 padded = egg_secure_alloc (ivlen);
332                 memset (padded, 0, ivlen);
333                 memcpy (padded, dat + n_batch, n_overflow);
334                 gcry = gcry_cipher_encrypt (ch, encrypted + n_batch, ivlen, padded, ivlen);
335                 egg_secure_free (padded);
336                 if (gcry) {
337                         g_free (encrypted);
338                         g_return_val_if_reached (NULL);
339                 }
340         }
341
342         gcry_cipher_close (ch);
343         return encrypted;
344 }
345
346 const gchar*
347 egg_openssl_get_dekinfo (GHashTable *headers)
348 {
349         const gchar *val;
350         if (!headers)
351                 return NULL;
352         val = g_hash_table_lookup (headers, "Proc-Type");
353         if (!val || strcmp (val, "4,ENCRYPTED") != 0)
354                 return NULL;
355         val = g_hash_table_lookup (headers, "DEK-Info");
356         g_return_val_if_fail (val, NULL);
357         return val;
358 }
359
360 const gchar*
361 egg_openssl_prep_dekinfo (GHashTable *headers)
362 {
363         gchar *dekinfo, *hex;
364         gsize ivlen;
365         guchar *iv;
366
367         /* Create the iv */
368         ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
369         g_return_val_if_fail (ivlen, NULL);
370         iv = g_malloc (ivlen);
371         gcry_create_nonce (iv, ivlen);
372
373         /* And encode it into the string */
374         hex = egg_hex_encode (iv, ivlen);
375         g_return_val_if_fail (hex, NULL);
376         dekinfo = g_strdup_printf ("DES-EDE3-CBC,%s", hex);
377         g_free (hex);
378
379         g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
380         g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
381
382         return dekinfo;
383 }