Ticket #231: eet_cipher.c

File eet_cipher.c, 25.3 KB (added by tomboy64, 3 years ago)

the c-file it bugs out on

Line 
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <string.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <sys/mman.h>
10
11#ifndef _MSC_VER
12# include <unistd.h>
13#endif
14
15#ifdef HAVE_NETINET_IN_H
16# include <netinet/in.h>
17#endif
18
19#ifdef HAVE_SIGNATURE
20# ifdef HAVE_GNUTLS
21#  include <gnutls/gnutls.h>
22#  include <gnutls/x509.h>
23# else
24#  include <openssl/rsa.h>
25#  include <openssl/objects.h>
26#  include <openssl/err.h>
27#  include <openssl/ssl.h>
28#  include <openssl/dh.h>
29#  include <openssl/dsa.h>
30#  include <openssl/evp.h>
31#  include <openssl/x509.h>
32#  include <openssl/pem.h>
33# endif
34#endif
35
36#ifdef HAVE_OPENSSL
37#  include <openssl/sha.h>
38#endif
39
40#ifdef HAVE_CIPHER
41# ifdef HAVE_GNUTLS
42#  include <gnutls/x509.h>
43#  include <gcrypt.h>
44# else
45#  include <openssl/evp.h>
46#  include <openssl/hmac.h>
47#  include <openssl/rand.h>
48# endif
49#endif
50
51#include "Eet.h"
52#include "Eet_private.h"
53
54#define EET_MAGIC_SIGN 0x1ee74271
55
56#ifdef HAVE_GNUTLS
57# define MAX_KEY_LEN 32
58# define MAX_IV_LEN 16
59#else
60# define MAX_KEY_LEN EVP_MAX_KEY_LENGTH
61# define MAX_IV_LEN EVP_MAX_IV_LENGTH
62#endif
63
64#ifdef HAVE_CIPHER
65# ifdef HAVE_GNUTLS
66static Eet_Error eet_hmac_sha1(const void *key, size_t key_len, const void *data, size_t data_len, unsigned char *res);
67# endif
68static Eet_Error eet_pbkdf2_sha1(const char *key, int key_len, const unsigned char *salt, unsigned int salt_len, int iter, unsigned char *res, int res_len);
69#endif
70
71struct _Eet_Key
72{
73   int          references;
74#ifdef HAVE_SIGNATURE
75# ifdef HAVE_GNUTLS
76   gnutls_x509_crt_t            certificate;
77   gnutls_x509_privkey_t        private_key;
78# else
79   X509        *certificate;
80   EVP_PKEY    *private_key;
81# endif
82#endif
83};
84
85EAPI Eet_Key*
86eet_identity_open(const char *certificate_file, const char *private_key_file, Eet_Key_Password_Callback cb)
87{
88#ifdef HAVE_SIGNATURE
89  /* Signature declarations */
90  Eet_Key *key = NULL;
91  FILE *fp = NULL;
92# ifdef HAVE_GNUTLS
93  /* Gnutls private declarations */
94  int fd = -1;
95  struct stat st;
96  void *data = NULL;
97  gnutls_datum_t load_file = { NULL, 0 };
98  char pass[1024];
99
100  /* Init */
101  if (!(key = malloc(sizeof(Eet_Key)))) goto on_error;
102  key->references = 1;
103
104  if (gnutls_x509_crt_init(&(key->certificate))) goto on_error;
105  if (gnutls_x509_privkey_init(&(key->private_key))) goto on_error;
106
107  /* Mmap certificate_file */
108  if (!(fp = fopen(certificate_file, "r"))) goto on_error;
109  if ((fd = fileno(fp)) == -1) goto on_error;
110  if (fstat(fd, &st)) goto on_error;
111  if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto on_error;
112
113  /* Import the certificate in Eet_Key structure */
114  load_file.data = data;
115  load_file.size = st.st_size;
116  if (gnutls_x509_crt_import(key->certificate, &load_file, GNUTLS_X509_FMT_PEM) < 0)
117    goto on_error;
118  if (munmap(data, st.st_size)) goto on_error;
119
120  /* Reset values */
121  fclose(fp);
122  fp = NULL;
123  data = NULL;
124  load_file.data = NULL;
125  load_file.size = 0;
126
127  /* Mmap private_key_file */
128  if (!(fp = fopen(private_key_file, "r"))) goto on_error;
129  if ((fd = fileno(fp)) == -1) goto on_error;
130  if (fstat(fd, &st)) goto on_error;
131  if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto on_error;
132
133  /* Import the private key in Eet_Key structure */
134  load_file.data = data;
135  load_file.size = st.st_size;
136  /* Try to directly import the PEM encoded private key */
137  if (gnutls_x509_privkey_import(key->private_key, &load_file, GNUTLS_X509_FMT_PEM) < 0)
138    {
139      /* Else ask for the private key pass */
140      if (cb && cb(pass, 1024, 0, NULL))
141        {
142          /* If pass then try to decode the pkcs 8 private key */
143          if (gnutls_x509_privkey_import_pkcs8(key->private_key, &load_file, GNUTLS_X509_FMT_PEM, pass, 0))
144            goto on_error;
145        }
146      else
147        {
148          /* Else try to import the pkcs 8 private key without pass */
149          if (gnutls_x509_privkey_import_pkcs8(key->private_key, &load_file, GNUTLS_X509_FMT_PEM, NULL, 1))
150            goto on_error;
151        }
152    }
153  if (munmap(data, st.st_size)) goto on_error;
154  fclose(fp);
155
156  return key;
157
158 on_error:
159  if (fp) fclose(fp);
160  if (key)
161    {
162      if (key->certificate) gnutls_x509_crt_deinit(key->certificate);
163      if (key->private_key) gnutls_x509_privkey_deinit(key->private_key);
164      free(key);
165    }
166  if (data) munmap(data, st.st_size);
167# else
168  /* Openssl private declarations */
169  EVP_PKEY *pkey = NULL;
170  X509 *cert = NULL;
171
172  /* Load the X509 certificate in memory. */
173  fp = fopen(certificate_file, "r");
174  if (!fp) return NULL;
175  cert = PEM_read_X509(fp, NULL, NULL, NULL);
176  fclose(fp);
177  if (!cert) goto on_error;
178
179  /* Check the presence of the public key. Just in case. */
180  pkey = X509_get_pubkey(cert);
181  if (!pkey) goto on_error;
182
183  /* Load the private key in memory. */
184  fp = fopen(private_key_file, "r");
185  if (!fp) goto on_error;
186  pkey = PEM_read_PrivateKey(fp, NULL, cb, NULL);
187  fclose(fp);
188  if (!pkey) goto on_error;
189
190  /* Load the certificate and the private key in Eet_Key structure */
191  key = malloc(sizeof(Eet_Key));
192  if (!key) goto on_error;
193  key->references = 1;
194  key->certificate = cert;
195  key->private_key = pkey;
196
197  return key;
198
199 on_error:
200  if (cert) X509_free(cert);
201  if (pkey) EVP_PKEY_free(pkey);
202# endif
203#endif
204  return NULL;
205}
206
207EAPI void
208eet_identity_close(Eet_Key *key)
209{
210#ifdef HAVE_SIGNATURE
211  if (!key || (key->references > 0)) return ;
212# ifdef HAVE_GNUTLS
213  gnutls_x509_crt_deinit(key->certificate);
214  gnutls_x509_privkey_deinit(key->private_key);
215# else
216  X509_free(key->certificate);
217  EVP_PKEY_free(key->private_key);
218# endif
219  free(key);
220#endif
221}
222
223EAPI void
224eet_identity_print(Eet_Key *key, FILE *out)
225{
226#ifdef HAVE_SIGNATURE
227# ifdef HAVE_GNUTLS
228  const char    *names[6] = {
229    "Modulus",
230    "Public exponent",
231    "Private exponent",
232    "First prime",
233    "Second prime",
234    "Coefficient"
235  };
236  int err = 0;
237  gnutls_datum_t data = { NULL, 0 };
238  gnutls_datum_t rsa_raw[6];
239  size_t size = 128;
240  char *res = NULL;
241  char buf[33];
242  unsigned int i, j;
243
244  if (!key) return ;
245
246  if (key->private_key)
247    {
248      if (gnutls_x509_privkey_export_rsa_raw(key->private_key,
249                                             rsa_raw + 0,  /* Modulus */
250                                             rsa_raw + 1,  /* Public exponent */
251                                             rsa_raw + 2,  /* Private exponent */
252                                             rsa_raw + 3,  /* First prime */
253                                             rsa_raw + 4,  /* Second prime */
254                                             rsa_raw + 5)) /* Coefficient */
255        goto on_error;
256      if (!(res = malloc(size))) goto on_error;
257
258      fprintf(out, "Private Key:\n");
259      buf[32] = '\0';
260
261      for (i = 0; i < 6; i++)
262        {
263          while ((err = gnutls_hex_encode(rsa_raw + i, res, &size)) == GNUTLS_E_SHORT_MEMORY_BUFFER)
264            {
265              size += 128;
266              if (!(res = realloc(res, size))) goto on_error;
267            }
268          if (err) goto on_error;
269
270          fprintf(out, "\t%s:\n", names[i]);
271          for (j = 0; strlen(res) > j; j += 32)
272            {
273              snprintf(buf, 32, "%s", res + j);
274              fprintf(out, "\t\t%s\n", buf);
275            }
276        }
277      free(res);
278      res = NULL;
279    }
280
281  if (key->certificate)
282    {
283      fprintf(out, "Public certificate:\n");
284      if (gnutls_x509_crt_print(key->certificate, GNUTLS_X509_CRT_FULL, &data)) goto on_error;
285      fprintf(out, "%s", data.data);
286      gnutls_free(data.data);
287      data.data = NULL;
288    }
289
290 on_error:
291  if (res) free(res);
292  if (data.data) gnutls_free(data.data);
293  return ;
294# else
295  RSA *rsa;
296  DSA *dsa;
297  DH *dh;
298
299  if (!key) return ;
300
301  rsa = EVP_PKEY_get1_RSA(key->private_key);
302  if (rsa)
303    {
304      fprintf(out, "Private key (RSA):\n");
305      RSA_print_fp(out, rsa, 0);
306    }
307
308  dsa = EVP_PKEY_get1_DSA(key->private_key);
309  if (dsa)
310    {
311      fprintf(out, "Private key (DSA):\n");
312      DSA_print_fp(out, dsa, 0);
313    }
314
315  dh = EVP_PKEY_get1_DH(key->private_key);
316  if (dh)
317    {
318      fprintf(out, "Private key (DH):\n");
319      DHparams_print_fp(out, dh);
320    }
321
322  fprintf(out, "Public certificate:\n");
323  X509_print_fp(out, key->certificate);
324# endif
325#else
326  fprintf(out, "You need to compile signature support in EET.\n");
327#endif
328}
329
330void
331eet_identity_ref(Eet_Key *key)
332{
333   if (key == NULL) return ;
334   key->references++;
335}
336
337void
338eet_identity_unref(Eet_Key *key)
339{
340   if (key == NULL) return ;
341   key->references--;
342   eet_identity_close(key);
343}
344
345void *
346eet_identity_compute_sha1(const void *data_base, unsigned int data_length,
347                          int *sha1_length)
348{
349   void *result;
350
351#ifdef HAVE_GNUTLS
352   result = malloc(gcry_md_get_algo_dlen(GCRY_MD_SHA1));
353   if (!result) return NULL;
354
355   gcry_md_hash_buffer(GCRY_MD_SHA1, result, data_base, data_length);
356   if (sha1_length) *sha1_length = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
357#else
358# ifdef HAVE_OPENSSL
359   result = malloc(SHA_DIGEST_LENGTH);
360   if (!result) return NULL;
361
362   SHA1(data_base, data_length, result);
363   if (sha1_length) *sha1_length = SHA_DIGEST_LENGTH;
364# else
365   result = NULL;
366# endif
367#endif
368
369   return result;
370}
371
372Eet_Error
373eet_identity_sign(FILE *fp, Eet_Key *key)
374{
375#ifdef HAVE_SIGNATURE
376   Eet_Error err = EET_ERROR_NONE;
377   struct stat st_buf;
378   void *data;
379   int fd;
380   int head[3];
381   unsigned char *sign = NULL;
382   unsigned char *cert = NULL;
383# ifdef HAVE_GNUTLS
384   gnutls_datum_t datum = { NULL, 0 };
385   size_t sign_len = 0;
386   size_t cert_len = 0;
387# else
388   EVP_MD_CTX md_ctx;
389   unsigned int sign_len = 0;
390   int cert_len = 0;
391# endif
392
393   /* A few check and flush pending write. */
394   if (!fp || !key || !key->certificate || !key->private_key)
395     return EET_ERROR_BAD_OBJECT;
396
397   /* Get the file size. */
398   fd = fileno(fp);
399   if (fd < 0) return EET_ERROR_BAD_OBJECT;
400   if (fstat(fd, &st_buf) < 0) return EET_ERROR_MMAP_FAILED;
401
402   /* Map the file in memory. */
403   data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
404   if (data == MAP_FAILED) return EET_ERROR_MMAP_FAILED;
405
406# ifdef HAVE_GNUTLS
407   datum.data = data;
408   datum.size = st_buf.st_size;
409
410   /* Get the signature length */
411   if (gnutls_x509_privkey_sign_data(key->private_key, GNUTLS_DIG_SHA1, 0, &datum, sign, &sign_len) &&
412       !sign_len)
413     {
414       err = EET_ERROR_SIGNATURE_FAILED;
415       goto on_error;
416     }
417
418   /* Get the signature */
419   sign = malloc(sign_len);
420   if (!sign || gnutls_x509_privkey_sign_data(key->private_key, GNUTLS_DIG_SHA1, 0, &datum, sign, &sign_len))
421     {
422       if (!sign) err = EET_ERROR_OUT_OF_MEMORY;
423       else err = EET_ERROR_SIGNATURE_FAILED;
424       goto on_error;
425     }
426
427   /* Get the certificate length */
428   if (gnutls_x509_crt_export(key->certificate, GNUTLS_X509_FMT_DER, cert, &cert_len) &&
429       !cert_len)
430     {
431       err = EET_ERROR_SIGNATURE_FAILED;
432       goto on_error;
433     }
434
435   /* Get the certificate */
436   cert = malloc(cert_len);
437   if (!cert || gnutls_x509_crt_export(key->certificate, GNUTLS_X509_FMT_DER, cert, &cert_len))
438     {
439       if (!cert) err = EET_ERROR_OUT_OF_MEMORY;
440       else err = EET_ERROR_SIGNATURE_FAILED;
441       goto on_error;
442     }
443# else
444   sign_len = EVP_PKEY_size(key->private_key);
445   sign = malloc(sign_len);
446   if (sign == NULL)
447     {
448        err = EET_ERROR_OUT_OF_MEMORY;
449        goto on_error;
450     }
451
452   /* Do the signature. */
453   EVP_SignInit(&md_ctx, EVP_sha1());
454   EVP_SignUpdate(&md_ctx, data, st_buf.st_size);
455   err = EVP_SignFinal(&md_ctx, sign, (unsigned int *)&sign_len, key->private_key);
456   if (err != 1)
457     {
458        ERR_print_errors_fp(stdout);
459        err = EET_ERROR_SIGNATURE_FAILED;
460        goto on_error;
461     }
462
463   /* Give me the der (binary form for X509). */
464   cert_len = i2d_X509(key->certificate, &cert);
465   if (cert_len < 0)
466     {
467        ERR_print_errors_fp(stdout);
468        err = EET_ERROR_X509_ENCODING_FAILED;
469        goto on_error;
470     }
471# endif
472   /* Append the signature at the end of the file. */
473   head[0] = (int) htonl ((unsigned int) EET_MAGIC_SIGN);
474   head[1] = (int) htonl ((unsigned int) sign_len);
475   head[2] = (int) htonl ((unsigned int) cert_len);
476
477   if (fwrite(head, sizeof(head), 1, fp) != 1)
478     {
479        err = EET_ERROR_WRITE_ERROR;
480        goto on_error;
481     }
482   if (fwrite(sign, sign_len, 1, fp) != 1)
483     {
484        err = EET_ERROR_WRITE_ERROR;
485        goto on_error;
486     }
487   if (fwrite(cert, cert_len, 1, fp) != 1)
488     {
489        err = EET_ERROR_WRITE_ERROR;
490        goto on_error;
491     }
492
493 on_error:
494# ifdef HAVE_GNUTLS
495   if (cert) free(cert);
496# else
497   if (cert) OPENSSL_free(cert);
498# endif
499   if (sign) free(sign);
500   munmap(data, st_buf.st_size);
501   return err;
502#else
503   return EET_ERROR_NOT_IMPLEMENTED;
504#endif
505}
506
507const void*
508eet_identity_check(const void *data_base, unsigned int data_length,
509                   void **sha1, int *sha1_length,
510                   const void *signature_base, unsigned int signature_length,
511                   const void **raw_signature_base, unsigned int *raw_signature_length,
512                   int *x509_length)
513{
514#ifdef HAVE_SIGNATURE
515   const int *header = signature_base;
516   const unsigned char *sign;
517   const unsigned char *cert_der;
518   int sign_len;
519   int cert_len;
520   int magic;
521
522   /* At least the header size */
523   if (signature_length < sizeof(int) * 3) return NULL;
524
525   /* Get the header */
526   magic = ntohl(header[0]);
527   sign_len = ntohl(header[1]);
528   cert_len = ntohl(header[2]);
529
530   /* Verify the header */
531   if (magic != EET_MAGIC_SIGN) return NULL;
532   if (sign_len + cert_len + sizeof(int) * 3 > signature_length) return NULL;
533
534   /* Update the signature and certificate pointer */
535   sign = signature_base + sizeof(int) * 3;
536   cert_der = sign + sign_len;
537
538# ifdef HAVE_GNUTLS
539   gnutls_x509_crt_t cert;
540   gcry_md_hd_t md;
541   gnutls_datum_t datum;
542   gnutls_datum_t signature;
543   unsigned char *hash;
544   int err;
545
546   /* Create an understanding certificate structure for gnutls */
547   datum.data = (void *)cert_der;
548   datum.size = cert_len;
549   gnutls_x509_crt_init(&cert);
550   gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER);
551
552   signature.data = (void *)sign;
553   signature.size = sign_len;
554
555   /* Verify the signature */
556#  if EET_USE_NEW_GNUTLS_API
557   /*
558     I am waiting for my patch being accepted in GnuTLS release.
559     But we now have a way to prevent double computation of SHA1.
560    */
561   err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
562   if (err < 0) return NULL;
563
564   gcry_md_write(md, data_base, data_length);
565
566   hash = gcry_md_read(md, GCRY_MD_SHA1);
567   if (hash == NULL)
568     {
569        gcry_md_close(md);
570        return NULL;
571     }
572
573   datum.size = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
574   datum.data = hash;
575
576   if (!gnutls_x509_crt_verify_hash(cert, 0, &datum, &signature))
577     {
578        gcry_md_close(md);
579        return NULL;
580     }
581
582   if (sha1)
583     {
584        *sha1 = malloc(datum.size);
585        if (!*sha1)
586          {
587             gcry_md_close(md);
588             return NULL;
589          }
590
591        memcpy(*sha1, hash, datum.size);
592        *sha1_length = datum.size;
593     }
594
595   gcry_md_close(md);
596#  else
597   datum.data = (void *)data_base;
598   datum.size = data_length;
599
600   if (!gnutls_x509_crt_verify_data(cert, 0, &datum, &signature))
601     return NULL;
602
603   if (sha1)
604     {
605        *sha1 = NULL;
606        *sha1_length = -1;
607     }
608#  endif
609  gnutls_x509_crt_deinit(cert);
610
611# else
612   const unsigned char *tmp;
613   EVP_PKEY *pkey;
614   X509 *x509;
615   EVP_MD_CTX md_ctx;
616   int err;
617
618   /* Strange but d2i_X509 seems to put 0 all over the place. */
619   tmp = alloca(cert_len);
620   memcpy((char*) tmp, cert_der, cert_len);
621   x509 = d2i_X509(NULL, &tmp, cert_len);
622   if (x509 == NULL) return NULL;
623
624   /* Get public key - eay */
625   pkey=X509_get_pubkey(x509);
626   if (pkey == NULL)
627     {
628        X509_free(x509);
629        return NULL;
630     }
631
632   /* Verify the signature */
633   EVP_VerifyInit(&md_ctx, EVP_sha1());
634   EVP_VerifyUpdate(&md_ctx, data_base, data_length);
635   err = EVP_VerifyFinal(&md_ctx, sign, sign_len, pkey);
636
637   X509_free(x509);
638   EVP_PKEY_free(pkey);
639
640   if (sha1)
641     {
642        *sha1 = NULL;
643        *sha1_length = -1;
644     }
645
646   if (err != 1)
647     return NULL;
648# endif
649   if (x509_length) *x509_length = cert_len;
650   if (raw_signature_base) *raw_signature_base = sign;
651   if (raw_signature_length) *raw_signature_length = sign_len;
652   return cert_der;
653#else
654   return NULL;
655#endif
656}
657
658EAPI void
659eet_identity_certificate_print(const unsigned char *certificate, int der_length, FILE *out)
660{
661#ifdef HAVE_SIGNATURE
662  if (!certificate || !out || der_length <= 0)
663     {
664        fprintf(out, "No certificate provided.\n");
665        return ;
666     }
667# ifdef HAVE_GNUTLS
668  gnutls_datum_t datum;
669  gnutls_x509_crt_t cert;
670
671  /* Create an understanding certificate structure for gnutls */
672  datum.data = (void *)certificate;
673  datum.size = der_length;
674  if (gnutls_x509_crt_init(&cert)) goto on_error;
675  if (gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER)) goto on_error;
676
677  /* Pretty print the certificate */
678  datum.data = NULL;
679  datum.size = 0;
680  if (gnutls_x509_crt_print(cert, GNUTLS_X509_CRT_FULL, &datum)) goto on_error;
681  fprintf(out, "Public certificate :\n");
682  fprintf(out, "%s", datum.data);
683
684 on_error:
685  if (datum.data) gnutls_free(datum.data);
686  gnutls_x509_crt_deinit(cert);
687# else
688   const unsigned char *tmp;
689   X509 *x509;
690
691   /* Strange but d2i_X509 seems to put 0 all over the place. */
692   tmp = alloca(der_length);
693   memcpy((char*) tmp, certificate, der_length);
694   x509 = d2i_X509(NULL, &tmp, der_length);
695   if (x509 == NULL)
696     {
697        fprintf(out, "Not a valid certificate.\n");
698        return ;
699     }
700
701   fprintf(out, "Public certificate :\n");
702   X509_print_fp(out, x509);
703
704   X509_free(x509);
705# endif
706#else
707   fprintf(out, "You need to compile signature support in EET.\n");
708#endif
709}
710
711Eet_Error
712eet_cipher(const void *data, unsigned int size, const char *key, unsigned int length, void **result, unsigned int *result_length)
713{
714#ifdef HAVE_CIPHER
715  /* Cipher declarations */
716   unsigned int *ret = NULL;
717   unsigned char iv[MAX_IV_LEN];
718   unsigned char ik[MAX_KEY_LEN];
719   unsigned char key_material[MAX_IV_LEN + MAX_KEY_LEN];
720   unsigned int salt;
721   unsigned int tmp = 0;
722   int crypted_length;
723   int opened = 0;
724# ifdef HAVE_GNUTLS
725   /* Gcrypt declarations */
726   gcry_error_t err = 0;
727   gcry_cipher_hd_t cipher;
728# else
729   /* Openssl declarations*/
730   EVP_CIPHER_CTX ctx;
731   unsigned int *buffer;
732   int tmp_len;
733# endif
734
735# ifdef HAVE_GNUTLS
736   /* Gcrypt salt generation */
737   gcry_create_nonce((unsigned char *)&salt, sizeof(salt));
738# else
739   /* Openssl salt generation */
740   if (!RAND_bytes((unsigned char*)&salt, sizeof (unsigned int)))
741     return EET_ERROR_PRNG_NOT_SEEDED;
742#endif
743
744   eet_pbkdf2_sha1(key, length, (unsigned char *)&salt, sizeof(unsigned int), 2048, key_material, MAX_KEY_LEN + MAX_IV_LEN);
745
746   memcpy(iv, key_material, MAX_IV_LEN);
747   memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN);
748
749   crypted_length = ((((size + sizeof (unsigned int)) >> 5) + 1) << 5);
750   ret = malloc(crypted_length + sizeof(unsigned int));
751   if (!ret) return EET_ERROR_OUT_OF_MEMORY;
752
753   *ret = salt;
754   tmp = htonl(size);
755
756#ifdef HAVE_GNUTLS
757   *(ret + 1) = tmp;
758   memcpy(ret + 2, data, size);
759
760   /* Gcrypt create the corresponding cipher
761      AES with a 256 bit key, Cipher Block Chaining mode */
762   err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
763   if (err) goto on_error;
764   opened = 1;
765   err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN);
766   if (err) goto on_error;
767   err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN);
768   if (err) goto on_error;
769
770   /* Gcrypt encrypt */
771   err = gcry_cipher_encrypt(cipher, (unsigned char *)(ret + 1), crypted_length, NULL, 0);
772   if (err) goto on_error;
773
774   /* Gcrypt close the cipher */
775   gcry_cipher_close(cipher);
776# else
777   buffer = alloca(crypted_length);
778   *buffer = tmp;
779
780   memcpy(buffer + 1, data, size);
781
782   /* Openssl create the corresponding cipher
783      AES with a 256 bit key, Cipher Block Chaining mode */
784   EVP_CIPHER_CTX_init(&ctx);
785   if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv)) goto on_error;
786   opened = 1;
787
788   /* Openssl encrypt */
789   if (!EVP_EncryptUpdate(&ctx, (unsigned char*)(ret + 1), &tmp_len, (unsigned char*) buffer, size + sizeof (unsigned int)))
790     goto on_error;
791
792   /* Openssl close the cipher */
793   if (!EVP_EncryptFinal_ex(&ctx, ((unsigned char*)(ret + 1)) + tmp_len, &tmp_len))
794     goto on_error;
795   EVP_CIPHER_CTX_cleanup(&ctx);
796# endif
797
798   /* Set return values */
799   if (result_length) *result_length = crypted_length + sizeof(unsigned int);
800   if (result) *result = ret;
801   else free(ret);
802
803   return EET_ERROR_NONE;
804
805 on_error:
806# ifdef HAVE_GNUTLS
807   /* Gcrypt error */
808   if (opened) gcry_cipher_close(cipher);
809# else
810   /* Openssl error */
811   if (opened) EVP_CIPHER_CTX_cleanup(&ctx);
812# endif
813   /* General error */
814   if (ret) free(ret);
815   if (result) *result = NULL;
816   if (result_length) *result_length = 0;
817
818   return EET_ERROR_ENCRYPT_FAILED;
819#else
820   /* Cipher not supported */
821   (void) data;
822   (void) size;
823   (void) key;
824   (void) length;
825   (void) result;
826   (void) result_length;
827   return EET_ERROR_NOT_IMPLEMENTED;
828#endif
829}
830
831Eet_Error
832eet_decipher(const void *data, unsigned int size, const char *key, unsigned int length, void **result, unsigned int *result_length)
833{
834#ifdef HAVE_CIPHER
835   const unsigned int *over = data;
836   unsigned int *ret = NULL;
837   unsigned char ik[MAX_KEY_LEN];
838   unsigned char iv[MAX_IV_LEN];
839   unsigned char key_material[MAX_KEY_LEN + MAX_IV_LEN];
840   unsigned int salt;
841   int tmp_len;
842   int tmp = 0;
843
844   /* At least the salt and an AES block */
845   if (size < sizeof(unsigned int) + 16) return EET_ERROR_BAD_OBJECT;
846
847   /* Get the salt */
848   salt = *over;
849
850   /* Generate the iv and the key with the salt */
851   eet_pbkdf2_sha1(key, length, (unsigned char *)&salt, sizeof(unsigned int), 2048, key_material, MAX_KEY_LEN + MAX_IV_LEN);
852   memcpy(iv, key_material, MAX_IV_LEN);
853   memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN);
854
855   /* Align to AES block size if size is not align */
856   tmp_len = size - sizeof (unsigned int);
857   if ((tmp_len & 0x1F) != 0) goto on_error;
858
859   ret = malloc(tmp_len);
860   if (!ret) goto on_error;
861
862# ifdef HAVE_GNUTLS
863   gcry_error_t err = 0;
864   gcry_cipher_hd_t cipher;
865
866   /* Gcrypt create the corresponding cipher */
867   err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
868   if (err) return EET_ERROR_DECRYPT_FAILED;
869   err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN);
870   if (err) goto on_error;
871   err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN);
872   if (err) goto on_error;
873
874   /* Gcrypt decrypt */
875   err = gcry_cipher_decrypt(cipher, ret, tmp_len, ((unsigned int *)data) + 1, tmp_len);
876   if (err) goto on_error;
877
878   /* Gcrypt close the cipher */
879   gcry_cipher_close(cipher);
880
881# else
882   EVP_CIPHER_CTX ctx;
883   int opened = 0;
884
885   /* Openssl create the corresponding cipher */
886   EVP_CIPHER_CTX_init(&ctx);
887   opened = 1;
888
889   if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv))
890     goto on_error;
891
892   /* Openssl decrypt */
893   if (!EVP_DecryptUpdate(&ctx, (unsigned char *) ret, &tmp,
894                          (unsigned char *) (over + 1), tmp_len))
895     goto on_error;
896
897   /* Openssl close the cipher*/
898   EVP_CIPHER_CTX_cleanup(&ctx);
899# endif
900   /* Get the decrypted data size */
901   tmp = *ret;
902   tmp = ntohl(tmp);
903   if (tmp > tmp_len) goto on_error;
904
905   /* Update the return values */
906   if (result_length) *result_length = tmp;
907   if (result)
908     {
909       *result = NULL;
910       *result = malloc(tmp);
911       if (!*result)
912         goto on_error;
913       memcpy(*result, ret + 1, tmp);
914     }
915   free(ret);
916
917   return EET_ERROR_NONE;
918
919 on_error:
920# ifdef HAVE_GNUTLS
921# else
922   if (opened) EVP_CIPHER_CTX_cleanup(&ctx);
923# endif
924   if (result) *result = NULL;
925   if (result_length) *result_length = 0;
926   if (ret) free(ret);
927
928   return EET_ERROR_DECRYPT_FAILED;
929#else
930   (void) data;
931   (void) size;
932   (void) key;
933   (void) length;
934   (void) result;
935   (void) result_length;
936   return EET_ERROR_NOT_IMPLEMENTED;
937#endif
938}
939
940#ifdef HAVE_CIPHER
941# ifdef HAVE_GNUTLS
942static Eet_Error
943eet_hmac_sha1(const void *key, size_t key_len,
944              const void *data, size_t data_len, unsigned char *res)
945{
946  size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
947  gcry_md_hd_t mdh;
948  unsigned char *hash;
949  gpg_error_t err;
950
951  err = gcry_md_open(&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
952  if (err != GPG_ERR_NO_ERROR)
953    return 1;
954
955  err = gcry_md_setkey(mdh, key, key_len);
956  if (err != GPG_ERR_NO_ERROR)
957    {
958      gcry_md_close(mdh);
959      return 1;
960    }
961
962  gcry_md_write(mdh, data, data_len);
963
964  hash = gcry_md_read(mdh, GCRY_MD_SHA1);
965  if (hash == NULL)
966    {
967      gcry_md_close(mdh);
968      return 1;
969    }
970
971  memcpy(res, hash, hlen);
972
973  gcry_md_close(mdh);
974
975  return 0;
976}
977# endif
978
979static Eet_Error
980eet_pbkdf2_sha1(const char          *key,
981                int                  key_len,
982                const unsigned char *salt,
983                unsigned int         salt_len,
984                int                  iter,
985                unsigned char       *res,
986                int                  res_len)
987{
988  unsigned char         digest[20];
989  unsigned char         tab[4];
990  unsigned char        *p = res;
991  unsigned char        *buf;
992  unsigned long         i;
993  int                   digest_len = 20;
994  int                   len = res_len;
995  int                   tmp_len;
996  int                   j, k;
997# ifdef HAVE_GNUTLS
998# else
999  HMAC_CTX              hctx;
1000# endif
1001
1002  buf = alloca(salt_len + 4);
1003  if (!buf) return 1;
1004
1005  for (i = 1; len; len -= tmp_len, p += tmp_len, i++)
1006    {
1007      if (len > digest_len) tmp_len = digest_len;
1008      else tmp_len = len;
1009
1010      tab[0] = (unsigned char)(i & 0xff000000) >> 24;
1011      tab[1] = (unsigned char)(i & 0x00ff0000) >> 16;
1012      tab[2] = (unsigned char)(i & 0x0000ff00) >> 8;
1013      tab[3] = (unsigned char)(i & 0x000000ff) >> 0;
1014
1015# ifdef HAVE_GNUTLS
1016      memcpy(buf, salt, salt_len);
1017      memcpy(buf + salt_len, tab, 4);
1018      eet_hmac_sha1(key, key_len, buf, salt_len + 4, digest);
1019# else
1020      HMAC_Init(&hctx, key, key_len, EVP_sha1());
1021      HMAC_Update(&hctx, salt, salt_len);
1022      HMAC_Update(&hctx, tab, 4);
1023      HMAC_Final(&hctx, digest, NULL);
1024# endif
1025      memcpy(p, digest, tmp_len);
1026
1027      for (j = 1; j < iter; j++)
1028        {
1029# ifdef HAVE_GNUTLS
1030          eet_hmac_sha1(key, key_len, digest, 20, digest);
1031# else
1032          HMAC(EVP_sha1(), key, key_len, digest, 20, digest, NULL);
1033# endif
1034          for (k = 0; k < tmp_len; k++)
1035            p[k] ^= digest[k];
1036        }
1037    }
1038
1039# ifdef HAVE_GNUTLS
1040# else
1041  HMAC_cleanup(&hctx);
1042# endif
1043  return 0;
1044}
1045#endif