]> source.dussan.org Git - rspamd.git/commitdiff
Add openssl aes-256-gcm encryption to libcryptobox
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 18 Oct 2015 22:20:18 +0000 (23:20 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 18 Oct 2015 22:20:18 +0000 (23:20 +0100)
src/libcryptobox/cryptobox.c

index fc2caacfaac8e814643097d53d9aed6ecde991c7..dc4f3e5e955432ab03800a5ac3af7f0860c407f1 100644 (file)
 #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
 }