commit 8f70f5e: [Feature] Lua_cryptobox: Add keyed ssl hash functions via HMAC

Vsevolod Stakhov vsevolod at highsecure.ru
Tue Aug 10 10:21:04 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-08-10 11:18:33 +0100
URL: https://github.com/rspamd/rspamd/commit/8f70f5e4b465ace44590ad233a223639e5a5e861 (HEAD -> master)

[Feature] Lua_cryptobox: Add keyed ssl hash functions via HMAC

---
 src/lua/lua_cryptobox.c | 184 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 155 insertions(+), 29 deletions(-)

diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
index 788f2e1df..f712fad0c 100644
--- a/src/lua/lua_cryptobox.c
+++ b/src/lua/lua_cryptobox.c
@@ -36,11 +36,13 @@
 #include "libutil/ref.h"
 
 #include <stdalign.h>
+#include <openssl/hmac.h>
 
 
 enum lua_cryptobox_hash_type {
 	LUA_CRYPTOBOX_HASH_BLAKE2 = 0,
 	LUA_CRYPTOBOX_HASH_SSL,
+	LUA_CRYPTOBOX_HASH_HMAC,
 	LUA_CRYPTOBOX_HASH_XXHASH64,
 	LUA_CRYPTOBOX_HASH_XXHASH32,
 	LUA_CRYPTOBOX_HASH_MUM,
@@ -51,6 +53,7 @@ struct rspamd_lua_cryptobox_hash {
 	union {
 		rspamd_cryptobox_hash_state_t *h;
 		EVP_MD_CTX *c;
+		HMAC_CTX *hmac_c;
 		rspamd_cryptobox_fast_hash_state_t *fh;
 	} content;
 
@@ -83,6 +86,7 @@ LUA_FUNCTION_DEF (cryptobox_signature, base64);
 LUA_FUNCTION_DEF (cryptobox_signature, bin);
 LUA_FUNCTION_DEF (cryptobox_hash, create);
 LUA_FUNCTION_DEF (cryptobox_hash, create_specific);
+LUA_FUNCTION_DEF (cryptobox_hash, create_specific_keyed);
 LUA_FUNCTION_DEF (cryptobox_hash, create_keyed);
 LUA_FUNCTION_DEF (cryptobox_hash, update);
 LUA_FUNCTION_DEF (cryptobox_hash, reset);
@@ -178,6 +182,7 @@ static const struct luaL_reg cryptoboxhashlib_f[] = {
 	LUA_INTERFACE_DEF (cryptobox_hash, create),
 	LUA_INTERFACE_DEF (cryptobox_hash, create_keyed),
 	LUA_INTERFACE_DEF (cryptobox_hash, create_specific),
+	LUA_INTERFACE_DEF (cryptobox_hash, create_specific_keyed),
 	{NULL, NULL}
 };
 
@@ -964,6 +969,9 @@ rspamd_lua_hash_update (struct rspamd_lua_cryptobox_hash *h,
 		case LUA_CRYPTOBOX_HASH_SSL:
 			EVP_DigestUpdate (h->content.c, p, len);
 			break;
+		case LUA_CRYPTOBOX_HASH_HMAC:
+			HMAC_Update (h->content.hmac_c, p, len);
+			break;
 		case LUA_CRYPTOBOX_HASH_XXHASH64:
 		case LUA_CRYPTOBOX_HASH_XXHASH32:
 		case LUA_CRYPTOBOX_HASH_MUM:
@@ -987,6 +995,14 @@ lua_cryptobox_hash_dtor (struct rspamd_lua_cryptobox_hash *h)
 #endif
 		EVP_MD_CTX_destroy (h->content.c);
 	}
+	else if (h->type == LUA_CRYPTOBOX_HASH_HMAC) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+		HMAC_CTX_cleanup (h->content.hmac_c);
+		g_free (h->content.hmac_c);
+#else
+		HMAC_CTX_free (h->content.hmac_c);
+#endif
+	}
 	else if (h->type == LUA_CRYPTOBOX_HASH_BLAKE2) {
 		rspamd_explicit_memzero (h->content.h, sizeof (*h->content.h));
 		free (h->content.h); /* Allocated by posix_memalign */
@@ -1013,6 +1029,50 @@ rspamd_lua_hash_init_default (struct rspamd_lua_cryptobox_hash *h,
 	h->out_len = rspamd_cryptobox_HASHBYTES;
 }
 
+static void
+rspamd_lua_ssl_hash_create (struct rspamd_lua_cryptobox_hash *h, const EVP_MD *htype,
+		bool insecure)
+{
+	h->type = LUA_CRYPTOBOX_HASH_SSL;
+	h->content.c = EVP_MD_CTX_create ();
+	h->out_len = EVP_MD_size (htype);
+
+	if (insecure) {
+		/* Should never ever be used for crypto/security purposes! */
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+		EVP_MD_CTX_set_flags(h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif
+	}
+
+	EVP_DigestInit_ex (h->content.c, htype, NULL);
+}
+
+static void
+rspamd_lua_ssl_hmac_create (struct rspamd_lua_cryptobox_hash *h, const EVP_MD *htype,
+							const gchar *key, gsize keylen,
+							bool insecure)
+{
+	h->type = LUA_CRYPTOBOX_HASH_HMAC;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+	h->content.hmac_c = g_malloc0 (sizeof(*h->content.hmac_c));
+#else
+	h->content.hmac_c = HMAC_CTX_new ();
+#endif
+	h->out_len = EVP_MD_size (htype);
+
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+	if (insecure) {
+		/* Should never ever be used for crypto/security purposes! */
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+		HMAC_CTX_set_flags(h->content.hmac_c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif
+	}
+#endif
+
+	HMAC_Init_ex (h->content.hmac_c, key, keylen, htype, NULL);
+}
+
 static struct rspamd_lua_cryptobox_hash *
 rspamd_lua_hash_create (const gchar *type, const gchar *key, gsize keylen)
 {
@@ -1023,43 +1083,45 @@ rspamd_lua_hash_create (const gchar *type, const gchar *key, gsize keylen)
 
 	if (type) {
 		if (g_ascii_strcasecmp (type, "md5") == 0) {
-			h->type = LUA_CRYPTOBOX_HASH_SSL;
-			h->content.c = EVP_MD_CTX_create ();
-			h->out_len = EVP_MD_size (EVP_md5 ());
-			/* Should never ever be used for crypto/security purposes! */
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
-			EVP_MD_CTX_set_flags (h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif
-			EVP_DigestInit_ex (h->content.c, EVP_md5 (), NULL);
+			if (keylen > 0) {
+				rspamd_lua_ssl_hmac_create(h, EVP_md5(), key, keylen, true);
+			}
+			else {
+				rspamd_lua_ssl_hash_create(h, EVP_md5(), true);
+			}
 		}
 		else if (g_ascii_strcasecmp (type, "sha1") == 0 ||
 					g_ascii_strcasecmp (type, "sha") == 0) {
-			h->type = LUA_CRYPTOBOX_HASH_SSL;
-			h->content.c = EVP_MD_CTX_create ();
-			h->out_len = EVP_MD_size (EVP_sha1 ());
-			/* Should never ever be used for crypto/security purposes! */
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
-			EVP_MD_CTX_set_flags (h->content.c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif
-			EVP_DigestInit_ex (h->content.c, EVP_sha1 (), NULL);
+			if (keylen > 0) {
+				rspamd_lua_ssl_hmac_create(h, EVP_sha1(), key, keylen, true);
+			}
+			else {
+				rspamd_lua_ssl_hash_create(h, EVP_sha1(), true);
+			}
 		}
 		else if (g_ascii_strcasecmp (type, "sha256") == 0) {
-			h->type = LUA_CRYPTOBOX_HASH_SSL;
-			h->content.c = EVP_MD_CTX_create ();
-			h->out_len = EVP_MD_size (EVP_sha256 ());
-			EVP_DigestInit (h->content.c, EVP_sha256 ());
+			if (keylen > 0) {
+				rspamd_lua_ssl_hmac_create(h, EVP_sha256(), key, keylen, true);
+			}
+			else {
+				rspamd_lua_ssl_hash_create(h, EVP_sha256(), true);
+			}
 		}
 		else if (g_ascii_strcasecmp (type, "sha512") == 0) {
-			h->type = LUA_CRYPTOBOX_HASH_SSL;
-			h->content.c = EVP_MD_CTX_create ();
-			h->out_len = EVP_MD_size (EVP_sha512 ());
-			EVP_DigestInit (h->content.c, EVP_sha512 ());
+			if (keylen > 0) {
+				rspamd_lua_ssl_hmac_create(h, EVP_sha512(), key, keylen, true);
+			}
+			else {
+				rspamd_lua_ssl_hash_create(h, EVP_sha512(), true);
+			}
 		}
 		else if (g_ascii_strcasecmp (type, "sha384") == 0) {
-			h->type = LUA_CRYPTOBOX_HASH_SSL;
-			h->content.c = EVP_MD_CTX_create ();
-			h->out_len = EVP_MD_size (EVP_sha384 ());
-			EVP_DigestInit (h->content.c, EVP_sha384 ());
+			if (keylen > 0) {
+				rspamd_lua_ssl_hmac_create(h, EVP_sha384(), key, keylen, true);
+			}
+			else {
+				rspamd_lua_ssl_hash_create(h, EVP_sha384(), true);
+			}
 		}
 		else if (g_ascii_strcasecmp (type, "xxh64") == 0) {
 			h->type = LUA_CRYPTOBOX_HASH_XXHASH64;
@@ -1235,7 +1297,57 @@ lua_cryptobox_hash_create_keyed (lua_State *L)
 		}
 
 		if (s) {
-			rspamd_cryptobox_hash_update (h->content.h, s, len);
+			rspamd_lua_hash_update (h, s, len);
+		}
+
+		ph = lua_newuserdata (L, sizeof (void *));
+		*ph = h;
+		rspamd_lua_setclass (L, "rspamd{cryptobox_hash}", -1);
+	}
+	else {
+		return luaL_error (L, "invalid arguments");
+	}
+
+	return 1;
+}
+
+/***
+ * @function rspamd_cryptobox_hash.create_specific_keyed(key, type, [string])
+ * Creates new hash context with specified key
+ * @param {string} key key
+ * @return {cryptobox_hash} hash object
+ */
+static gint
+lua_cryptobox_hash_create_specific_keyed (lua_State *L)
+{
+	LUA_TRACE_POINT;
+	struct rspamd_lua_cryptobox_hash *h, **ph;
+	const gchar *key, *s = NULL, *type = luaL_checkstring (L, 2);
+	struct rspamd_lua_text *t;
+	gsize len = 0;
+	gsize keylen;
+
+	key = luaL_checklstring (L, 1, &keylen);
+
+	if (key != NULL && type != NULL) {
+		h = rspamd_lua_hash_create (type, key, keylen);
+
+		if (lua_type (L, 3) == LUA_TSTRING) {
+			s = lua_tolstring (L, 3, &len);
+		}
+		else if (lua_type (L, 3) == LUA_TUSERDATA) {
+			t = lua_check_text (L, 3);
+
+			if (!t) {
+				return luaL_error (L, "invalid arguments");
+			}
+
+			s = t->start;
+			len = t->len;
+		}
+
+		if (s) {
+			rspamd_lua_hash_update (h, s, len);
 		}
 
 		ph = lua_newuserdata (L, sizeof (void *));
@@ -1327,6 +1439,14 @@ lua_cryptobox_hash_reset (lua_State *L)
 		case LUA_CRYPTOBOX_HASH_SSL:
 			EVP_DigestInit (h->content.c, EVP_MD_CTX_md (h->content.c));
 			break;
+		case LUA_CRYPTOBOX_HASH_HMAC:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+			/* Old openssl is awesome... */
+			HMAC_Init_ex (h->content.hmac_c, NULL, 0, h->content.hmac_c->md, NULL);
+#else
+			HMAC_CTX_reset (h->content.hmac_c);
+#endif
+			break;
 		case LUA_CRYPTOBOX_HASH_XXHASH64:
 			rspamd_cryptobox_fast_hash_init_specific (h->content.fh,
 					RSPAMD_CRYPTOBOX_XXHASH64, 0);
@@ -1378,6 +1498,12 @@ lua_cryptobox_hash_finish (struct rspamd_lua_cryptobox_hash *h)
 		g_assert (ssl_outlen <= sizeof (h->out));
 		memcpy (h->out, out, ssl_outlen);
 		break;
+	case LUA_CRYPTOBOX_HASH_HMAC:
+		HMAC_Final (h->content.hmac_c, out, &ssl_outlen);
+		h->out_len = ssl_outlen;
+		g_assert (ssl_outlen <= sizeof (h->out));
+		memcpy (h->out, out, ssl_outlen);
+		break;
 	case LUA_CRYPTOBOX_HASH_XXHASH64:
 	case LUA_CRYPTOBOX_HASH_XXHASH32:
 	case LUA_CRYPTOBOX_HASH_MUM:


More information about the Commits mailing list