summaryrefslogtreecommitdiff
path: root/src/lib/emile/emile_main.c
blob: b8712fce452f93fe9753b037ed6b821f38ae0bf2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* ifdef HAVE_CONFIG_H */

#ifdef HAVE_GNUTLS
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
# include <gcrypt.h>
#endif /* ifdef HAVE_GNUTLS */

#ifdef HAVE_OPENSSL
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/evp.h>
#endif /* ifdef HAVE_OPENSSL */

#include <Eina.h>

#include "Emile.h"
#include "emile_private.h"

static Eina_Bool _emile_cipher_inited = EINA_FALSE;
static unsigned int _emile_init_count = 0;
int _emile_log_dom_global = -1;

EAPI Eina_Bool
emile_cipher_init(void)
{
   if (_emile_cipher_inited) return EINA_TRUE;

   if (!_emile_cipher_init()) return EINA_FALSE;

   _emile_cipher_inited = EINA_TRUE;

   return EINA_TRUE;
}

EAPI int
emile_init(void)
{
   if (++_emile_init_count != 1)
     return _emile_init_count;

   if (!eina_init())
     return --_emile_init_count;

   _emile_log_dom_global = eina_log_domain_register("emile", EINA_COLOR_CYAN);
   if (_emile_log_dom_global < 0)
     {
        EINA_LOG_ERR("Emile can not create a general log domain.");
        goto shutdown_eina;
     }

   eina_log_timing(_emile_log_dom_global,
                   EINA_LOG_STATE_STOP,
                   EINA_LOG_STATE_INIT);

   return _emile_init_count;

 shutdown_eina:
   eina_shutdown();

   return --_emile_init_count;
}

EAPI int
emile_shutdown(void)
{
   if (--_emile_init_count != 0)
     return _emile_init_count;

   eina_log_timing(_emile_log_dom_global,
                   EINA_LOG_STATE_START,
                   EINA_LOG_STATE_SHUTDOWN);

   if (_emile_cipher_inited)
     {
#ifdef HAVE_GNUTLS
        /* Note that gnutls has a leak where it doesnt free stuff it alloced
         * on init. valgrind trace here:
         * 21 bytes in 1 blocks are definitely lost in loss record 24 of 194
         *    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
         *    by 0x68AC801: strdup (strdup.c:43)
         *    by 0xD215B6A: p11_kit_registered_module_to_name (in /usr/lib/x86_64-linux-gnu/libp11-kit.so.0.0.0)
         *    by 0x9571574: gnutls_pkcs11_init (in /usr/lib/x86_64-linux-gnu/libgnutls.so.26.21.8)
         *    by 0x955B031: gnutls_global_init (in /usr/lib/x86_64-linux-gnu/libgnutls.so.26.21.8)
         *    by 0x6DFD6D0: eet_init (eet_lib.c:608)
         *
         * yes - i've tried calling gnutls_pkcs11_deinit() by hand but no luck.
         * the leak is in there.
         */
        gnutls_global_deinit();
#endif /* ifdef HAVE_GNUTLS */
#ifdef HAVE_OPENSSL
        EVP_cleanup();
        ERR_free_strings();
#endif /* ifdef HAVE_OPENSSL */
     }

   eina_log_domain_unregister(_emile_log_dom_global);
   _emile_log_dom_global = -1;

   eina_shutdown();

   return _emile_init_count;
}

/* For the moment, we have just one function shared accross both cipher
 * backend, so here it is. */
Eina_Bool
emile_pbkdf2_sha1(const char *key,
                  unsigned int key_len,
                  const unsigned char *salt,
                  unsigned int salt_len,
                  unsigned int iter,
                  unsigned char *res,
                  unsigned int res_len)
{
   Eina_Binbuf *step1, *step2;
   unsigned char *buf;
   unsigned char *p = res;
   unsigned char digest[20];
   unsigned char tab[4];
   unsigned int len = res_len;
   unsigned int tmp_len;
   unsigned int i, j, k;

   buf = alloca(salt_len + 4);
   if (!buf) return EINA_FALSE;

   step1 = eina_binbuf_manage_read_only_new_length(buf, salt_len + 4);
   if (!step1) return EINA_FALSE;
   step2 = eina_binbuf_manage_read_only_new_length(digest, 20);
   if (!step2) return EINA_FALSE;

   for (i = 1; len; len -= tmp_len, p += tmp_len, i++)
     {
        tmp_len = (len > 20) ? 20 : len;

        tab[0] = (unsigned char)(i & 0xff000000) >> 24;
        tab[1] = (unsigned char)(i & 0x00ff0000) >> 16;
        tab[2] = (unsigned char)(i & 0x0000ff00) >> 8;
        tab[3] = (unsigned char)(i & 0x000000ff) >> 0;

        memcpy(buf, salt, salt_len);
        memcpy(buf + salt_len, tab, 4);

        if (!emile_binbuf_sha1(key, key_len, step1, digest))
          return EINA_FALSE;

        memcpy(p, digest, tmp_len);

        for (j = 1; j < iter; j++)
          {
             if (!emile_binbuf_sha1(key, key_len, step2, digest))
               return EINA_FALSE;
             for (k = 0; k < tmp_len; k++)
               p[k] ^= digest[k];
          }
     }

   eina_binbuf_free(step1);
   eina_binbuf_free(step2);

   return EINA_TRUE;
}