forked from enlightenment/efl
emile: split OpenSSL, GNUTLS and no cipher into separate file as a first step toward module.
This commit is contained in:
parent
c3a1859e59
commit
10184ca860
|
@ -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)\" \
|
||||
|
|
|
@ -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)
|
||||
EAPI Eina_Binbuf *
|
||||
emile_binbuf_cipher(const Eina_Binbuf *data EINA_UNUSED,
|
||||
const char *key EINA_UNUSED,
|
||||
unsigned int length EINA_UNUSED)
|
||||
{
|
||||
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;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EAPI Eina_Binbuf *
|
||||
emile_binbuf_cipher(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
|
||||
/* 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)
|
||||
{
|
||||
#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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue