LCOV - code coverage report
Current view: top level - egg - egg-openssl.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.9 % 128 110
Test Date: 2024-12-15 20:37:51 Functions: 100.0 % 7 7

            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              : }
        

Generated by: LCOV version 2.0-1