#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
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,
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);
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);
}
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);
void
rspamd_cryptobox_openssl_mode (gboolean enable)
{
+#ifdef HAVE_USABLE_OPENSSL
use_openssl = enable;
+#else
+ g_assert (0);
+#endif
}