Browse Source

Add openssl aes-256-gcm encryption to libcryptobox

tags/1.0.7
Vsevolod Stakhov 8 years ago
parent
commit
b7efc84795
1 changed files with 298 additions and 56 deletions
  1. 298
    56
      src/libcryptobox/cryptobox.c

+ 298
- 56
src/libcryptobox/cryptobox.c View File

@@ -40,6 +40,11 @@
#include <cpuid.h>
#endif
#ifdef HAVE_OPENSSL
#include <openssl/opensslv.h>
/* Openssl >= 1.0.1d is required for GCM verification */
#if OPENSSL_VERSION_NUMBER >= 0x1000104fL
#define HAVE_USABLE_OPENSSL 1
#endif
#include <openssl/evp.h>
#endif

@@ -256,154 +261,387 @@ rspamd_cryptobox_nm (rspamd_nm_t nm, const rspamd_pk_t pk, const rspamd_sk_t sk)
static gsize
rspamd_cryptobox_encrypt_ctx_len (void)
{
return sizeof (chacha_state) + CRYPTOBOX_ALIGNMENT;
if (G_LIKELY (!use_openssl)) {
return sizeof (chacha_state) + CRYPTOBOX_ALIGNMENT;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
return sizeof (EVP_CIPHER_CTX) + CRYPTOBOX_ALIGNMENT;
#endif
}

return 0;
}

static gsize
rspamd_cryptobox_auth_ctx_len (void)
{
return sizeof (poly1305_state) + CRYPTOBOX_ALIGNMENT;
if (G_LIKELY (!use_openssl)) {
return sizeof (poly1305_state) + CRYPTOBOX_ALIGNMENT;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
return sizeof (void *);
#endif
}

return 0;
}

static void *
rspamd_cryptobox_encrypt_init (void *enc_ctx, const rspamd_nonce_t nonce,
const rspamd_nm_t nm)
{
chacha_state *s;
if (G_LIKELY (!use_openssl)) {
chacha_state *s;

s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
xchacha_init (s,
(const chacha_key *) nm,
(const chacha_iv24 *) nonce,
20);

return s;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s;

s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
xchacha_init (s, (const chacha_key *) nm, (const chacha_iv24 *) nonce, 20);
s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
g_assert (EVP_EncryptInit_ex (s, EVP_aes_256_gcm (), NULL, NULL, NULL) == 1);
g_assert (EVP_CIPHER_CTX_ctrl (s, EVP_CTRL_GCM_SET_IVLEN, 24, NULL) == 1);
g_assert (EVP_EncryptInit_ex (s, NULL, NULL, nm, nonce) == 1);

return s;
return s;
#endif
}

return NULL;
}

static void *
rspamd_cryptobox_auth_init (void *auth_ctx, void *enc_ctx)
{
poly1305_state *mac_ctx;
guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
if (G_LIKELY (!use_openssl)) {
poly1305_state *mac_ctx;
guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];

mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
memset (subkey, 0, sizeof (subkey));
chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
poly1305_init (mac_ctx, (const poly1305_key *) subkey);
rspamd_explicit_memzero (subkey, sizeof (subkey));

return mac_ctx;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
auth_ctx = enc_ctx;

mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
memset (subkey, 0, sizeof (subkey));
chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
poly1305_init (mac_ctx, (const poly1305_key *) subkey);
rspamd_explicit_memzero (subkey, sizeof (subkey));
return auth_ctx;
#endif
}

return mac_ctx;
return NULL;
}

static gboolean
rspamd_cryptobox_encrypt_update (void *enc_ctx, const guchar *in, gsize inlen,
guchar *out, gsize *outlen)
{
gsize r;
if (G_LIKELY (!use_openssl)) {
gsize r;

r = chacha_update (enc_ctx, in, out, inlen);

if (outlen != NULL) {
*outlen = r;
}

r = chacha_update (enc_ctx, in, out, inlen);
return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = enc_ctx;
gint r;

r = outlen ? *outlen : inlen;
g_assert (EVP_EncryptUpdate (s, out, &r, in, inlen) == 1);

if (outlen != NULL) {
*outlen = r;
if (outlen) {
*outlen = r;
}

return TRUE;
#endif
}

return TRUE;
return FALSE;
}

static gboolean
rspamd_cryptobox_auth_update (void *auth_ctx, const guchar *in, gsize inlen)
{
poly1305_update (auth_ctx, in, inlen);
if (G_LIKELY (!use_openssl)) {
poly1305_update (auth_ctx, in, inlen);

return TRUE;
return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
return TRUE;
#endif
}

return FALSE;
}

static gsize
rspamd_cryptobox_encrypt_final (void *enc_ctx, guchar *out)
rspamd_cryptobox_encrypt_final (void *enc_ctx, guchar *out, gsize remain)
{
return chacha_final (enc_ctx, out);
if (G_LIKELY (!use_openssl)) {
return chacha_final (enc_ctx, out);
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = enc_ctx;
gint r = remain;

g_assert (EVP_EncryptFinal_ex (s, out, &r) == 1);

return r;
#endif
}

return 0;
}

static gboolean
rspamd_cryptobox_auth_final (void *auth_ctx, rspamd_sig_t sig)
{
poly1305_finish (auth_ctx, sig);
if (G_LIKELY (!use_openssl)) {
poly1305_finish (auth_ctx, sig);

return TRUE;
return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = auth_ctx;

g_assert (EVP_CIPHER_CTX_ctrl (s, EVP_CTRL_GCM_GET_TAG,
sizeof (rspamd_sig_t), sig) == 1);

return TRUE;
#endif
}

return FALSE;
}

static void *
rspamd_cryptobox_decrypt_init (void *enc_ctx, const rspamd_nonce_t nonce,
const rspamd_nm_t nm)
{
chacha_state *s;
if (G_LIKELY (!use_openssl)) {

s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
xchacha_init (s, (const chacha_key *) nm, (const chacha_iv24 *) nonce, 20);
chacha_state *s;

return s;
s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
xchacha_init (s,
(const chacha_key *) nm,
(const chacha_iv24 *) nonce,
20);

return s;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s;

s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
g_assert (EVP_DecryptInit_ex(s, EVP_aes_256_gcm (), NULL, NULL, NULL) == 1);
g_assert (EVP_CIPHER_CTX_ctrl (s, EVP_CTRL_GCM_SET_IVLEN, 24, NULL) == 1);
g_assert (EVP_DecryptInit_ex (s, NULL, NULL, nm, nonce) == 1);

return s;
#endif
}

return NULL;
}

static void *
rspamd_cryptobox_auth_verify_init (void *auth_ctx, void *enc_ctx)
{
poly1305_state *mac_ctx;
guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
if (G_LIKELY (!use_openssl)) {
poly1305_state *mac_ctx;
guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];

mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
memset (subkey, 0, sizeof (subkey));
chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
poly1305_init (mac_ctx, (const poly1305_key *) subkey);
rspamd_explicit_memzero (subkey, sizeof (subkey));

mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
memset (subkey, 0, sizeof (subkey));
chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
poly1305_init (mac_ctx, (const poly1305_key *) subkey);
rspamd_explicit_memzero (subkey, sizeof (subkey));
return mac_ctx;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
auth_ctx = enc_ctx;

return auth_ctx;
#endif
}

return mac_ctx;
return NULL;
}

static gboolean
rspamd_cryptobox_decrypt_update (void *enc_ctx, const guchar *in, gsize inlen,
guchar *out, gsize *outlen)
{
gsize r;
if (G_LIKELY (!use_openssl)) {
gsize r;

r = chacha_update (enc_ctx, in, out, inlen);

r = chacha_update (enc_ctx, in, out, inlen);
if (outlen != NULL) {
*outlen = r;
}

if (outlen != NULL) {
*outlen = r;
return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = enc_ctx;
gint r;

return TRUE;
r = outlen ? *outlen : inlen;
g_assert (EVP_DecryptUpdate (s, out, &r, in, inlen) == 1);

if (outlen) {
*outlen = r;
}

return TRUE;
#endif
}
}

static gboolean
rspamd_cryptobox_auth_verify_update (void *auth_ctx, const guchar *in, gsize inlen)
{
poly1305_update (auth_ctx, in, inlen);
if (G_LIKELY (!use_openssl)) {
poly1305_update (auth_ctx, in, inlen);

return TRUE;
return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
/* We do not need to authenticate as a separate process */
return TRUE;
#else
#endif
}

return FALSE;
}

static gsize
rspamd_cryptobox_decrypt_final (void *enc_ctx, guchar *out)
static gboolean
rspamd_cryptobox_decrypt_final (void *enc_ctx, guchar *out, gsize remain)
{
return chacha_final (enc_ctx, out);
if (G_LIKELY (!use_openssl)) {
chacha_final (enc_ctx, out);

return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = enc_ctx;
gint r = remain;

if (EVP_DecryptFinal_ex (s, out, &r) < 0) {
return FALSE;
}

return TRUE;
#endif
}

return FALSE;
}

static gboolean
rspamd_cryptobox_auth_verify_final (void *auth_ctx, const rspamd_sig_t sig)
{
rspamd_sig_t mac;
if (G_LIKELY (!use_openssl)) {
rspamd_sig_t mac;

poly1305_finish (auth_ctx, mac);
poly1305_finish (auth_ctx, mac);

if (!poly1305_verify (mac, sig)) {
return FALSE;
if (!poly1305_verify (mac, sig)) {
return FALSE;
}

return TRUE;
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = auth_ctx;

return TRUE;
if (EVP_CIPHER_CTX_ctrl (s, EVP_CTRL_GCM_SET_TAG, 16, (guchar *)sig) != 1) {
return FALSE;
}

return TRUE;
#endif
}

return FALSE;
}


static void
rspamd_cryptobox_cleanup (void *enc_ctx, void *auth_ctx)
{
rspamd_explicit_memzero (auth_ctx, sizeof (poly1305_state));
if (G_LIKELY (!use_openssl)) {
rspamd_explicit_memzero (auth_ctx, sizeof (poly1305_state));
}
else {
#ifndef HAVE_USABLE_OPENSSL
g_assert (0);
#else
EVP_CIPHER_CTX *s = enc_ctx;

EVP_CIPHER_CTX_free (s);
#endif
}
}

void rspamd_cryptobox_encrypt_nm_inplace (guchar *data, gsize len,
@@ -421,7 +659,7 @@ void rspamd_cryptobox_encrypt_nm_inplace (guchar *data, gsize len,
auth_ctx = rspamd_cryptobox_auth_init (auth_ctx, enc_ctx);

rspamd_cryptobox_encrypt_update (enc_ctx, data, len, data, &r);
rspamd_cryptobox_encrypt_final (enc_ctx, data + r);
rspamd_cryptobox_encrypt_final (enc_ctx, data + r, len - r);

rspamd_cryptobox_auth_update (auth_ctx, data, len);
rspamd_cryptobox_auth_final (auth_ctx, sig);
@@ -538,7 +776,7 @@ rspamd_cryptobox_encryptv_nm_inplace (struct rspamd_cryptobox_segment *segments,
rspamd_cryptobox_encrypt_update (enc_ctx, outbuf, sizeof (outbuf) - remain,
outbuf, &r);
out = outbuf + r;
rspamd_cryptobox_encrypt_final (enc_ctx, out);
rspamd_cryptobox_encrypt_final (enc_ctx, out, sizeof (outbuf) - remain - r);

rspamd_cryptobox_auth_update (auth_ctx, outbuf, sizeof (outbuf) - remain);
rspamd_cryptobox_auth_final (auth_ctx, sig);
@@ -569,7 +807,7 @@ rspamd_cryptobox_decrypt_nm_inplace (guchar *data, gsize len,
}
else {
rspamd_cryptobox_decrypt_update (enc_ctx, data, len, data, &r);
rspamd_cryptobox_decrypt_final (enc_ctx, data + r);
ret = rspamd_cryptobox_decrypt_final (enc_ctx, data + r, len - r);
}

rspamd_cryptobox_cleanup (enc_ctx, auth_ctx);
@@ -688,5 +926,9 @@ rspamd_cryptobox_pbkdf (const char *pass, gsize pass_len,
void
rspamd_cryptobox_openssl_mode (gboolean enable)
{
#ifdef HAVE_USABLE_OPENSSL
use_openssl = enable;
#else
g_assert (0);
#endif
}

Loading…
Cancel
Save