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