diff options
author | Cedric BAIL <cedric.bail@samsung.com> | 2015-01-26 15:48:58 +0100 |
---|---|---|
committer | Cedric BAIL <cedric@osg.samsung.com> | 2015-02-16 14:47:48 +0100 |
commit | 8bfe94dc1120ca63a81d1a5d2900b21bd2c117a5 (patch) | |
tree | 5945069891b547621cb008051fe4d45694137fb5 | |
parent | 866ec799b822ff9919f0445630bb1f1a6385904a (diff) | |
download | efl-8bfe94dc1120ca63a81d1a5d2900b21bd2c117a5.tar.gz |
emile: split OpenSSL, GNUTLS and no cipher into separate file as a first step toward module.
-rw-r--r-- | src/Makefile_Emile.am | 10 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher.c | 445 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher_gnutls.c | 310 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher_openssl.c | 274 |
4 files changed, 600 insertions, 439 deletions
diff --git a/src/Makefile_Emile.am b/src/Makefile_Emile.am index 067eb988ca..a90e5bda09 100644 --- a/src/Makefile_Emile.am +++ b/src/Makefile_Emile.am @@ -19,6 +19,16 @@ static_libs/lz4/lz4hc.c \ static_libs/lz4/lz4hc.h endif +if HAVE_CRYPTO_GNUTLS +lib_emile_libemile_la_SOURCES += lib/emile/emile_cipher_gnutls.c +else +if HAVE_CRYPTO_OPENSSL +lib_emile_libemile_la_SOURCES += lib/emile/emile_cipher_openssl.c +else +lib_emile_libemile_la_SOURCES += lib/emile/emile_cipher.c +endif +endif + lib_emile_libemile_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ diff --git a/src/lib/emile/emile_cipher.c b/src/lib/emile/emile_cipher.c index e48f1dff5f..e1a3ac08d8 100644 --- a/src/lib/emile/emile_cipher.c +++ b/src/lib/emile/emile_cipher.c @@ -2,457 +2,24 @@ # include <config.h> #endif /* ifdef HAVE_CONFIG_H */ -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif - -#ifdef HAVE_OPENSSL -# include <openssl/sha.h> -#endif /* ifdef HAVE_OPENSSL */ - -#ifdef HAVE_CIPHER -# ifdef HAVE_GNUTLS -# include <gnutls/abstract.h> -# include <gnutls/x509.h> -# include <gcrypt.h> -# else /* ifdef HAVE_GNUTLS */ -# include <openssl/evp.h> -# include <openssl/hmac.h> -# include <openssl/rand.h> -# endif /* ifdef HAVE_GNUTLS */ -#endif /* ifdef HAVE_CIPHER */ - #include <Eina.h> #include "Emile.h" #include "emile_private.h" -#ifdef HAVE_GNUTLS -# define MAX_KEY_LEN 32 -# define MAX_IV_LEN 16 -#else /* ifdef HAVE_GNUTLS */ -# define MAX_KEY_LEN EVP_MAX_KEY_LENGTH -# define MAX_IV_LEN EVP_MAX_IV_LENGTH -#endif /* ifdef HAVE_GNUTLS */ - -# ifdef HAVE_GNUTLS -static inline Eina_Bool -emile_hmac_sha1(const void *key, - size_t key_len, - const void *data, - size_t data_len, - unsigned char *res) -{ - size_t hlen = gcry_md_get_algo_dlen(GCRY_MD_SHA1); - gcry_md_hd_t mdh; - unsigned char *hash; - gpg_error_t err; - - err = gcry_md_open(&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); - if (err != GPG_ERR_NO_ERROR) - return EINA_FALSE; - - err = gcry_md_setkey(mdh, key, key_len); - if (err != GPG_ERR_NO_ERROR) - { - gcry_md_close(mdh); - return EINA_FALSE; - } - - gcry_md_write(mdh, data, data_len); - - hash = gcry_md_read(mdh, GCRY_MD_SHA1); - if (!hash) - { - gcry_md_close(mdh); - return EINA_FALSE; - } - - memcpy(res, hash, hlen); - - gcry_md_close(mdh); - - return EINA_TRUE; -} -# endif /* ifdef HAVE_GNUTLS */ - -static Eina_Bool -emile_pbkdf2_sha1(const char *key, - int key_len, - const unsigned char *salt, - unsigned int salt_len, - int iter, - unsigned char *res, - int res_len) -{ - unsigned char digest[20]; - unsigned char tab[4]; - unsigned char *p = res; - unsigned char *buf; - unsigned long i; - int digest_len = 20; - int len = res_len; - int tmp_len; - int j, k; -# ifdef HAVE_GNUTLS -# else - HMAC_CTX hctx; -# endif /* ifdef HAVE_GNUTLS */ - - buf = alloca(salt_len + 4); - if (!buf) return EINA_FALSE; - - for (i = 1; len; len -= tmp_len, p += tmp_len, i++) - { - if (len > digest_len) - tmp_len = digest_len; - else - tmp_len = 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; - -# ifdef HAVE_GNUTLS - memcpy(buf, salt, salt_len); - memcpy(buf + salt_len, tab, 4); - if (!emile_hmac_sha1(key, key_len, buf, salt_len + 4, digest)) - return EINA_FALSE; -# else /* ifdef HAVE_GNUTLS */ - HMAC_Init(&hctx, key, key_len, EVP_sha1()); - HMAC_Update(&hctx, salt, salt_len); - HMAC_Update(&hctx, tab, 4); - HMAC_Final(&hctx, digest, NULL); -# endif /* ifdef HAVE_GNUTLS */ - memcpy(p, digest, tmp_len); - - for (j = 1; j < iter; j++) - { -# ifdef HAVE_GNUTLS - if (!emile_hmac_sha1(key, key_len, digest, 20, digest)) - return EINA_FALSE; -# else /* ifdef HAVE_GNUTLS */ - HMAC(EVP_sha1(), key, key_len, digest, 20, digest, NULL); -# endif /* ifdef HAVE_GNUTLS */ - for (k = 0; k < tmp_len; k++) - p[k] ^= digest[k]; - } -# ifdef HAVE_GNUTLS -# else - HMAC_cleanup(&hctx); -# endif /* ifdef HAVE_GNUTLS */ - } - - return EINA_TRUE; -} - EAPI Eina_Binbuf * -emile_binbuf_cipher(const Eina_Binbuf *data, - const char *key, - unsigned int length) +emile_binbuf_cipher(const Eina_Binbuf *data EINA_UNUSED, + const char *key EINA_UNUSED, + unsigned int length EINA_UNUSED) { -#ifdef HAVE_CIPHER - /* Cipher declarations */ - Eina_Binbuf *result; - unsigned char *pointer; - unsigned char iv[MAX_IV_LEN]; - unsigned char ik[MAX_KEY_LEN]; - unsigned char key_material[MAX_IV_LEN + MAX_KEY_LEN]; - unsigned int salt; - unsigned int tmp = 0; - unsigned int crypted_length; - int opened = 0; -# ifdef HAVE_GNUTLS - /* Gcrypt declarations */ - gcry_error_t err = 0; - gcry_cipher_hd_t cipher; -# else /* ifdef HAVE_GNUTLS */ - /* Openssl declarations*/ - EVP_CIPHER_CTX ctx; - unsigned int *buffer = NULL; - int tmp_len; -# endif /* ifdef HAVE_GNUTLS */ - - if (!emile_cipher_init()) return NULL; - -# ifdef HAVE_GNUTLS - /* Gcrypt salt generation */ - gcry_create_nonce((unsigned char *)&salt, sizeof(salt)); -# else /* ifdef HAVE_GNUTLS */ - /* Openssl salt generation */ - if (!RAND_bytes((unsigned char *)&salt, sizeof (unsigned int))) - return NULL; - -# endif /* ifdef HAVE_GNUTLS */ - - result = eina_binbuf_new(); - if (!result) return NULL; - - emile_pbkdf2_sha1(key, - length, - (unsigned char *)&salt, - sizeof(unsigned int), - 2048, - key_material, - MAX_KEY_LEN + MAX_IV_LEN); - - memcpy(iv, key_material, MAX_IV_LEN); - memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); - - memset(key_material, 0, sizeof (key_material)); - - crypted_length = ((((eina_binbuf_length_get(data) + sizeof (unsigned int)) >> 5) + 1) << 5) - + sizeof (unsigned int); - - eina_binbuf_append_length(result, (unsigned char*) &salt, sizeof (salt)); - memset(&salt, 0, sizeof (salt)); - - tmp = htonl(eina_binbuf_length_get(data)); -# ifdef HAVE_GNUTLS - eina_binbuf_append_length(result, (unsigned char*) &tmp, sizeof (tmp)); - eina_binbuf_append_buffer(result, data); - - while (eina_binbuf_length_get(result) < crypted_length) - { - int r; - - r = rand(); - eina_binbuf_append_length(result, (unsigned char*) &r, sizeof (r)); - } - eina_binbuf_remove(result, crypted_length, eina_binbuf_length_get(result)); - - /* Gcrypt create the corresponding cipher - AES with a 256 bit key, Cipher Block Chaining mode */ - err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0); - if (err) goto on_error; - - opened = 1; - err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN); - if (err) goto on_error; - - err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN); - if (err) goto on_error; - - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - - pointer = (unsigned char*) eina_binbuf_string_get(result); - - /* Gcrypt encrypt */ - err = gcry_cipher_encrypt(cipher, pointer + sizeof (int), - eina_binbuf_length_get(result) - sizeof (int), - NULL, 0); - if (err) goto on_error; - - /* Gcrypt close the cipher */ - gcry_cipher_close(cipher); -# else /* ifdef HAVE_GNUTLS */ - buffer = malloc(crypted_length - sizeof (int)); - if (!buffer) goto on_error; - *buffer = tmp; - - eina_binbuf_append_length(result, - (unsigned char *) buffer, - crypted_length - sizeof (int)); - memcpy(buffer + 1, - eina_binbuf_string_get(data), - eina_binbuf_length_get(data)); - - /* Openssl create the corresponding cipher - AES with a 256 bit key, Cipher Block Chaining mode */ - EVP_CIPHER_CTX_init(&ctx); - if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv)) - goto on_error; - - opened = 1; - - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - - pointer = (unsigned char*) eina_binbuf_string_get(result); - - /* Openssl encrypt */ - if (!EVP_EncryptUpdate(&ctx, pointer + sizeof (int), &tmp_len, - (unsigned char *)buffer, - eina_binbuf_length_get(data) + sizeof(unsigned int))) - goto on_error; - - /* Openssl close the cipher */ - if (!EVP_EncryptFinal_ex(&ctx, pointer + sizeof (int) + tmp_len, - &tmp_len)) - goto on_error; - - EVP_CIPHER_CTX_cleanup(&ctx); - free(buffer); -# endif /* ifdef HAVE_GNUTLS */ - - return result; - -on_error: - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - -# ifdef HAVE_GNUTLS - /* Gcrypt error */ - if (opened) - gcry_cipher_close(cipher); - -# else /* ifdef HAVE_GNUTLS */ - /* Openssl error */ - if (opened) - EVP_CIPHER_CTX_cleanup(&ctx); - - free(buffer); - -# endif /* ifdef HAVE_GNUTLS */ - /* General error */ - eina_binbuf_free(result); - - return NULL; -#else /* ifdef HAVE_CIPHER */ - /* Cipher not supported */ - (void)data; - (void)size; - (void)key; - (void)length; - (void)result; - (void)result_length; return NULL; -#endif /* ifdef HAVE_CIPHER */ } EAPI Eina_Binbuf * -emile_binbuf_decipher(const Eina_Binbuf *data, - const char *key, - unsigned int length) +emile_binbuf_decipher(const Eina_Binbuf *data EINA_UNUSED, + const char *key EINA_UNUSED, + unsigned int length EINA_UNUSED) { -#ifdef HAVE_CIPHER - Eina_Binbuf *result = NULL; - unsigned int *over; - unsigned char ik[MAX_KEY_LEN]; - unsigned char iv[MAX_IV_LEN]; - unsigned char key_material[MAX_KEY_LEN + MAX_IV_LEN]; - unsigned int salt; - unsigned int size; - int tmp_len; - int tmp = 0; - int opened = 0; - - if (!emile_cipher_init()) return NULL; - - over = (unsigned int*) eina_binbuf_string_get(data); - size = eina_binbuf_length_get(data); - - /* At least the salt and an AES block */ - if (size < sizeof(unsigned int) + 16) - return NULL; - - /* Get the salt */ - salt = *over; - - /* Generate the iv and the key with the salt */ - emile_pbkdf2_sha1(key, length, (unsigned char *)&salt, - sizeof(unsigned int), 2048, key_material, - MAX_KEY_LEN + MAX_IV_LEN); - - memcpy(iv, key_material, MAX_IV_LEN); - memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); - - memset(key_material, 0, sizeof (key_material)); - memset(&salt, 0, sizeof (salt)); - - /* Align to AES block size if size is not align */ - tmp_len = size - sizeof (unsigned int); - if ((tmp_len & 0x1F) != 0) goto on_error; - - result = eina_binbuf_new(); - if (!result) goto on_error; - - eina_binbuf_append_length(result, (unsigned char*) (over + 1), tmp_len); - -# ifdef HAVE_GNUTLS - gcry_error_t err = 0; - gcry_cipher_hd_t cipher; - - /* Gcrypt create the corresponding cipher */ - err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0); - if (err) goto on_error; - - err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN); - if (err) goto on_error; - - err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN); - if (err) goto on_error; - - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - - /* Gcrypt decrypt */ - err = gcry_cipher_decrypt(cipher, - (void*) eina_binbuf_string_get(result), tmp_len, - (void*) (over + 1), tmp_len); - if (err) goto on_error; - - /* Gcrypt close the cipher */ - gcry_cipher_close(cipher); - -# else /* ifdef HAVE_GNUTLS */ - EVP_CIPHER_CTX ctx; - - /* Openssl create the corresponding cipher */ - EVP_CIPHER_CTX_init(&ctx); - opened = 1; - - if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv)) - goto on_error; - - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - - /* Openssl decrypt */ - if (!EVP_DecryptUpdate(&ctx, - (void*) eina_binbuf_string_get(result), &tmp, - (void*) (over + 1), tmp_len)) - goto on_error; - - /* Openssl close the cipher*/ - EVP_CIPHER_CTX_cleanup(&ctx); -# endif /* ifdef HAVE_GNUTLS */ - /* Get the decrypted data size */ - tmp = *(unsigned int*)(eina_binbuf_string_get(result)); - tmp = ntohl(tmp); - if (tmp > tmp_len || tmp <= 0) - goto on_error; - - /* Remove header and padding */ - eina_binbuf_remove(result, 0, sizeof (unsigned int)); - eina_binbuf_remove(result, tmp, eina_binbuf_length_get(result)); - - return result; - -on_error: - memset(iv, 0, sizeof (iv)); - memset(ik, 0, sizeof (ik)); - -# ifdef HAVE_GNUTLS - (void)opened; -# else - if (opened) - EVP_CIPHER_CTX_cleanup(&ctx); - -# endif /* ifdef HAVE_GNUTLS */ - eina_binbuf_free(result); - - return NULL; -#else /* ifdef HAVE_CIPHER */ - (void)data; - (void)size; - (void)key; - (void)length; - (void)result; - (void)result_length; return NULL; -#endif /* ifdef HAVE_CIPHER */ } diff --git a/src/lib/emile/emile_cipher_gnutls.c b/src/lib/emile/emile_cipher_gnutls.c new file mode 100644 index 0000000000..8cfcc6366f --- /dev/null +++ b/src/lib/emile/emile_cipher_gnutls.c @@ -0,0 +1,310 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* ifdef HAVE_CONFIG_H */ + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_GNUTLS +# include <gnutls/abstract.h> +# include <gnutls/x509.h> +# include <gcrypt.h> +#endif /* ifdef HAVE_CIPHER */ + +#include <Eina.h> + +#include "Emile.h" + +#include "emile_private.h" + +#define MAX_KEY_LEN 32 +#define MAX_IV_LEN 16 + +# ifdef HAVE_GNUTLS +static inline Eina_Bool +emile_hmac_sha1(const void *key, + size_t key_len, + const void *data, + size_t data_len, + unsigned char *res) +{ + size_t hlen = gcry_md_get_algo_dlen(GCRY_MD_SHA1); + gcry_md_hd_t mdh; + unsigned char *hash; + gpg_error_t err; + + err = gcry_md_open(&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + if (err != GPG_ERR_NO_ERROR) + return EINA_FALSE; + + err = gcry_md_setkey(mdh, key, key_len); + if (err != GPG_ERR_NO_ERROR) + { + gcry_md_close(mdh); + return EINA_FALSE; + } + + gcry_md_write(mdh, data, data_len); + + hash = gcry_md_read(mdh, GCRY_MD_SHA1); + if (!hash) + { + gcry_md_close(mdh); + return EINA_FALSE; + } + + memcpy(res, hash, hlen); + + gcry_md_close(mdh); + + return EINA_TRUE; +} +# endif /* ifdef HAVE_GNUTLS */ + + +static Eina_Bool +emile_pbkdf2_sha1(const char *key, + int key_len, + const unsigned char *salt, + unsigned int salt_len, + int iter, + unsigned char *res, + int res_len) +{ + unsigned char digest[20]; + unsigned char tab[4]; + unsigned char *p = res; + unsigned char *buf; + unsigned long i; + int digest_len = 20; + int len = res_len; + int tmp_len; + int j, k; + + buf = alloca(salt_len + 4); + if (!buf) return EINA_FALSE; + + for (i = 1; len; len -= tmp_len, p += tmp_len, i++) + { + if (len > digest_len) + tmp_len = digest_len; + else + tmp_len = 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_hmac_sha1(key, key_len, buf, salt_len + 4, digest)) + return EINA_FALSE; + memcpy(p, digest, tmp_len); + + for (j = 1; j < iter; j++) + { + if (!emile_hmac_sha1(key, key_len, digest, 20, digest)) + return EINA_FALSE; + for (k = 0; k < tmp_len; k++) + p[k] ^= digest[k]; + } + } + + return EINA_TRUE; +} + + +EAPI Eina_Binbuf * +emile_binbuf_cipher(const Eina_Binbuf *data, + const char *key, + unsigned int length) +{ + /* Cipher declarations */ + Eina_Binbuf *result; + unsigned char *pointer; + unsigned char iv[MAX_IV_LEN]; + unsigned char ik[MAX_KEY_LEN]; + unsigned char key_material[MAX_IV_LEN + MAX_KEY_LEN]; + unsigned int salt; + unsigned int tmp = 0; + unsigned int crypted_length; + int opened = 0; + /* Gcrypt declarations */ + gcry_error_t err = 0; + gcry_cipher_hd_t cipher; + + if (!emile_cipher_init()) return NULL; + + /* Gcrypt salt generation */ + gcry_create_nonce((unsigned char *)&salt, sizeof(salt)); + + result = eina_binbuf_new(); + if (!result) return NULL; + + emile_pbkdf2_sha1(key, + length, + (unsigned char *)&salt, + sizeof(unsigned int), + 2048, + key_material, + MAX_KEY_LEN + MAX_IV_LEN); + + memcpy(iv, key_material, MAX_IV_LEN); + memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); + + memset(key_material, 0, sizeof (key_material)); + + crypted_length = ((((eina_binbuf_length_get(data) + sizeof (unsigned int)) >> 5) + 1) << 5) + + sizeof (unsigned int); + + eina_binbuf_append_length(result, (unsigned char*) &salt, sizeof (salt)); + memset(&salt, 0, sizeof (salt)); + + tmp = htonl(eina_binbuf_length_get(data)); + eina_binbuf_append_length(result, (unsigned char*) &tmp, sizeof (tmp)); + eina_binbuf_append_buffer(result, data); + + while (eina_binbuf_length_get(result) < crypted_length) + { + int r; + + r = rand(); + eina_binbuf_append_length(result, (unsigned char*) &r, sizeof (r)); + } + eina_binbuf_remove(result, crypted_length, eina_binbuf_length_get(result)); + + /* Gcrypt create the corresponding cipher + AES with a 256 bit key, Cipher Block Chaining mode */ + err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0); + if (err) goto on_error; + + opened = 1; + err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN); + if (err) goto on_error; + + err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN); + if (err) goto on_error; + + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + pointer = (unsigned char*) eina_binbuf_string_get(result); + + /* Gcrypt encrypt */ + err = gcry_cipher_encrypt(cipher, pointer + sizeof (int), + eina_binbuf_length_get(result) - sizeof (int), + NULL, 0); + if (err) goto on_error; + + /* Gcrypt close the cipher */ + gcry_cipher_close(cipher); + + return result; + +on_error: + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + /* Gcrypt error */ + if (opened) + gcry_cipher_close(cipher); + + /* General error */ + eina_binbuf_free(result); + + return NULL; +} + +EAPI Eina_Binbuf * +emile_binbuf_decipher(const Eina_Binbuf *data, + const char *key, + unsigned int length) +{ + Eina_Binbuf *result = NULL; + unsigned int *over; + gcry_error_t err = 0; + gcry_cipher_hd_t cipher; + unsigned char ik[MAX_KEY_LEN]; + unsigned char iv[MAX_IV_LEN]; + unsigned char key_material[MAX_KEY_LEN + MAX_IV_LEN]; + unsigned int salt; + unsigned int size; + int tmp_len; + int tmp = 0; + + if (!emile_cipher_init()) return NULL; + + over = (unsigned int*) eina_binbuf_string_get(data); + size = eina_binbuf_length_get(data); + + /* At least the salt and an AES block */ + if (size < sizeof(unsigned int) + 16) + return NULL; + + /* Get the salt */ + salt = *over; + + /* Generate the iv and the key with the salt */ + emile_pbkdf2_sha1(key, length, (unsigned char *)&salt, + sizeof(unsigned int), 2048, key_material, + MAX_KEY_LEN + MAX_IV_LEN); + + memcpy(iv, key_material, MAX_IV_LEN); + memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); + + memset(key_material, 0, sizeof (key_material)); + memset(&salt, 0, sizeof (salt)); + + /* Align to AES block size if size is not align */ + tmp_len = size - sizeof (unsigned int); + if ((tmp_len & 0x1F) != 0) goto on_error; + + result = eina_binbuf_new(); + if (!result) goto on_error; + + eina_binbuf_append_length(result, (unsigned char*) (over + 1), tmp_len); + + /* Gcrypt create the corresponding cipher */ + err = gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0); + if (err) goto on_error; + + err = gcry_cipher_setiv(cipher, iv, MAX_IV_LEN); + if (err) goto on_error; + + err = gcry_cipher_setkey(cipher, ik, MAX_KEY_LEN); + if (err) goto on_error; + + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + /* Gcrypt decrypt */ + err = gcry_cipher_decrypt(cipher, + (void*) eina_binbuf_string_get(result), tmp_len, + (void*) (over + 1), tmp_len); + if (err) goto on_error; + + /* Gcrypt close the cipher */ + gcry_cipher_close(cipher); + + /* Get the decrypted data size */ + tmp = *(unsigned int*)(eina_binbuf_string_get(result)); + tmp = ntohl(tmp); + if (tmp > tmp_len || tmp <= 0) + goto on_error; + + /* Remove header and padding */ + eina_binbuf_remove(result, 0, sizeof (unsigned int)); + eina_binbuf_remove(result, tmp, eina_binbuf_length_get(result)); + + return result; + +on_error: + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + eina_binbuf_free(result); + + return NULL; +} diff --git a/src/lib/emile/emile_cipher_openssl.c b/src/lib/emile/emile_cipher_openssl.c new file mode 100644 index 0000000000..630cf127d1 --- /dev/null +++ b/src/lib/emile/emile_cipher_openssl.c @@ -0,0 +1,274 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* ifdef HAVE_CONFIG_H */ + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_OPENSSL +# include <openssl/sha.h> +# include <openssl/evp.h> +# include <openssl/hmac.h> +# include <openssl/rand.h> +#endif /* ifdef HAVE_GNUTLS */ + +#include <Eina.h> + +#include "Emile.h" + +#include "emile_private.h" + +#define MAX_KEY_LEN EVP_MAX_KEY_LENGTH +#define MAX_IV_LEN EVP_MAX_IV_LENGTH + +static Eina_Bool +emile_pbkdf2_sha1(const char *key, + int key_len, + const unsigned char *salt, + unsigned int salt_len, + int iter, + unsigned char *res, + int res_len) +{ + unsigned char digest[20]; + unsigned char tab[4]; + unsigned char *p = res; + unsigned char *buf; + unsigned long i; + int digest_len = 20; + int len = res_len; + int tmp_len; + int j, k; + HMAC_CTX hctx; + + buf = alloca(salt_len + 4); + if (!buf) return EINA_FALSE; + + for (i = 1; len; len -= tmp_len, p += tmp_len, i++) + { + if (len > digest_len) + tmp_len = digest_len; + else + tmp_len = 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; + + HMAC_Init(&hctx, key, key_len, EVP_sha1()); + HMAC_Update(&hctx, salt, salt_len); + HMAC_Update(&hctx, tab, 4); + HMAC_Final(&hctx, digest, NULL); + memcpy(p, digest, tmp_len); + + for (j = 1; j < iter; j++) + { + HMAC(EVP_sha1(), key, key_len, digest, 20, digest, NULL); + for (k = 0; k < tmp_len; k++) + p[k] ^= digest[k]; + } + HMAC_cleanup(&hctx); + } + + return EINA_TRUE; +} + +EAPI Eina_Binbuf * +emile_binbuf_cipher(const Eina_Binbuf *data, + const char *key, + unsigned int length) +{ + /* Cipher declarations */ + Eina_Binbuf *result; + unsigned char *pointer; + unsigned char iv[MAX_IV_LEN]; + unsigned char ik[MAX_KEY_LEN]; + unsigned char key_material[MAX_IV_LEN + MAX_KEY_LEN]; + unsigned int salt; + unsigned int tmp = 0; + unsigned int crypted_length; + int opened = 0; + /* Openssl declarations*/ + EVP_CIPHER_CTX ctx; + unsigned int *buffer = NULL; + int tmp_len; + + if (!emile_cipher_init()) return NULL; + + /* Openssl salt generation */ + if (!RAND_bytes((unsigned char *)&salt, sizeof (unsigned int))) + return NULL; + + result = eina_binbuf_new(); + if (!result) return NULL; + + emile_pbkdf2_sha1(key, + length, + (unsigned char *)&salt, + sizeof(unsigned int), + 2048, + key_material, + MAX_KEY_LEN + MAX_IV_LEN); + + memcpy(iv, key_material, MAX_IV_LEN); + memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); + + memset(key_material, 0, sizeof (key_material)); + + crypted_length = ((((eina_binbuf_length_get(data) + sizeof (unsigned int)) >> 5) + 1) << 5) + + sizeof (unsigned int); + + eina_binbuf_append_length(result, (unsigned char*) &salt, sizeof (salt)); + memset(&salt, 0, sizeof (salt)); + + tmp = htonl(eina_binbuf_length_get(data)); + buffer = malloc(crypted_length - sizeof (int)); + if (!buffer) goto on_error; + *buffer = tmp; + + eina_binbuf_append_length(result, + (unsigned char *) buffer, + crypted_length - sizeof (int)); + memcpy(buffer + 1, + eina_binbuf_string_get(data), + eina_binbuf_length_get(data)); + + /* Openssl create the corresponding cipher + AES with a 256 bit key, Cipher Block Chaining mode */ + EVP_CIPHER_CTX_init(&ctx); + if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv)) + goto on_error; + + opened = 1; + + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + pointer = (unsigned char*) eina_binbuf_string_get(result); + + /* Openssl encrypt */ + if (!EVP_EncryptUpdate(&ctx, pointer + sizeof (int), &tmp_len, + (unsigned char *)buffer, + eina_binbuf_length_get(data) + sizeof(unsigned int))) + goto on_error; + + /* Openssl close the cipher */ + if (!EVP_EncryptFinal_ex(&ctx, pointer + sizeof (int) + tmp_len, + &tmp_len)) + goto on_error; + + EVP_CIPHER_CTX_cleanup(&ctx); + free(buffer); + + return result; + +on_error: + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + /* Openssl error */ + if (opened) + EVP_CIPHER_CTX_cleanup(&ctx); + + free(buffer); + + /* General error */ + eina_binbuf_free(result); + + return NULL; +} + + +EAPI Eina_Binbuf * +emile_binbuf_decipher(const Eina_Binbuf *data, + const char *key, + unsigned int length) +{ + Eina_Binbuf *result = NULL; + unsigned int *over; + EVP_CIPHER_CTX ctx; + unsigned char ik[MAX_KEY_LEN]; + unsigned char iv[MAX_IV_LEN]; + unsigned char key_material[MAX_KEY_LEN + MAX_IV_LEN]; + unsigned int salt; + unsigned int size; + int tmp_len; + int tmp = 0; + int opened = 0; + + if (!emile_cipher_init()) return NULL; + + over = (unsigned int*) eina_binbuf_string_get(data); + size = eina_binbuf_length_get(data); + + /* At least the salt and an AES block */ + if (size < sizeof(unsigned int) + 16) + return NULL; + + /* Get the salt */ + salt = *over; + + /* Generate the iv and the key with the salt */ + emile_pbkdf2_sha1(key, length, (unsigned char *)&salt, + sizeof(unsigned int), 2048, key_material, + MAX_KEY_LEN + MAX_IV_LEN); + + memcpy(iv, key_material, MAX_IV_LEN); + memcpy(ik, key_material + MAX_IV_LEN, MAX_KEY_LEN); + + memset(key_material, 0, sizeof (key_material)); + memset(&salt, 0, sizeof (salt)); + + /* Align to AES block size if size is not align */ + tmp_len = size - sizeof (unsigned int); + if ((tmp_len & 0x1F) != 0) goto on_error; + + result = eina_binbuf_new(); + if (!result) goto on_error; + + eina_binbuf_append_length(result, (unsigned char*) (over + 1), tmp_len); + + /* Openssl create the corresponding cipher */ + EVP_CIPHER_CTX_init(&ctx); + opened = 1; + + if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, ik, iv)) + goto on_error; + + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + /* Openssl decrypt */ + if (!EVP_DecryptUpdate(&ctx, + (void*) eina_binbuf_string_get(result), &tmp, + (void*) (over + 1), tmp_len)) + goto on_error; + + /* Openssl close the cipher*/ + EVP_CIPHER_CTX_cleanup(&ctx); + + /* Get the decrypted data size */ + tmp = *(unsigned int*)(eina_binbuf_string_get(result)); + tmp = ntohl(tmp); + if (tmp > tmp_len || tmp <= 0) + goto on_error; + + /* Remove header and padding */ + eina_binbuf_remove(result, 0, sizeof (unsigned int)); + eina_binbuf_remove(result, tmp, eina_binbuf_length_get(result)); + + return result; + +on_error: + memset(iv, 0, sizeof (iv)); + memset(ik, 0, sizeof (ik)); + + if (opened) + EVP_CIPHER_CTX_cleanup(&ctx); + + eina_binbuf_free(result); + + return NULL; +} |