From b7efc8479526b5f1f10e1df9659f393adfac08c7 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 18 Oct 2015 23:20:18 +0100 Subject: [PATCH] Add openssl aes-256-gcm encryption to libcryptobox --- src/libcryptobox/cryptobox.c | 354 +++++++++++++++++++++++++++++------ 1 file changed, 298 insertions(+), 56 deletions(-) diff --git a/src/libcryptobox/cryptobox.c b/src/libcryptobox/cryptobox.c index fc2caacfa..dc4f3e5e9 100644 --- a/src/libcryptobox/cryptobox.c +++ b/src/libcryptobox/cryptobox.c @@ -40,6 +40,11 @@ #include #endif #ifdef HAVE_OPENSSL +#include +/* Openssl >= 1.0.1d is required for GCM verification */ +#if OPENSSL_VERSION_NUMBER >= 0x1000104fL +#define HAVE_USABLE_OPENSSL 1 +#endif #include #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 } -- 2.39.5