1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* egg-openssl.c - OpenSSL compatibility functionality
4 Copyright (C) 2007 Stefan Walter
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.
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.
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.
21 Author: Stef Walter <stef@memberwebs.com>
27 #include "egg-openssl.h"
28 #include "egg-secure-memory.h"
29 #include "egg-symkey.h"
38 EGG_SECURE_DECLARE (openssl);
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 },
54 /* DES-EDE-CFB64 DES-EDE-CFB */
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 },
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 },
72 /* RC2-CFB64 RC2-CFB */
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 },
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 },
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 },
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 */
138 /* ------------------------------------------------------------------------- */
141 egg_openssl_parse_algo (const char *name, int *mode)
143 static GQuark openssl_quarks[G_N_ELEMENTS(openssl_algos)] = { 0, };
144 static gsize openssl_quarks_inited = 0;
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);
154 q = g_quark_try_string (name);
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;
168 parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
170 gboolean success = FALSE;
171 gchar **parts = NULL;
175 parts = g_strsplit (dek, ",", 2);
176 if (!parts || !parts[0] || !parts[1])
179 /* Parse the algorithm name */
180 *algo = egg_openssl_parse_algo (parts[0], mode);
184 /* Make sure this is usable */
185 gcry = gcry_cipher_test_algo (*algo);
190 ivlen = gcry_cipher_get_algo_blklen (*algo);
192 *iv = egg_hex_decode (parts[1], strlen(parts[1]), &len);
193 if (!*iv || ivlen != len) {
206 egg_openssl_decrypt_block (const gchar *dekinfo,
207 const gchar *password,
220 if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
223 ivlen = gcry_cipher_get_algo_blklen (algo);
225 /* We assume the iv is at least as long as at 8 byte salt */
226 g_return_val_if_fail (ivlen >= 8, FALSE);
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)) {
235 gcry = gcry_cipher_open (&ch, algo, mode, 0);
236 g_return_val_if_fail (!gcry, NULL);
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);
243 gcry = gcry_cipher_setiv (ch, iv, ivlen);
244 g_return_val_if_fail (!gcry, NULL);
247 /* Allocate output area */
248 *n_decrypted = g_bytes_get_size (data);
249 decrypted = egg_secure_alloc (*n_decrypted);
251 gcry = gcry_cipher_decrypt (ch, decrypted, *n_decrypted,
252 g_bytes_get_data (data, NULL),
253 g_bytes_get_size (data));
255 egg_secure_free (decrypted);
256 g_return_val_if_reached (NULL);
259 gcry_cipher_close (ch);
265 egg_openssl_encrypt_block (const gchar *dekinfo,
266 const gchar *password,
271 gsize n_overflow, n_batch, n_padding;
275 guchar *padded = NULL;
283 if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
284 g_return_val_if_reached (NULL);
286 ivlen = gcry_cipher_get_algo_blklen (algo);
288 /* We assume the iv is at least as long as at 8 byte salt */
289 g_return_val_if_fail (ivlen >= 8, NULL);
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);
296 gcry = gcry_cipher_open (&ch, algo, mode, 0);
297 g_return_val_if_fail (!gcry, NULL);
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);
304 gcry = gcry_cipher_setiv (ch, iv, ivlen);
305 g_return_val_if_fail (!gcry, NULL);
308 dat = g_bytes_get_data (data, &n_data);
310 /* Allocate output area */
311 n_overflow = (n_data % ivlen);
312 n_padding = n_overflow ? (ivlen - n_overflow) : 0;
313 n_batch = n_data - n_overflow;
314 *n_encrypted = n_data + n_padding;
315 encrypted = g_malloc0 (*n_encrypted);
317 g_assert (*n_encrypted % ivlen == 0);
318 g_assert (*n_encrypted >= n_data);
319 g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
321 /* Encrypt everything but the last bit */
322 gcry = gcry_cipher_encrypt (ch, encrypted, n_batch, dat, n_batch);
325 g_return_val_if_reached (NULL);
328 /* Encrypt the padded block */
330 padded = egg_secure_alloc (ivlen);
331 memset (padded, 0, ivlen);
332 memcpy (padded, dat + n_batch, n_overflow);
333 gcry = gcry_cipher_encrypt (ch, encrypted + n_batch, ivlen, padded, ivlen);
334 egg_secure_free (padded);
337 g_return_val_if_reached (NULL);
341 gcry_cipher_close (ch);
346 egg_openssl_get_dekinfo (GHashTable *headers)
351 val = g_hash_table_lookup (headers, "Proc-Type");
352 if (!val || strcmp (val, "4,ENCRYPTED") != 0)
354 val = g_hash_table_lookup (headers, "DEK-Info");
355 g_return_val_if_fail (val, NULL);
360 egg_openssl_prep_dekinfo (GHashTable *headers)
362 gchar *dekinfo, *hex;
367 ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
368 g_return_val_if_fail (ivlen, NULL);
369 iv = g_malloc (ivlen);
370 gcry_create_nonce (iv, ivlen);
372 /* And encode it into the string */
373 hex = egg_hex_encode (iv, ivlen);
374 g_return_val_if_fail (hex, NULL);
375 dekinfo = g_strdup_printf ("DES-EDE3-CBC,%s", hex);
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"));