summaryrefslogtreecommitdiff
path: root/src/lib/emile
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@samsung.com>2015-03-17 08:50:00 +0100
committerCedric BAIL <cedric@osg.samsung.com>2015-03-17 09:58:17 +0100
commit2e34d835d66f8062422008ccef8f5ac91ad1597c (patch)
treec4a8481a1de34c3e50d07cacd31069f893a67757 /src/lib/emile
parentcc88832353f01b754fcb199c28f7baa20679bdb9 (diff)
emile: expose cipher/uncipher block logic.
Diffstat (limited to 'src/lib/emile')
-rw-r--r--src/lib/emile/Emile.h8
-rw-r--r--src/lib/emile/emile_cipher.c454
-rw-r--r--src/lib/emile/emile_private.h27
3 files changed, 489 insertions, 0 deletions
diff --git a/src/lib/emile/Emile.h b/src/lib/emile/Emile.h
index b0ab0efa64..28f84aa53c 100644
--- a/src/lib/emile/Emile.h
+++ b/src/lib/emile/Emile.h
@@ -27,6 +27,8 @@
27#ifndef EMILE_H_ 27#ifndef EMILE_H_
28#define EMILE_H_ 28#define EMILE_H_
29 29
30#include <Eina.h>
31
30#ifdef EAPI 32#ifdef EAPI
31# undef EAPI 33# undef EAPI
32#endif /* ifdef EAPI */ 34#endif /* ifdef EAPI */
@@ -104,6 +106,12 @@ EAPI int emile_shutdown(void);
104 * @} 106 * @}
105 */ 107 */
106 108
109EAPI Eina_Binbuf *emile_binbuf_cipher(const Eina_Binbuf *in,
110 const char *key, unsigned int length);
111
112EAPI Eina_Binbuf *emile_binbuf_decipher(const Eina_Binbuf *in,
113 const char *key, unsigned int length);
114
107#ifdef __cplusplus 115#ifdef __cplusplus
108} 116}
109#endif /* ifdef __cplusplus */ 117#endif /* ifdef __cplusplus */
diff --git a/src/lib/emile/emile_cipher.c b/src/lib/emile/emile_cipher.c
new file mode 100644
index 0000000000..cdfabc24b0
--- /dev/null
+++ b/src/lib/emile/emile_cipher.c
@@ -0,0 +1,454 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif /* ifdef HAVE_CONFIG_H */
4
5#ifdef HAVE_NETINET_IN_H
6# include <netinet/in.h>
7#endif
8
9#ifdef HAVE_OPENSSL
10# include <openssl/sha.h>
11#endif /* ifdef HAVE_OPENSSL */
12
13#ifdef HAVE_CIPHER
14# ifdef HAVE_GNUTLS
15# include <gnutls/abstract.h>
16# include <gnutls/x509.h>
17# include <gcrypt.h>
18# else /* ifdef HAVE_GNUTLS */
19# include <openssl/evp.h>
20# include <openssl/hmac.h>
21# include <openssl/rand.h>
22# endif /* ifdef HAVE_GNUTLS */
23#endif /* ifdef HAVE_CIPHER */
24
25#include <Eina.h>
26
27#include "Emile.h"
28
29#include "emile_private.h"
30
31#ifdef HAVE_GNUTLS
32# define MAX_KEY_LEN 32
33# define MAX_IV_LEN 16
34#else /* ifdef HAVE_GNUTLS */
35# define MAX_KEY_LEN EVP_MAX_KEY_LENGTH
36# define MAX_IV_LEN EVP_MAX_IV_LENGTH
37#endif /* ifdef HAVE_GNUTLS */
38
39# ifdef HAVE_GNUTLS
40static inline Eina_Bool
41emile_hmac_sha1(const void *key,
42 size_t key_len,
43 const void *data,
44 size_t data_len,
45 unsigned char *res)
46{
47 size_t hlen = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
48 gcry_md_hd_t mdh;
49 unsigned char *hash;
50 gpg_error_t err;
51
52 err = gcry_md_open(&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
53 if (err != GPG_ERR_NO_ERROR)
54 return EINA_FALSE;
55
56 err = gcry_md_setkey(mdh, key, key_len);
57 if (err != GPG_ERR_NO_ERROR)
58 {
59 gcry_md_close(mdh);
60 return EINA_FALSE;
61 }
62
63 gcry_md_write(mdh, data, data_len);
64
65 hash = gcry_md_read(mdh, GCRY_MD_SHA1);
66 if (!hash)
67 {
68 gcry_md_close(mdh);
69 return EINA_FALSE;
70 }
71
72 memcpy(res, hash, hlen);
73
74 gcry_md_close(mdh);
75
76 return EINA_TRUE;
77}
78# endif /* ifdef HAVE_GNUTLS */
79
80static Eina_Bool
81emile_pbkdf2_sha1(const char *key,
82 int key_len,
83 const unsigned char *salt,
84 unsigned int salt_len,
85 int iter,
86 unsigned char *res,
87 int res_len)
88{
89 unsigned char digest[20];
90 unsigned char tab[4];
91 unsigned char *p = res;
92 unsigned char *buf;
93 unsigned long i;
94 int digest_len = 20;
95 int len = res_len;
96 int tmp_len;
97 int j, k;
98# ifdef HAVE_GNUTLS
99# else
100 HMAC_CTX hctx;
101# endif /* ifdef HAVE_GNUTLS */
102
103 buf = alloca(salt_len + 4);
104 if (!buf) return EINA_FALSE;
105
106 for (i = 1; len; len -= tmp_len, p += tmp_len, i++)
107 {
108 if (len > digest_len)
109 tmp_len = digest_len;
110 else
111 tmp_len = len;
112
113 tab[0] = (unsigned char)(i & 0xff000000) >> 24;
114 tab[1] = (unsigned char)(i & 0x00ff0000) >> 16;
115 tab[2] = (unsigned char)(i & 0x0000ff00) >> 8;
116 tab[3] = (unsigned char)(i & 0x000000ff) >> 0;
117
118# ifdef HAVE_GNUTLS
119 memcpy(buf, salt, salt_len);
120 memcpy(buf + salt_len, tab, 4);
121 if (!emile_hmac_sha1(key, key_len, buf, salt_len + 4, digest))
122 return EINA_FALSE;
123# else /* ifdef HAVE_GNUTLS */
124 HMAC_Init(&hctx, key, key_len, EVP_sha1());
125 HMAC_Update(&hctx, salt, salt_len);
126 HMAC_Update(&hctx, tab, 4);
127 HMAC_Final(&hctx, digest, NULL);
128# endif /* ifdef HAVE_GNUTLS */
129 memcpy(p, digest, tmp_len);
130
131 for (j = 1; j < iter; j++)
132 {
133# ifdef HAVE_GNUTLS
134 if (!emile_hmac_sha1(key, key_len, digest, 20, digest))
135 return EINA_FALSE;
136# else /* ifdef HAVE_GNUTLS */
137 HMAC(EVP_sha1(), key, key_len, digest, 20, digest, NULL);
138# endif /* ifdef HAVE_GNUTLS */
139 for (k = 0; k < tmp_len; k++)
140 p[k] ^= digest[k];
141 }
142# ifdef HAVE_GNUTLS
143# else
144 HMAC_cleanup(&hctx);
145# endif /* ifdef HAVE_GNUTLS */
146 }
147
148 return EINA_TRUE;
149}
150
151EAPI Eina_Binbuf *
152emile_binbuf_cipher(const Eina_Binbuf *data,
153 const char *key,
154 unsigned int length)
155{
156#ifdef HAVE_CIPHER
157 /* Cipher declarations */
158 Eina_Binbuf *result;
159 unsigned char *pointer;
160 unsigned char iv[MAX_IV_LEN];
161 unsigned char ik[MAX_KEY_LEN];
162 unsigned char key_material[MAX_IV_LEN + MAX_KEY_LEN];
163 unsigned int salt;
164 unsigned int tmp = 0;
165 unsigned int crypted_length;
166 int opened = 0;
167# ifdef HAVE_GNUTLS
168 /* Gcrypt declarations */
169 gcry_error_t err = 0;
170 gcry_cipher_hd_t cipher;
171# else /* ifdef HAVE_GNUTLS */
172 /* Openssl declarations*/
173 EVP_CIPHER_CTX ctx;
174 unsigned int *buffer = NULL;
175 int tmp_len;
176# endif /* ifdef HAVE_GNUTLS */
177
178# ifdef HAVE_GNUTLS
179 /* Gcrypt salt generation */
180 gcry_create_nonce((unsigned char *)&salt, sizeof(salt));
181# else /* ifdef HAVE_GNUTLS */
182 /* Openssl salt generation */
183 if (!RAND_bytes((unsigned char *)&salt, sizeof (unsigned int)))
184 return NULL;
185
186# endif /* ifdef HAVE_GNUTLS */
187
188 result = eina_binbuf_new();
189 if (!result) return NULL;
190
191 emile_pbkdf2_sha1(key,
192 length,
193 (unsigned char *)&salt,
194 sizeof(unsigned int),
195 2048,
196 key_material,
197 MAX_KEY_LEN + MAX_IV_LEN);
198
199 memcpy(iv, key_material, MAX_IV_LEN);
200 memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN);
201
202 memset(key_material, 0, sizeof (key_material));
203
204 crypted_length = ((((eina_binbuf_length_get(data) + sizeof (unsigned int)) >> 5) + 1) << 5)
205 + sizeof (unsigned int);
206
207 eina_binbuf_append_length(result, (unsigned char*) &salt, sizeof (salt));
208 memset(&salt, 0, sizeof (salt));
209
210 tmp = htonl(eina_binbuf_length_get(data));
211# ifdef HAVE_GNUTLS
212 eina_binbuf_append_length(result, (unsigned char*) &tmp, sizeof (tmp));
213 eina_binbuf_append_buffer(result, data);
214
215 while (eina_binbuf_length_get(result) < crypted_length)
216 {
217 int r;
218
219 r = rand();
220 eina_binbuf_append_length(result, (unsigned char*) &r, sizeof (r));
221 }
222 eina_binbuf_remove(result, crypted_length, eina_binbuf_length_get(result));
223
224 /* Gcrypt create the corresponding cipher
225 AES with a 256 bit key, Cipher Block Chaining mode */
226 err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
227 if (err) goto on_error;
228
229 opened = 1;
230 err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN);
231 if (err) goto on_error;
232
233 err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN);
234 if (err) goto on_error;
235
236 memset(iv, 0, sizeof (iv));
237 memset(ik, 0, sizeof (ik));
238
239 pointer = (unsigned char*) eina_binbuf_string_get(result);
240
241 /* Gcrypt encrypt */
242 err = gcry_cipher_encrypt(cipher, pointer + sizeof (int),
243 eina_binbuf_length_get(result) - sizeof (int),
244 NULL, 0);
245 if (err) goto on_error;
246
247 /* Gcrypt close the cipher */
248 gcry_cipher_close(cipher);
249# else /* ifdef HAVE_GNUTLS */
250 buffer = malloc(crypted_length - sizeof (int));
251 if (!buffer) goto on_error;
252 *buffer = tmp;
253
254 eina_binbuf_append_length(result,
255 (unsigned char *) buffer,
256 crypted_length - sizeof (int));
257 memcpy(buffer + 1,
258 eina_binbuf_string_get(data),
259 eina_binbuf_length_get(data));
260
261 /* Openssl create the corresponding cipher
262 AES with a 256 bit key, Cipher Block Chaining mode */
263 EVP_CIPHER_CTX_init(&ctx);
264 if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv))
265 goto on_error;
266
267 opened = 1;
268
269 memset(iv, 0, sizeof (iv));
270 memset(ik, 0, sizeof (ik));
271
272 pointer = (unsigned char*) eina_binbuf_string_get(result);
273
274 /* Openssl encrypt */
275 if (!EVP_EncryptUpdate(&ctx, pointer + sizeof (int), &tmp_len,
276 (unsigned char *)buffer,
277 eina_binbuf_length_get(data) + sizeof(unsigned int)))
278 goto on_error;
279
280 /* Openssl close the cipher */
281 if (!EVP_EncryptFinal_ex(&ctx, pointer + sizeof (int) + tmp_len,
282 &tmp_len))
283 goto on_error;
284
285 EVP_CIPHER_CTX_cleanup(&ctx);
286 free(buffer);
287# endif /* ifdef HAVE_GNUTLS */
288
289 return result;
290
291on_error:
292 memset(iv, 0, sizeof (iv));
293 memset(ik, 0, sizeof (ik));
294
295# ifdef HAVE_GNUTLS
296 /* Gcrypt error */
297 if (opened)
298 gcry_cipher_close(cipher);
299
300# else /* ifdef HAVE_GNUTLS */
301 /* Openssl error */
302 if (opened)
303 EVP_CIPHER_CTX_cleanup(&ctx);
304
305 free(buffer);
306
307# endif /* ifdef HAVE_GNUTLS */
308 /* General error */
309 eina_binbuf_free(result);
310
311 return NULL;
312#else /* ifdef HAVE_CIPHER */
313 /* Cipher not supported */
314 (void)data;
315 (void)size;
316 (void)key;
317 (void)length;
318 (void)result;
319 (void)result_length;
320 return NULL;
321#endif /* ifdef HAVE_CIPHER */
322}
323
324EAPI Eina_Binbuf *
325emile_binbuf_decipher(const Eina_Binbuf *data,
326 const char *key,
327 unsigned int length)
328{
329#ifdef HAVE_CIPHER
330 Eina_Binbuf *result = NULL;
331 unsigned int *over;
332 unsigned char ik[MAX_KEY_LEN];
333 unsigned char iv[MAX_IV_LEN];
334 unsigned char key_material[MAX_KEY_LEN + MAX_IV_LEN];
335 unsigned int salt;
336 unsigned int size;
337 int tmp_len;
338 int tmp = 0;
339 int opened = 0;
340
341 over = (unsigned int*) eina_binbuf_string_get(data);
342 size = eina_binbuf_length_get(data);
343
344 /* At least the salt and an AES block */
345 if (size < sizeof(unsigned int) + 16)
346 return NULL;
347
348 /* Get the salt */
349 salt = *over;
350
351 /* Generate the iv and the key with the salt */
352 emile_pbkdf2_sha1(key, length, (unsigned char *)&salt,
353 sizeof(unsigned int), 2048, key_material,
354 MAX_KEY_LEN + MAX_IV_LEN);
355
356 memcpy(iv, key_material, MAX_IV_LEN);
357 memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN);
358
359 memset(key_material, 0, sizeof (key_material));
360 memset(&salt, 0, sizeof (salt));
361
362 /* Align to AES block size if size is not align */
363 tmp_len = size - sizeof (unsigned int);
364 if ((tmp_len & 0x1F) != 0) goto on_error;
365
366 result = eina_binbuf_new();
367 if (!result) goto on_error;
368
369 eina_binbuf_append_length(result, (unsigned char*) (over + 1), tmp_len);
370
371# ifdef HAVE_GNUTLS
372 gcry_error_t err = 0;
373 gcry_cipher_hd_t cipher;
374
375 /* Gcrypt create the corresponding cipher */
376 err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
377 if (err) goto on_error;
378
379 err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN);
380 if (err) goto on_error;
381
382 err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN);
383 if (err) goto on_error;
384
385 memset(iv, 0, sizeof (iv));
386 memset(ik, 0, sizeof (ik));
387
388 /* Gcrypt decrypt */
389 err = gcry_cipher_decrypt(cipher,
390 (void*) eina_binbuf_string_get(result), tmp_len,
391 (void*) (over + 1), tmp_len);
392 if (err) goto on_error;
393
394 /* Gcrypt close the cipher */
395 gcry_cipher_close(cipher);
396
397# else /* ifdef HAVE_GNUTLS */
398 EVP_CIPHER_CTX ctx;
399
400 /* Openssl create the corresponding cipher */
401 EVP_CIPHER_CTX_init(&ctx);
402 opened = 1;
403
404 if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv))
405 goto on_error;
406
407 memset(iv, 0, sizeof (iv));
408 memset(ik, 0, sizeof (ik));
409
410 /* Openssl decrypt */
411 if (!EVP_DecryptUpdate(&ctx,
412 (void*) eina_binbuf_string_get(result), &tmp,
413 (void*) (over + 1), tmp_len))
414 goto on_error;
415
416 /* Openssl close the cipher*/
417 EVP_CIPHER_CTX_cleanup(&ctx);
418# endif /* ifdef HAVE_GNUTLS */
419 /* Get the decrypted data size */
420 tmp = *(unsigned int*)(eina_binbuf_string_get(result));
421 tmp = ntohl(tmp);
422 if (tmp > tmp_len || tmp <= 0)
423 goto on_error;
424
425 /* Remove header and padding */
426 eina_binbuf_remove(result, 0, sizeof (unsigned int));
427 eina_binbuf_remove(result, tmp, eina_binbuf_length_get(result));
428
429 return result;
430
431on_error:
432 memset(iv, 0, sizeof (iv));
433 memset(ik, 0, sizeof (ik));
434
435# ifdef HAVE_GNUTLS
436 (void)opened;
437# else
438 if (opened)
439 EVP_CIPHER_CTX_cleanup(&ctx);
440
441# endif /* ifdef HAVE_GNUTLS */
442 eina_binbuf_free(result);
443
444 return NULL;
445#else /* ifdef HAVE_CIPHER */
446 (void)data;
447 (void)size;
448 (void)key;
449 (void)length;
450 (void)result;
451 (void)result_length;
452 return NULL;
453#endif /* ifdef HAVE_CIPHER */
454}
diff --git a/src/lib/emile/emile_private.h b/src/lib/emile/emile_private.h
new file mode 100644
index 0000000000..0210379091
--- /dev/null
+++ b/src/lib/emile/emile_private.h
@@ -0,0 +1,27 @@
1#ifndef EMILE_PRIVATE_H_
2# define EMILE_PRIVATE_H_
3
4extern int _emile_log_dom_global;
5
6#ifdef ERR
7# undef ERR
8#endif /* ifdef ERR */
9#define ERR(...) EINA_LOG_DOM_ERR(_emile_log_dom_global, __VA_ARGS__)
10#ifdef DBG
11# undef DBG
12#endif /* ifdef DBG */
13#define DBG(...) EINA_LOG_DOM_DBG(_emile_log_dom_global, __VA_ARGS__)
14#ifdef INF
15# undef INF
16#endif /* ifdef INF */
17#define INF(...) EINA_LOG_DOM_INFO(_emile_log_dom_global, __VA_ARGS__)
18#ifdef WRN
19# undef WRN
20#endif /* ifdef WRN */
21#define WRN(...) EINA_LOG_DOM_WARN(_emile_log_dom_global, __VA_ARGS__)
22#ifdef CRI
23# undef CRI
24#endif /* ifdef CRI */
25#define CRI(...) EINA_LOG_DOM_CRIT(_emile_log_dom_global, __VA_ARGS__)
26
27#endif /* EMILE_PRIVATE_H_ */