1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /* Workaround for memset_s */
17 #ifdef __APPLE__
18 #define __STDC_WANT_LIB_EXT1__ 1
19 #include <string.h>
20 #endif
21 
22 #include "config.h"
23 #include "cryptobox.h"
24 #include "platform_config.h"
25 #include "chacha20/chacha.h"
26 #include "catena/catena.h"
27 #include "base64/base64.h"
28 #include "ottery.h"
29 #include "printf.h"
30 #include "xxhash.h"
31 #define MUM_TARGET_INDEPENDENT_HASH 1 /* For 32/64 bit equal hashes */
32 #include "../../contrib/mumhash/mum.h"
33 #include "../../contrib/t1ha/t1ha.h"
34 #ifdef HAVE_CPUID_H
35 #include <cpuid.h>
36 #endif
37 #ifdef HAVE_OPENSSL
38 #include <openssl/opensslv.h>
39 /* Openssl >= 1.0.1d is required for GCM verification */
40 #if OPENSSL_VERSION_NUMBER >= 0x1000104fL
41 #define HAVE_USABLE_OPENSSL 1
42 #endif
43 #endif
44 
45 #ifdef HAVE_USABLE_OPENSSL
46 #include <openssl/evp.h>
47 #include <openssl/ec.h>
48 #include <openssl/ecdh.h>
49 #include <openssl/ecdsa.h>
50 #include <openssl/rand.h>
51 #define CRYPTOBOX_CURVE_NID NID_X9_62_prime256v1
52 #endif
53 
54 #include <signal.h>
55 #include <setjmp.h>
56 #include <stdalign.h>
57 
58 #include <sodium.h>
59 
60 unsigned cpu_config = 0;
61 
62 static gboolean cryptobox_loaded = FALSE;
63 
64 static const guchar n0[16] = {0};
65 
66 #define CRYPTOBOX_ALIGNMENT   16
67 #define cryptobox_align_ptr(p, a)                                             \
68     (void *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
69 
70 static void
rspamd_cryptobox_cpuid(gint cpu[4],gint info)71 rspamd_cryptobox_cpuid (gint cpu[4], gint info)
72 {
73 	guint32 __attribute__ ((unused)) eax, __attribute__ ((unused)) ecx = 0, __attribute__ ((unused)) ebx = 0, __attribute__ ((unused)) edx = 0;
74 
75 	eax = info;
76 #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
77 # if defined( __i386__ ) && defined ( __PIC__ )
78 
79 	/* in case of PIC under 32-bit EBX cannot be clobbered */
80 
81 	__asm__ volatile ("movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi" : "=D" (ebx),
82 			"+a" (eax), "+c" (ecx), "=d" (edx));
83 # else
84 	__asm__ volatile ("cpuid" : "+b" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx));
85 # endif
86 
87 	cpu[0] = eax; cpu[1] = ebx; cpu[2] = ecx; cpu[3] = edx;
88 #else
89 	memset (cpu, 0, sizeof (gint) * 4);
90 #endif
91 }
92 
93 static sig_atomic_t ok = 0;
94 static jmp_buf j;
95 
96 __attribute__((noreturn))
97 static void
rspamd_cryptobox_ill_handler(int signo)98 rspamd_cryptobox_ill_handler (int signo)
99 {
100 	ok = 0;
101 	longjmp (j, -1);
102 }
103 
104 static gboolean
rspamd_cryptobox_test_instr(gint instr)105 rspamd_cryptobox_test_instr (gint instr)
106 {
107 	void (*old_handler) (int);
108 	guint32 rd;
109 
110 #if defined(__GNUC__)
111 	ok = 1;
112 	old_handler = signal (SIGILL, rspamd_cryptobox_ill_handler);
113 
114 	if (setjmp (j) != 0) {
115 		signal (SIGILL, old_handler);
116 
117 		return FALSE;
118 	}
119 
120 	switch (instr) {
121 #ifdef HAVE_SSE2
122 	case CPUID_SSE2:
123 		__asm__ volatile ("psubb %xmm0, %xmm0");
124 		break;
125 	case CPUID_RDRAND:
126 		/* Use byte code here for compatibility */
127 		__asm__ volatile (".byte 0x0f,0xc7,0xf0; setc %1"
128 			: "=a" (rd), "=qm" (ok)
129 			:
130 			: "edx"
131 		);
132 		break;
133 #endif
134 #ifdef HAVE_SSE3
135 	case CPUID_SSE3:
136 		__asm__ volatile ("movshdup %xmm0, %xmm0");
137 		break;
138 #endif
139 #ifdef HAVE_SSSE3
140 	case CPUID_SSSE3:
141 		__asm__ volatile ("pshufb %xmm0, %xmm0");
142 		break;
143 #endif
144 #ifdef HAVE_SSE41
145 	case CPUID_SSE41:
146 		__asm__ volatile ("pcmpeqq %xmm0, %xmm0");
147 		break;
148 #endif
149 #ifdef HAVE_SSE42
150 	case CPUID_SSE42:
151 		__asm__ volatile ("pushq %rax\n"
152 				"xorq %rax, %rax\n"
153 				"crc32 %rax, %rax\n"
154 				"popq %rax");
155 		break;
156 #endif
157 #ifdef HAVE_AVX
158 	case CPUID_AVX:
159 		__asm__ volatile ("vpaddq %xmm0, %xmm0, %xmm0");
160 		break;
161 #endif
162 #ifdef HAVE_AVX2
163 	case CPUID_AVX2:
164 		__asm__ volatile ("vpaddq %ymm0, %ymm0, %ymm0");\
165 		break;
166 #endif
167 	default:
168 		return FALSE;
169 		break;
170 	}
171 
172 	signal (SIGILL, old_handler);
173 #endif
174 
175 	(void)rd; /* Silence warning */
176 
177 	/* We actually never return here if SIGILL has been caught */
178 	return ok == 1;
179 }
180 
181 struct rspamd_cryptobox_library_ctx*
rspamd_cryptobox_init(void)182 rspamd_cryptobox_init (void)
183 {
184 	gint cpu[4], nid;
185 	const guint32 osxsave_mask = (1 << 27);
186 	const guint32 fma_movbe_osxsave_mask = ((1 << 12) | (1 << 22) | (1 << 27));
187 	const guint32 avx2_bmi12_mask = (1 << 5) | (1 << 3) | (1 << 8);
188 	gulong bit;
189 	static struct rspamd_cryptobox_library_ctx *ctx;
190 	GString *buf;
191 
192 	if (cryptobox_loaded) {
193 		/* Ignore reload attempts */
194 		return ctx;
195 	}
196 
197 	cryptobox_loaded = TRUE;
198 	ctx = g_malloc0 (sizeof (*ctx));
199 
200 	rspamd_cryptobox_cpuid (cpu, 0);
201 	nid = cpu[0];
202 	rspamd_cryptobox_cpuid (cpu, 1);
203 
204 	if (nid > 1) {
205 		if ((cpu[3] & ((guint32)1 << 26))) {
206 			if (rspamd_cryptobox_test_instr (CPUID_SSE2)) {
207 				cpu_config |= CPUID_SSE2;
208 			}
209 		}
210 		if ((cpu[2] & ((guint32)1 << 0))) {
211 			if (rspamd_cryptobox_test_instr (CPUID_SSE3)) {
212 				cpu_config |= CPUID_SSE3;
213 			}
214 		}
215 		if ((cpu[2] & ((guint32)1 << 9))) {
216 			if (rspamd_cryptobox_test_instr (CPUID_SSSE3)) {
217 				cpu_config |= CPUID_SSSE3;
218 			}
219 		}
220 		if ((cpu[2] & ((guint32)1 << 19))) {
221 			if (rspamd_cryptobox_test_instr (CPUID_SSE41)) {
222 				cpu_config |= CPUID_SSE41;
223 			}
224 		}
225 		if ((cpu[2] & ((guint32)1 << 20))) {
226 			if (rspamd_cryptobox_test_instr (CPUID_SSE42)) {
227 				cpu_config |= CPUID_SSE42;
228 			}
229 		}
230 		if ((cpu[2] & ((guint32)1 << 30))) {
231 			if (rspamd_cryptobox_test_instr (CPUID_RDRAND)) {
232 				cpu_config |= CPUID_RDRAND;
233 			}
234 		}
235 
236 		/* OSXSAVE */
237 		if ((cpu[2] & osxsave_mask) == osxsave_mask) {
238 			if ((cpu[2] & ((guint32)1 << 28))) {
239 				if (rspamd_cryptobox_test_instr (CPUID_AVX)) {
240 					cpu_config |= CPUID_AVX;
241 				}
242 			}
243 
244 			if (nid >= 7 &&
245 					(cpu[2] & fma_movbe_osxsave_mask) == fma_movbe_osxsave_mask) {
246 				rspamd_cryptobox_cpuid (cpu, 7);
247 
248 				if ((cpu[1] & avx2_bmi12_mask) == avx2_bmi12_mask) {
249 					if (rspamd_cryptobox_test_instr (CPUID_AVX2)) {
250 						cpu_config |= CPUID_AVX2;
251 					}
252 				}
253 			}
254 		}
255 	}
256 
257 	buf = g_string_new ("");
258 
259 	for (bit = 0x1; bit != 0; bit <<= 1) {
260 		if (cpu_config & bit) {
261 			switch (bit) {
262 			case CPUID_SSE2:
263 				rspamd_printf_gstring (buf, "sse2, ");
264 				break;
265 			case CPUID_SSE3:
266 				rspamd_printf_gstring (buf, "sse3, ");
267 				break;
268 			case CPUID_SSSE3:
269 				rspamd_printf_gstring (buf, "ssse3, ");
270 				break;
271 			case CPUID_SSE41:
272 				rspamd_printf_gstring (buf, "sse4.1, ");
273 				break;
274 			case CPUID_SSE42:
275 				rspamd_printf_gstring (buf, "sse4.2, ");
276 				break;
277 			case CPUID_AVX:
278 				rspamd_printf_gstring (buf, "avx, ");
279 				break;
280 			case CPUID_AVX2:
281 				rspamd_printf_gstring (buf, "avx2, ");
282 				break;
283 			case CPUID_RDRAND:
284 				rspamd_printf_gstring (buf, "rdrand, ");
285 				break;
286 			default:
287 				break; /* Silence warning */
288 			}
289 		}
290 	}
291 
292 	if (buf->len > 2) {
293 		/* Trim last chars */
294 		g_string_erase (buf, buf->len - 2, 2);
295 	}
296 
297 	ctx->cpu_extensions = buf->str;
298 	g_string_free (buf, FALSE);
299 	ctx->cpu_config = cpu_config;
300 	g_assert (sodium_init () != -1);
301 
302 	ctx->chacha20_impl = chacha_load ();
303 	ctx->base64_impl = base64_load ();
304 #if defined(HAVE_USABLE_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER))
305 	/* Needed for old openssl api, not sure about LibreSSL */
306 	ERR_load_EC_strings ();
307 	ERR_load_RAND_strings ();
308 	ERR_load_EVP_strings ();
309 #endif
310 
311 	return ctx;
312 }
313 
314 void
rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx * ctx)315 rspamd_cryptobox_deinit (struct rspamd_cryptobox_library_ctx *ctx)
316 {
317 	if (ctx) {
318 		g_free (ctx->cpu_extensions);
319 		g_free (ctx);
320 	}
321 }
322 
323 void
rspamd_cryptobox_keypair(rspamd_pk_t pk,rspamd_sk_t sk,enum rspamd_cryptobox_mode mode)324 rspamd_cryptobox_keypair (rspamd_pk_t pk, rspamd_sk_t sk,
325 		enum rspamd_cryptobox_mode mode)
326 {
327 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
328 		ottery_rand_bytes (sk, rspamd_cryptobox_MAX_SKBYTES);
329 		sk[0] &= 248;
330 		sk[31] &= 127;
331 		sk[31] |= 64;
332 
333 		crypto_scalarmult_base (pk, sk);
334 	}
335 	else {
336 #ifndef HAVE_USABLE_OPENSSL
337 		g_assert (0);
338 #else
339 		EC_KEY *ec_sec;
340 		const BIGNUM *bn_sec;
341 		BIGNUM *bn_pub;
342 		const EC_POINT *ec_pub;
343 		gint len;
344 
345 		ec_sec = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
346 		g_assert (ec_sec != NULL);
347 		g_assert (EC_KEY_generate_key (ec_sec) != 0);
348 
349 		bn_sec = EC_KEY_get0_private_key (ec_sec);
350 		g_assert (bn_sec != NULL);
351 		ec_pub = EC_KEY_get0_public_key (ec_sec);
352 		g_assert (ec_pub != NULL);
353 		bn_pub = EC_POINT_point2bn (EC_KEY_get0_group (ec_sec),
354 				ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
355 
356 		len = BN_num_bytes (bn_sec);
357 		g_assert (len <= (gint)sizeof (rspamd_sk_t));
358 		BN_bn2bin (bn_sec, sk);
359 		len = BN_num_bytes (bn_pub);
360 		g_assert (len <= (gint)rspamd_cryptobox_pk_bytes (mode));
361 		BN_bn2bin (bn_pub, pk);
362 		BN_free (bn_pub);
363 		EC_KEY_free (ec_sec);
364 #endif
365 	}
366 }
367 
368 void
rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk,rspamd_sig_sk_t sk,enum rspamd_cryptobox_mode mode)369 rspamd_cryptobox_keypair_sig (rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
370 		enum rspamd_cryptobox_mode mode)
371 {
372 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
373 		crypto_sign_keypair (pk, sk);
374 	}
375 	else {
376 #ifndef HAVE_USABLE_OPENSSL
377 		g_assert (0);
378 #else
379 		EC_KEY *ec_sec;
380 		const BIGNUM *bn_sec;
381 		BIGNUM *bn_pub;
382 		const EC_POINT *ec_pub;
383 		gint len;
384 
385 		ec_sec = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
386 		g_assert (ec_sec != NULL);
387 		g_assert (EC_KEY_generate_key (ec_sec) != 0);
388 
389 		bn_sec = EC_KEY_get0_private_key (ec_sec);
390 		g_assert (bn_sec != NULL);
391 		ec_pub = EC_KEY_get0_public_key (ec_sec);
392 		g_assert (ec_pub != NULL);
393 		bn_pub = EC_POINT_point2bn (EC_KEY_get0_group (ec_sec),
394 				ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
395 
396 		len = BN_num_bytes (bn_sec);
397 		g_assert (len <= (gint)sizeof (rspamd_sk_t));
398 		BN_bn2bin (bn_sec, sk);
399 		len = BN_num_bytes (bn_pub);
400 		g_assert (len <= (gint)rspamd_cryptobox_pk_bytes (mode));
401 		BN_bn2bin (bn_pub, pk);
402 		BN_free (bn_pub);
403 		EC_KEY_free (ec_sec);
404 #endif
405 	}
406 }
407 
408 void
rspamd_cryptobox_nm(rspamd_nm_t nm,const rspamd_pk_t pk,const rspamd_sk_t sk,enum rspamd_cryptobox_mode mode)409 rspamd_cryptobox_nm (rspamd_nm_t nm,
410 		const rspamd_pk_t pk, const rspamd_sk_t sk,
411 		enum rspamd_cryptobox_mode mode)
412 {
413 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
414 		guchar s[32];
415 		guchar e[32];
416 
417 		memcpy (e, sk, 32);
418 		e[0] &= 248;
419 		e[31] &= 127;
420 		e[31] |= 64;
421 
422 		if (crypto_scalarmult (s, e, pk) != -1) {
423 			hchacha (s, n0, nm, 20);
424 		}
425 
426 		rspamd_explicit_memzero (e, 32);
427 	}
428 	else {
429 #ifndef HAVE_USABLE_OPENSSL
430 		g_assert (0);
431 #else
432 		EC_KEY *lk;
433 		EC_POINT *ec_pub;
434 		BIGNUM *bn_pub, *bn_sec;
435 		gint len;
436 		guchar s[32];
437 
438 		lk = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
439 		g_assert (lk != NULL);
440 
441 		bn_pub = BN_bin2bn (pk, rspamd_cryptobox_pk_bytes (mode), NULL);
442 		g_assert (bn_pub != NULL);
443 		bn_sec = BN_bin2bn (sk, sizeof (rspamd_sk_t), NULL);
444 		g_assert (bn_sec != NULL);
445 
446 		g_assert (EC_KEY_set_private_key (lk, bn_sec) == 1);
447 		ec_pub = EC_POINT_bn2point (EC_KEY_get0_group (lk), bn_pub, NULL, NULL);
448 		g_assert (ec_pub != NULL);
449 		len = ECDH_compute_key (s, sizeof (s), ec_pub, lk, NULL);
450 		g_assert (len == sizeof (s));
451 
452 		/* Still do hchacha iteration since we are not using SHA1 KDF */
453 		hchacha (s, n0, nm, 20);
454 
455 		EC_KEY_free (lk);
456 		EC_POINT_free (ec_pub);
457 		BN_free (bn_sec);
458 		BN_free (bn_pub);
459 #endif
460 	}
461 }
462 
463 void
rspamd_cryptobox_sign(guchar * sig,unsigned long long * siglen_p,const guchar * m,gsize mlen,const rspamd_sk_t sk,enum rspamd_cryptobox_mode mode)464 rspamd_cryptobox_sign (guchar *sig, unsigned long long *siglen_p,
465 		const guchar *m, gsize mlen,
466 		const rspamd_sk_t sk,
467 		enum rspamd_cryptobox_mode mode)
468 {
469 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
470 		crypto_sign_detached (sig, siglen_p, m, mlen, sk);
471 	}
472 	else {
473 #ifndef HAVE_USABLE_OPENSSL
474 		g_assert (0);
475 #else
476 		EC_KEY *lk;
477 		BIGNUM *bn_sec, *kinv = NULL, *rp = NULL;
478 		EVP_MD_CTX *sha_ctx;
479 		unsigned char h[64];
480 		guint diglen = rspamd_cryptobox_signature_bytes (mode);
481 
482 		/* Prehash */
483 		sha_ctx = EVP_MD_CTX_create ();
484 		g_assert (EVP_DigestInit (sha_ctx, EVP_sha512()) == 1);
485 		EVP_DigestUpdate (sha_ctx, m, mlen);
486 		EVP_DigestFinal (sha_ctx, h, NULL);
487 
488 		/* Key setup */
489 		lk = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
490 		g_assert (lk != NULL);
491 		bn_sec = BN_bin2bn (sk, sizeof (rspamd_sk_t), NULL);
492 		g_assert (bn_sec != NULL);
493 		g_assert (EC_KEY_set_private_key (lk, bn_sec) == 1);
494 
495 		/* ECDSA */
496 		g_assert (ECDSA_sign_setup (lk, NULL, &kinv, &rp) == 1);
497 		g_assert (ECDSA_sign_ex (0, h, sizeof (h), sig,
498 				&diglen, kinv, rp, lk) == 1);
499 		g_assert (diglen <= sizeof (rspamd_signature_t));
500 
501 		if (siglen_p) {
502 			*siglen_p = diglen;
503 		}
504 
505 		EC_KEY_free (lk);
506 		EVP_MD_CTX_destroy (sha_ctx);
507 		BN_free (bn_sec);
508 		BN_free (kinv);
509 		BN_free (rp);
510 
511 #endif
512 	}
513 }
514 
515 bool
rspamd_cryptobox_verify(const guchar * sig,gsize siglen,const guchar * m,gsize mlen,const rspamd_pk_t pk,enum rspamd_cryptobox_mode mode)516 rspamd_cryptobox_verify (const guchar *sig,
517 		gsize siglen,
518 		const guchar *m,
519 		gsize mlen,
520 		const rspamd_pk_t pk,
521 		enum rspamd_cryptobox_mode mode)
522 {
523 	bool ret = false;
524 
525 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
526 		if (siglen == rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)) {
527 			ret = (crypto_sign_verify_detached (sig, m, mlen, pk) == 0);
528 		}
529 	}
530 	else {
531 #ifndef HAVE_USABLE_OPENSSL
532 		g_assert (0);
533 #else
534 		EC_KEY *lk;
535 		EC_POINT *ec_pub;
536 		BIGNUM *bn_pub;
537 		EVP_MD_CTX *sha_ctx;
538 		unsigned char h[64];
539 
540 		/* Prehash */
541 		sha_ctx = EVP_MD_CTX_create ();
542 		g_assert (EVP_DigestInit (sha_ctx, EVP_sha512()) == 1);
543 		EVP_DigestUpdate (sha_ctx, m, mlen);
544 		EVP_DigestFinal (sha_ctx, h, NULL);
545 
546 		/* Key setup */
547 		lk = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
548 		g_assert (lk != NULL);
549 		bn_pub = BN_bin2bn (pk, rspamd_cryptobox_pk_bytes (mode), NULL);
550 		g_assert (bn_pub != NULL);
551 		ec_pub = EC_POINT_bn2point (EC_KEY_get0_group (lk), bn_pub, NULL, NULL);
552 		g_assert (ec_pub != NULL);
553 		g_assert (EC_KEY_set_public_key (lk, ec_pub) == 1);
554 
555 		/* ECDSA */
556 		ret = ECDSA_verify (0, h, sizeof (h), sig, siglen, lk) == 1;
557 
558 		EC_KEY_free (lk);
559 		EVP_MD_CTX_destroy (sha_ctx);
560 		BN_free (bn_pub);
561 		EC_POINT_free (ec_pub);
562 #endif
563 	}
564 
565 	return ret;
566 }
567 
568 static gsize
rspamd_cryptobox_encrypt_ctx_len(enum rspamd_cryptobox_mode mode)569 rspamd_cryptobox_encrypt_ctx_len (enum rspamd_cryptobox_mode mode)
570 {
571 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
572 		return sizeof (chacha_state) + CRYPTOBOX_ALIGNMENT;
573 	}
574 	else {
575 #ifndef HAVE_USABLE_OPENSSL
576 		g_assert (0);
577 #else
578 		return sizeof (EVP_CIPHER_CTX *) + CRYPTOBOX_ALIGNMENT;
579 #endif
580 	}
581 
582 	return 0;
583 }
584 
585 static gsize
rspamd_cryptobox_auth_ctx_len(enum rspamd_cryptobox_mode mode)586 rspamd_cryptobox_auth_ctx_len (enum rspamd_cryptobox_mode mode)
587 {
588 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
589 		return sizeof (crypto_onetimeauth_state) + _Alignof (crypto_onetimeauth_state);
590 	}
591 	else {
592 #ifndef HAVE_USABLE_OPENSSL
593 		g_assert (0);
594 #else
595 		return sizeof (void *);
596 #endif
597 	}
598 
599 	return 0;
600 }
601 
602 static void *
rspamd_cryptobox_encrypt_init(void * enc_ctx,const rspamd_nonce_t nonce,const rspamd_nm_t nm,enum rspamd_cryptobox_mode mode)603 rspamd_cryptobox_encrypt_init (void *enc_ctx, const rspamd_nonce_t nonce,
604 		const rspamd_nm_t nm,
605 		enum rspamd_cryptobox_mode mode)
606 {
607 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
608 		chacha_state *s;
609 
610 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
611 		xchacha_init (s,
612 				(const chacha_key *) nm,
613 				(const chacha_iv24 *) nonce,
614 				20);
615 
616 		return s;
617 	}
618 	else {
619 #ifndef HAVE_USABLE_OPENSSL
620 		g_assert (0);
621 #else
622 		EVP_CIPHER_CTX **s;
623 
624 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
625 		memset (s, 0, sizeof (*s));
626 		*s = EVP_CIPHER_CTX_new ();
627 		g_assert (EVP_EncryptInit_ex (*s, EVP_aes_256_gcm (), NULL, NULL, NULL) == 1);
628 		g_assert (EVP_CIPHER_CTX_ctrl (*s, EVP_CTRL_GCM_SET_IVLEN,
629 				rspamd_cryptobox_nonce_bytes (mode), NULL) == 1);
630 		g_assert (EVP_EncryptInit_ex (*s, NULL, NULL, nm, nonce) == 1);
631 
632 		return s;
633 #endif
634 	}
635 
636 	return NULL;
637 }
638 
639 static void *
rspamd_cryptobox_auth_init(void * auth_ctx,void * enc_ctx,enum rspamd_cryptobox_mode mode)640 rspamd_cryptobox_auth_init (void *auth_ctx, void *enc_ctx,
641 		enum rspamd_cryptobox_mode mode)
642 {
643 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
644 		crypto_onetimeauth_state *mac_ctx;
645 		guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
646 
647 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
648 		memset (subkey, 0, sizeof (subkey));
649 		chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
650 		crypto_onetimeauth_init (mac_ctx, subkey);
651 		rspamd_explicit_memzero (subkey, sizeof (subkey));
652 
653 		return mac_ctx;
654 	}
655 	else {
656 #ifndef HAVE_USABLE_OPENSSL
657 		g_assert (0);
658 #else
659 		auth_ctx = enc_ctx;
660 
661 		return auth_ctx;
662 #endif
663 	}
664 
665 	return NULL;
666 }
667 
668 static gboolean
rspamd_cryptobox_encrypt_update(void * enc_ctx,const guchar * in,gsize inlen,guchar * out,gsize * outlen,enum rspamd_cryptobox_mode mode)669 rspamd_cryptobox_encrypt_update (void *enc_ctx, const guchar *in, gsize inlen,
670 		guchar *out, gsize *outlen,
671 		enum rspamd_cryptobox_mode mode)
672 {
673 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
674 		gsize r;
675 		chacha_state *s;
676 
677 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
678 
679 		r = chacha_update (s, in, out, inlen);
680 
681 		if (outlen != NULL) {
682 			*outlen = r;
683 		}
684 
685 		return TRUE;
686 	}
687 	else {
688 #ifndef HAVE_USABLE_OPENSSL
689 		g_assert (0);
690 #else
691 		EVP_CIPHER_CTX **s = enc_ctx;
692 		gint r;
693 
694 		r = inlen;
695 		g_assert (EVP_EncryptUpdate (*s, out, &r, in, inlen) == 1);
696 
697 		if (outlen) {
698 			*outlen = r;
699 		}
700 
701 		return TRUE;
702 #endif
703 	}
704 
705 	return FALSE;
706 }
707 
708 static gboolean
rspamd_cryptobox_auth_update(void * auth_ctx,const guchar * in,gsize inlen,enum rspamd_cryptobox_mode mode)709 rspamd_cryptobox_auth_update (void *auth_ctx, const guchar *in, gsize inlen,
710 		enum rspamd_cryptobox_mode mode)
711 {
712 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
713 		crypto_onetimeauth_state *mac_ctx;
714 
715 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
716 		crypto_onetimeauth_update (mac_ctx, in, inlen);
717 
718 		return TRUE;
719 	}
720 	else {
721 #ifndef HAVE_USABLE_OPENSSL
722 		g_assert (0);
723 #else
724 		return TRUE;
725 #endif
726 	}
727 
728 	return FALSE;
729 }
730 
731 static gsize
rspamd_cryptobox_encrypt_final(void * enc_ctx,guchar * out,gsize remain,enum rspamd_cryptobox_mode mode)732 rspamd_cryptobox_encrypt_final (void *enc_ctx, guchar *out, gsize remain,
733 		enum rspamd_cryptobox_mode mode)
734 {
735 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
736 		chacha_state *s;
737 
738 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
739 		return chacha_final (s, out);
740 	}
741 	else {
742 #ifndef HAVE_USABLE_OPENSSL
743 		g_assert (0);
744 #else
745 		EVP_CIPHER_CTX **s = enc_ctx;
746 		gint r = remain;
747 
748 		g_assert (EVP_EncryptFinal_ex (*s, out, &r) == 1);
749 
750 		return r;
751 #endif
752 	}
753 
754 	return 0;
755 }
756 
757 static gboolean
rspamd_cryptobox_auth_final(void * auth_ctx,rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)758 rspamd_cryptobox_auth_final (void *auth_ctx, rspamd_mac_t sig,
759 		enum rspamd_cryptobox_mode mode)
760 {
761 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
762 		crypto_onetimeauth_state *mac_ctx;
763 
764 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
765 		crypto_onetimeauth_final (mac_ctx, sig);
766 
767 		return TRUE;
768 	}
769 	else {
770 #ifndef HAVE_USABLE_OPENSSL
771 		g_assert (0);
772 #else
773 		EVP_CIPHER_CTX **s = auth_ctx;
774 
775 		g_assert (EVP_CIPHER_CTX_ctrl (*s, EVP_CTRL_GCM_GET_TAG,
776 				sizeof (rspamd_mac_t), sig) == 1);
777 
778 		return TRUE;
779 #endif
780 	}
781 
782 	return FALSE;
783 }
784 
785 static void *
rspamd_cryptobox_decrypt_init(void * enc_ctx,const rspamd_nonce_t nonce,const rspamd_nm_t nm,enum rspamd_cryptobox_mode mode)786 rspamd_cryptobox_decrypt_init (void *enc_ctx, const rspamd_nonce_t nonce,
787 		const rspamd_nm_t nm,
788 		enum rspamd_cryptobox_mode mode)
789 {
790 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
791 
792 		chacha_state *s;
793 
794 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
795 		xchacha_init (s,
796 				(const chacha_key *) nm,
797 				(const chacha_iv24 *) nonce,
798 				20);
799 
800 		return s;
801 	}
802 	else {
803 #ifndef HAVE_USABLE_OPENSSL
804 		g_assert (0);
805 #else
806 		EVP_CIPHER_CTX **s;
807 
808 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
809 		memset (s, 0, sizeof (*s));
810 		*s = EVP_CIPHER_CTX_new ();
811 		g_assert (EVP_DecryptInit_ex(*s, EVP_aes_256_gcm (), NULL, NULL, NULL) == 1);
812 		g_assert (EVP_CIPHER_CTX_ctrl (*s, EVP_CTRL_GCM_SET_IVLEN,
813 				rspamd_cryptobox_nonce_bytes (mode), NULL) == 1);
814 		g_assert (EVP_DecryptInit_ex (*s, NULL, NULL, nm, nonce) == 1);
815 
816 		return s;
817 #endif
818 	}
819 
820 	return NULL;
821 }
822 
823 static void *
rspamd_cryptobox_auth_verify_init(void * auth_ctx,void * enc_ctx,enum rspamd_cryptobox_mode mode)824 rspamd_cryptobox_auth_verify_init (void *auth_ctx, void *enc_ctx,
825 		enum rspamd_cryptobox_mode mode)
826 {
827 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
828 		crypto_onetimeauth_state *mac_ctx;
829 		guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
830 
831 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
832 		memset (subkey, 0, sizeof (subkey));
833 		chacha_update (enc_ctx, subkey, subkey, sizeof (subkey));
834 		crypto_onetimeauth_init (mac_ctx, subkey);
835 		rspamd_explicit_memzero (subkey, sizeof (subkey));
836 
837 		return mac_ctx;
838 	}
839 	else {
840 #ifndef HAVE_USABLE_OPENSSL
841 		g_assert (0);
842 #else
843 		auth_ctx = enc_ctx;
844 
845 		return auth_ctx;
846 #endif
847 	}
848 
849 	return NULL;
850 }
851 
852 static gboolean
rspamd_cryptobox_decrypt_update(void * enc_ctx,const guchar * in,gsize inlen,guchar * out,gsize * outlen,enum rspamd_cryptobox_mode mode)853 rspamd_cryptobox_decrypt_update (void *enc_ctx, const guchar *in, gsize inlen,
854 		guchar *out, gsize *outlen,
855 		enum rspamd_cryptobox_mode mode)
856 {
857 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
858 		gsize r;
859 		chacha_state *s;
860 
861 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
862 		r = chacha_update (s, in, out, inlen);
863 
864 		if (outlen != NULL) {
865 			*outlen = r;
866 		}
867 
868 		return TRUE;
869 	}
870 	else {
871 #ifndef HAVE_USABLE_OPENSSL
872 		g_assert (0);
873 #else
874 		EVP_CIPHER_CTX **s = enc_ctx;
875 		gint r;
876 
877 		r = outlen ? *outlen : inlen;
878 		g_assert (EVP_DecryptUpdate (*s, out, &r, in, inlen) == 1);
879 
880 		if (outlen) {
881 			*outlen = r;
882 		}
883 
884 		return TRUE;
885 #endif
886 	}
887 }
888 
889 static gboolean
rspamd_cryptobox_auth_verify_update(void * auth_ctx,const guchar * in,gsize inlen,enum rspamd_cryptobox_mode mode)890 rspamd_cryptobox_auth_verify_update (void *auth_ctx,
891 		const guchar *in, gsize inlen,
892 		enum rspamd_cryptobox_mode mode)
893 {
894 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
895 		crypto_onetimeauth_state *mac_ctx;
896 
897 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
898 		crypto_onetimeauth_update (mac_ctx, in, inlen);
899 
900 		return TRUE;
901 	}
902 	else {
903 #ifndef HAVE_USABLE_OPENSSL
904 		/* We do not need to authenticate as a separate process */
905 		return TRUE;
906 #else
907 #endif
908 	}
909 
910 	return FALSE;
911 }
912 
913 static gboolean
rspamd_cryptobox_decrypt_final(void * enc_ctx,guchar * out,gsize remain,enum rspamd_cryptobox_mode mode)914 rspamd_cryptobox_decrypt_final (void *enc_ctx, guchar *out, gsize remain,
915 		enum rspamd_cryptobox_mode mode)
916 {
917 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
918 		chacha_state *s;
919 
920 		s = cryptobox_align_ptr (enc_ctx, CRYPTOBOX_ALIGNMENT);
921 		chacha_final (s, out);
922 
923 		return TRUE;
924 	}
925 	else {
926 #ifndef HAVE_USABLE_OPENSSL
927 		g_assert (0);
928 #else
929 		EVP_CIPHER_CTX **s = enc_ctx;
930 		gint r = remain;
931 
932 		if (EVP_DecryptFinal_ex (*s, out, &r) < 0) {
933 			return FALSE;
934 		}
935 
936 		return TRUE;
937 #endif
938 	}
939 
940 	return FALSE;
941 }
942 
943 static gboolean
rspamd_cryptobox_auth_verify_final(void * auth_ctx,const rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)944 rspamd_cryptobox_auth_verify_final (void *auth_ctx, const rspamd_mac_t sig,
945 		enum rspamd_cryptobox_mode mode)
946 {
947 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
948 		rspamd_mac_t mac;
949 		crypto_onetimeauth_state *mac_ctx;
950 
951 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
952 		crypto_onetimeauth_final (mac_ctx, mac);
953 
954 		if (crypto_verify_16 (mac, sig) != 0) {
955 			return FALSE;
956 		}
957 
958 		return TRUE;
959 	}
960 	else {
961 #ifndef HAVE_USABLE_OPENSSL
962 		g_assert (0);
963 #else
964 		EVP_CIPHER_CTX **s = auth_ctx;
965 
966 		if (EVP_CIPHER_CTX_ctrl (*s, EVP_CTRL_GCM_SET_TAG, 16, (guchar *)sig) != 1) {
967 			return FALSE;
968 		}
969 
970 		return TRUE;
971 #endif
972 	}
973 
974 	return FALSE;
975 }
976 
977 
978 static void
rspamd_cryptobox_cleanup(void * enc_ctx,void * auth_ctx,enum rspamd_cryptobox_mode mode)979 rspamd_cryptobox_cleanup (void *enc_ctx, void *auth_ctx,
980 		enum rspamd_cryptobox_mode mode)
981 {
982 	if (G_LIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
983 		crypto_onetimeauth_state *mac_ctx;
984 
985 		mac_ctx = cryptobox_align_ptr (auth_ctx, CRYPTOBOX_ALIGNMENT);
986 		rspamd_explicit_memzero (mac_ctx, sizeof (*mac_ctx));
987 	}
988 	else {
989 #ifndef HAVE_USABLE_OPENSSL
990 		g_assert (0);
991 #else
992 		EVP_CIPHER_CTX **s = enc_ctx;
993 
994 		EVP_CIPHER_CTX_cleanup (*s);
995 		EVP_CIPHER_CTX_free (*s);
996 #endif
997 	}
998 }
999 
rspamd_cryptobox_encrypt_nm_inplace(guchar * data,gsize len,const rspamd_nonce_t nonce,const rspamd_nm_t nm,rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1000 void rspamd_cryptobox_encrypt_nm_inplace (guchar *data, gsize len,
1001 		const rspamd_nonce_t nonce,
1002 		const rspamd_nm_t nm,
1003 		rspamd_mac_t sig,
1004 		enum rspamd_cryptobox_mode mode)
1005 {
1006 	gsize r;
1007 	void *enc_ctx, *auth_ctx;
1008 
1009 	enc_ctx = g_alloca (rspamd_cryptobox_encrypt_ctx_len (mode));
1010 	auth_ctx = g_alloca (rspamd_cryptobox_auth_ctx_len (mode));
1011 
1012 	enc_ctx = rspamd_cryptobox_encrypt_init (enc_ctx, nonce, nm, mode);
1013 	auth_ctx = rspamd_cryptobox_auth_init (auth_ctx, enc_ctx, mode);
1014 
1015 	rspamd_cryptobox_encrypt_update (enc_ctx, data, len, data, &r, mode);
1016 	rspamd_cryptobox_encrypt_final (enc_ctx, data + r, len - r, mode);
1017 
1018 	rspamd_cryptobox_auth_update (auth_ctx, data, len, mode);
1019 	rspamd_cryptobox_auth_final (auth_ctx, sig, mode);
1020 
1021 	rspamd_cryptobox_cleanup (enc_ctx, auth_ctx, mode);
1022 }
1023 
1024 static void
rspamd_cryptobox_flush_outbuf(struct rspamd_cryptobox_segment * st,const guchar * buf,gsize len,gsize offset)1025 rspamd_cryptobox_flush_outbuf (struct rspamd_cryptobox_segment *st,
1026 		const guchar *buf, gsize len, gsize offset)
1027 {
1028 	gsize cpy_len;
1029 
1030 	while (len > 0) {
1031 		cpy_len = MIN (len, st->len - offset);
1032 		memcpy (st->data + offset, buf, cpy_len);
1033 		st ++;
1034 		buf += cpy_len;
1035 		len -= cpy_len;
1036 		offset = 0;
1037 	}
1038 }
1039 
1040 void
rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment * segments,gsize cnt,const rspamd_nonce_t nonce,const rspamd_nm_t nm,rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1041 rspamd_cryptobox_encryptv_nm_inplace (struct rspamd_cryptobox_segment *segments,
1042 		gsize cnt,
1043 		const rspamd_nonce_t nonce,
1044 		const rspamd_nm_t nm, rspamd_mac_t sig,
1045 		enum rspamd_cryptobox_mode mode)
1046 {
1047 	struct rspamd_cryptobox_segment *cur = segments, *start_seg = segments;
1048 	guchar outbuf[CHACHA_BLOCKBYTES * 16];
1049 	void *enc_ctx, *auth_ctx;
1050 	guchar *out, *in;
1051 	gsize r, remain, inremain, seg_offset;
1052 
1053 	enc_ctx = g_alloca (rspamd_cryptobox_encrypt_ctx_len (mode));
1054 	auth_ctx = g_alloca (rspamd_cryptobox_auth_ctx_len (mode));
1055 
1056 	enc_ctx = rspamd_cryptobox_encrypt_init (enc_ctx, nonce, nm, mode);
1057 	auth_ctx = rspamd_cryptobox_auth_init (auth_ctx, enc_ctx, mode);
1058 
1059 	remain = sizeof (outbuf);
1060 	out = outbuf;
1061 	inremain = cur->len;
1062 	seg_offset = 0;
1063 
1064 	for (;;) {
1065 		if (cur - segments == (gint)cnt) {
1066 			break;
1067 		}
1068 
1069 		if (cur->len <= remain) {
1070 			memcpy (out, cur->data, cur->len);
1071 			remain -= cur->len;
1072 			out += cur->len;
1073 			cur ++;
1074 
1075 			if (remain == 0) {
1076 				rspamd_cryptobox_encrypt_update (enc_ctx, outbuf, sizeof (outbuf),
1077 						outbuf, NULL, mode);
1078 				rspamd_cryptobox_auth_update (auth_ctx, outbuf, sizeof (outbuf),
1079 						mode);
1080 				rspamd_cryptobox_flush_outbuf (start_seg, outbuf,
1081 						sizeof (outbuf), seg_offset);
1082 				start_seg = cur;
1083 				seg_offset = 0;
1084 				remain = sizeof (outbuf);
1085 				out = outbuf;
1086 			}
1087 		}
1088 		else {
1089 			memcpy (out, cur->data, remain);
1090 			rspamd_cryptobox_encrypt_update (enc_ctx, outbuf, sizeof (outbuf),
1091 					outbuf, NULL, mode);
1092 			rspamd_cryptobox_auth_update (auth_ctx, outbuf, sizeof (outbuf),
1093 					mode);
1094 			rspamd_cryptobox_flush_outbuf (start_seg, outbuf, sizeof (outbuf),
1095 					seg_offset);
1096 			seg_offset = 0;
1097 
1098 			inremain = cur->len - remain;
1099 			in = cur->data + remain;
1100 			out = outbuf;
1101 			remain = 0;
1102 			start_seg = cur;
1103 
1104 			while (inremain > 0) {
1105 				if (sizeof (outbuf) <= inremain) {
1106 					memcpy (outbuf, in, sizeof (outbuf));
1107 					rspamd_cryptobox_encrypt_update (enc_ctx,
1108 							outbuf,
1109 							sizeof (outbuf),
1110 							outbuf,
1111 							NULL,
1112 							mode);
1113 					rspamd_cryptobox_auth_update (auth_ctx,
1114 							outbuf,
1115 							sizeof (outbuf),
1116 							mode);
1117 					memcpy (in, outbuf, sizeof (outbuf));
1118 					in += sizeof (outbuf);
1119 					inremain -= sizeof (outbuf);
1120 					remain = sizeof (outbuf);
1121 				}
1122 				else {
1123 					memcpy (outbuf, in, inremain);
1124 					remain = sizeof (outbuf) - inremain;
1125 					out = outbuf + inremain;
1126 					inremain = 0;
1127 				}
1128 			}
1129 
1130 			seg_offset = cur->len - (sizeof (outbuf) - remain);
1131 			cur ++;
1132 		}
1133 	}
1134 
1135 	rspamd_cryptobox_encrypt_update (enc_ctx, outbuf, sizeof (outbuf) - remain,
1136 			outbuf, &r, mode);
1137 	out = outbuf + r;
1138 	rspamd_cryptobox_encrypt_final (enc_ctx, out, sizeof (outbuf) - remain - r,
1139 			mode);
1140 
1141 	rspamd_cryptobox_auth_update (auth_ctx, outbuf, sizeof (outbuf) - remain,
1142 			mode);
1143 	rspamd_cryptobox_auth_final (auth_ctx, sig, mode);
1144 
1145 	rspamd_cryptobox_flush_outbuf (start_seg, outbuf, sizeof (outbuf) - remain,
1146 			seg_offset);
1147 	rspamd_cryptobox_cleanup (enc_ctx, auth_ctx, mode);
1148 }
1149 
1150 gboolean
rspamd_cryptobox_decrypt_nm_inplace(guchar * data,gsize len,const rspamd_nonce_t nonce,const rspamd_nm_t nm,const rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1151 rspamd_cryptobox_decrypt_nm_inplace (guchar *data, gsize len,
1152 		const rspamd_nonce_t nonce, const rspamd_nm_t nm,
1153 		const rspamd_mac_t sig, enum rspamd_cryptobox_mode mode)
1154 {
1155 	gsize r = 0;
1156 	gboolean ret = TRUE;
1157 	void *enc_ctx, *auth_ctx;
1158 
1159 	enc_ctx = g_alloca (rspamd_cryptobox_encrypt_ctx_len (mode));
1160 	auth_ctx = g_alloca (rspamd_cryptobox_auth_ctx_len (mode));
1161 
1162 	enc_ctx = rspamd_cryptobox_decrypt_init (enc_ctx, nonce, nm, mode);
1163 	auth_ctx = rspamd_cryptobox_auth_verify_init (auth_ctx, enc_ctx, mode);
1164 
1165 	rspamd_cryptobox_auth_verify_update (auth_ctx, data, len, mode);
1166 
1167 	if (!rspamd_cryptobox_auth_verify_final (auth_ctx, sig, mode)) {
1168 		ret = FALSE;
1169 	}
1170 	else {
1171 		rspamd_cryptobox_decrypt_update (enc_ctx, data, len, data, &r, mode);
1172 		ret = rspamd_cryptobox_decrypt_final (enc_ctx, data + r, len - r, mode);
1173 	}
1174 
1175 	rspamd_cryptobox_cleanup (enc_ctx, auth_ctx, mode);
1176 
1177 	return ret;
1178 }
1179 
1180 gboolean
rspamd_cryptobox_decrypt_inplace(guchar * data,gsize len,const rspamd_nonce_t nonce,const rspamd_pk_t pk,const rspamd_sk_t sk,const rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1181 rspamd_cryptobox_decrypt_inplace (guchar *data, gsize len,
1182 		const rspamd_nonce_t nonce,
1183 		const rspamd_pk_t pk, const rspamd_sk_t sk,
1184 		const rspamd_mac_t sig,
1185 		enum rspamd_cryptobox_mode mode)
1186 {
1187 	guchar nm[rspamd_cryptobox_MAX_NMBYTES];
1188 	gboolean ret;
1189 
1190 	rspamd_cryptobox_nm (nm, pk, sk, mode);
1191 	ret = rspamd_cryptobox_decrypt_nm_inplace (data, len, nonce, nm, sig, mode);
1192 
1193 	rspamd_explicit_memzero (nm, sizeof (nm));
1194 
1195 	return ret;
1196 }
1197 
1198 void
rspamd_cryptobox_encrypt_inplace(guchar * data,gsize len,const rspamd_nonce_t nonce,const rspamd_pk_t pk,const rspamd_sk_t sk,rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1199 rspamd_cryptobox_encrypt_inplace (guchar *data, gsize len,
1200 		const rspamd_nonce_t nonce,
1201 		const rspamd_pk_t pk, const rspamd_sk_t sk,
1202 		rspamd_mac_t sig,
1203 		enum rspamd_cryptobox_mode mode)
1204 {
1205 	guchar nm[rspamd_cryptobox_MAX_NMBYTES];
1206 
1207 	rspamd_cryptobox_nm (nm, pk, sk, mode);
1208 	rspamd_cryptobox_encrypt_nm_inplace (data, len, nonce, nm, sig, mode);
1209 	rspamd_explicit_memzero (nm, sizeof (nm));
1210 }
1211 
1212 void
rspamd_cryptobox_encryptv_inplace(struct rspamd_cryptobox_segment * segments,gsize cnt,const rspamd_nonce_t nonce,const rspamd_pk_t pk,const rspamd_sk_t sk,rspamd_mac_t sig,enum rspamd_cryptobox_mode mode)1213 rspamd_cryptobox_encryptv_inplace (struct rspamd_cryptobox_segment *segments,
1214 		gsize cnt,
1215 		const rspamd_nonce_t nonce,
1216 		const rspamd_pk_t pk, const rspamd_sk_t sk,
1217 		rspamd_mac_t sig,
1218 		enum rspamd_cryptobox_mode mode)
1219 {
1220 	guchar nm[rspamd_cryptobox_MAX_NMBYTES];
1221 
1222 	rspamd_cryptobox_nm (nm, pk, sk, mode);
1223 	rspamd_cryptobox_encryptv_nm_inplace (segments, cnt, nonce, nm, sig, mode);
1224 	rspamd_explicit_memzero (nm, sizeof (nm));
1225 }
1226 
1227 
1228 void
rspamd_cryptobox_siphash(unsigned char * out,const unsigned char * in,unsigned long long inlen,const rspamd_sipkey_t k)1229 rspamd_cryptobox_siphash (unsigned char *out, const unsigned char *in,
1230 		unsigned long long inlen,
1231 		const rspamd_sipkey_t k)
1232 {
1233 	crypto_shorthash_siphash24 (out, in, inlen, k);
1234 }
1235 
1236 /*
1237  * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
1238  * Code based on IEEE Std 802.11-2007, Annex H.4.2.
1239  */
1240 static gboolean
rspamd_cryptobox_pbkdf2(const char * pass,gsize pass_len,const guint8 * salt,gsize salt_len,guint8 * key,gsize key_len,unsigned int rounds)1241 rspamd_cryptobox_pbkdf2 (const char *pass, gsize pass_len,
1242 		const guint8 *salt, gsize salt_len, guint8 *key, gsize key_len,
1243 		unsigned int rounds)
1244 {
1245 	guint8 *asalt, obuf[crypto_generichash_blake2b_BYTES_MAX];
1246 	guint8 d1[crypto_generichash_blake2b_BYTES_MAX],
1247 			d2[crypto_generichash_blake2b_BYTES_MAX];
1248 	unsigned int i, j;
1249 	unsigned int count;
1250 	gsize r;
1251 
1252 	if (rounds < 1 || key_len == 0) {
1253 		return FALSE;
1254 	}
1255 	if (salt_len == 0 || salt_len > G_MAXSIZE - 4) {
1256 		return FALSE;
1257 	}
1258 
1259 	asalt = g_malloc (salt_len + 4);
1260 	memcpy (asalt, salt, salt_len);
1261 
1262 	for (count = 1; key_len > 0; count++) {
1263 		asalt[salt_len + 0] = (count >> 24) & 0xff;
1264 		asalt[salt_len + 1] = (count >> 16) & 0xff;
1265 		asalt[salt_len + 2] = (count >> 8) & 0xff;
1266 		asalt[salt_len + 3] = count & 0xff;
1267 
1268 		if (pass_len <= crypto_generichash_blake2b_KEYBYTES_MAX) {
1269 			crypto_generichash_blake2b (d1, sizeof (d1), asalt, salt_len + 4,
1270 					pass, pass_len);
1271 		}
1272 		else {
1273 			guint8 k[crypto_generichash_blake2b_BYTES_MAX];
1274 
1275 			/*
1276 			 * We use additional blake2 iteration to store large key
1277 			 * XXX: it is not compatible with the original implementation but safe
1278 			 */
1279 			crypto_generichash_blake2b (k, sizeof (k), pass, pass_len,
1280 					NULL, 0);
1281 			crypto_generichash_blake2b (d1, sizeof (d1), asalt, salt_len + 4,
1282 					k, sizeof (k));
1283 		}
1284 
1285 		memcpy (obuf, d1, sizeof(obuf));
1286 
1287 		for (i = 1; i < rounds; i++) {
1288 			if (pass_len <= crypto_generichash_blake2b_KEYBYTES_MAX) {
1289 				crypto_generichash_blake2b (d2, sizeof (d2), d1, sizeof (d1),
1290 						pass, pass_len);
1291 			}
1292 			else {
1293 				guint8 k[crypto_generichash_blake2b_BYTES_MAX];
1294 
1295 				/*
1296 				 * We use additional blake2 iteration to store large key
1297 				 * XXX: it is not compatible with the original implementation but safe
1298 				 */
1299 				crypto_generichash_blake2b (k, sizeof (k), pass, pass_len,
1300 						NULL, 0);
1301 				crypto_generichash_blake2b (d2, sizeof (d2), d1, sizeof (d1),
1302 						k, sizeof (k));
1303 			}
1304 
1305 			memcpy (d1, d2, sizeof(d1));
1306 
1307 			for (j = 0; j < sizeof(obuf); j++) {
1308 				obuf[j] ^= d1[j];
1309 			}
1310 		}
1311 
1312 		r = MIN(key_len, crypto_generichash_blake2b_BYTES_MAX);
1313 		memcpy (key, obuf, r);
1314 		key += r;
1315 		key_len -= r;
1316 	}
1317 
1318 	rspamd_explicit_memzero (asalt, salt_len + 4);
1319 	g_free (asalt);
1320 	rspamd_explicit_memzero (d1, sizeof (d1));
1321 	rspamd_explicit_memzero (d2, sizeof (d2));
1322 	rspamd_explicit_memzero (obuf, sizeof (obuf));
1323 
1324 	return TRUE;
1325 }
1326 
1327 gboolean
rspamd_cryptobox_pbkdf(const char * pass,gsize pass_len,const guint8 * salt,gsize salt_len,guint8 * key,gsize key_len,unsigned int complexity,enum rspamd_cryptobox_pbkdf_type type)1328 rspamd_cryptobox_pbkdf (const char *pass, gsize pass_len,
1329 		const guint8 *salt, gsize salt_len, guint8 *key, gsize key_len,
1330 		unsigned int complexity, enum rspamd_cryptobox_pbkdf_type type)
1331 {
1332 	gboolean ret = FALSE;
1333 
1334 	switch (type) {
1335 	case RSPAMD_CRYPTOBOX_CATENA:
1336 		if (catena (pass, pass_len, salt, salt_len, "rspamd", 6,
1337 				4, complexity, complexity, key_len, key) == 0) {
1338 			ret = TRUE;
1339 		}
1340 		break;
1341 	case RSPAMD_CRYPTOBOX_PBKDF2:
1342 	default:
1343 		ret = rspamd_cryptobox_pbkdf2 (pass, pass_len, salt, salt_len, key,
1344 				key_len, complexity);
1345 		break;
1346 	}
1347 
1348 	return ret;
1349 }
1350 
1351 guint
rspamd_cryptobox_pk_bytes(enum rspamd_cryptobox_mode mode)1352 rspamd_cryptobox_pk_bytes (enum rspamd_cryptobox_mode mode)
1353 {
1354 	if (G_UNLIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
1355 		return 32;
1356 	}
1357 	else {
1358 		return 65;
1359 	}
1360 }
1361 
1362 guint
rspamd_cryptobox_pk_sig_bytes(enum rspamd_cryptobox_mode mode)1363 rspamd_cryptobox_pk_sig_bytes (enum rspamd_cryptobox_mode mode)
1364 {
1365 	if (G_UNLIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
1366 		return 32;
1367 	}
1368 	else {
1369 		return 65;
1370 	}
1371 }
1372 
1373 guint
rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode)1374 rspamd_cryptobox_nonce_bytes (enum rspamd_cryptobox_mode mode)
1375 {
1376 	if (G_UNLIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
1377 		return 24;
1378 	}
1379 	else {
1380 		return 16;
1381 	}
1382 }
1383 
1384 
1385 guint
rspamd_cryptobox_sk_bytes(enum rspamd_cryptobox_mode mode)1386 rspamd_cryptobox_sk_bytes (enum rspamd_cryptobox_mode mode)
1387 {
1388 	return 32;
1389 }
1390 
1391 guint
rspamd_cryptobox_sk_sig_bytes(enum rspamd_cryptobox_mode mode)1392 rspamd_cryptobox_sk_sig_bytes (enum rspamd_cryptobox_mode mode)
1393 {
1394 	if (G_UNLIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
1395 		return 64;
1396 	}
1397 	else {
1398 		return 32;
1399 	}
1400 }
1401 
1402 guint
rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode)1403 rspamd_cryptobox_signature_bytes (enum rspamd_cryptobox_mode mode)
1404 {
1405 	static guint ssl_keylen;
1406 
1407 	if (G_UNLIKELY (mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
1408 		return 64;
1409 	}
1410 	else {
1411 #ifndef HAVE_USABLE_OPENSSL
1412 		g_assert (0);
1413 #else
1414 		if (ssl_keylen == 0) {
1415 			EC_KEY *lk;
1416 			lk = EC_KEY_new_by_curve_name (CRYPTOBOX_CURVE_NID);
1417 			ssl_keylen = ECDSA_size (lk);
1418 			EC_KEY_free (lk);
1419 		}
1420 #endif
1421 		return ssl_keylen;
1422 	}
1423 }
1424 
1425 guint
rspamd_cryptobox_nm_bytes(enum rspamd_cryptobox_mode mode)1426 rspamd_cryptobox_nm_bytes (enum rspamd_cryptobox_mode mode)
1427 {
1428 	return 32;
1429 }
1430 
1431 guint
rspamd_cryptobox_mac_bytes(enum rspamd_cryptobox_mode mode)1432 rspamd_cryptobox_mac_bytes (enum rspamd_cryptobox_mode mode)
1433 {
1434 	return 16;
1435 }
1436 
1437 void
rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t * p,const guchar * key,gsize keylen)1438 rspamd_cryptobox_hash_init (rspamd_cryptobox_hash_state_t *p, const guchar *key, gsize keylen)
1439 {
1440 	crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
1441 			_Alignof(crypto_generichash_blake2b_state));
1442 	crypto_generichash_blake2b_init (st, key, keylen,
1443 			crypto_generichash_blake2b_BYTES_MAX);
1444 }
1445 
1446 /**
1447  * Update hash with data portion
1448  */
1449 void
rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t * p,const guchar * data,gsize len)1450 rspamd_cryptobox_hash_update (rspamd_cryptobox_hash_state_t *p, const guchar *data, gsize len)
1451 {
1452 	crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
1453 			_Alignof(crypto_generichash_blake2b_state));
1454 	crypto_generichash_blake2b_update (st, data, len);
1455 }
1456 
1457 /**
1458  * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
1459  */
1460 void
rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t * p,guchar * out)1461 rspamd_cryptobox_hash_final (rspamd_cryptobox_hash_state_t *p, guchar *out)
1462 {
1463 	crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
1464 			_Alignof(crypto_generichash_blake2b_state));
1465 	crypto_generichash_blake2b_final (st, out, crypto_generichash_blake2b_BYTES_MAX);
1466 }
1467 
1468 /**
1469  * One in all function
1470  */
rspamd_cryptobox_hash(guchar * out,const guchar * data,gsize len,const guchar * key,gsize keylen)1471 void rspamd_cryptobox_hash (guchar *out,
1472 		const guchar *data,
1473 		gsize len,
1474 		const guchar *key,
1475 		gsize keylen)
1476 {
1477 	crypto_generichash_blake2b (out, crypto_generichash_blake2b_BYTES_MAX,
1478 			data, len, key, keylen);
1479 }
1480 
1481 G_STATIC_ASSERT (sizeof (t1ha_context_t) <=
1482 		sizeof (((rspamd_cryptobox_fast_hash_state_t *)NULL)->opaque));
1483 G_STATIC_ASSERT (sizeof (XXH64_state_t) <=
1484 				 sizeof (((rspamd_cryptobox_fast_hash_state_t *)NULL)->opaque));
1485 
1486 
1487 struct RSPAMD_ALIGNED(16) _mum_iuf {
1488 	union {
1489 		gint64 ll;
1490 		unsigned char b[sizeof (guint64)];
1491 	} buf;
1492 	gint64 h;
1493 	unsigned rem;
1494 };
1495 
1496 void
rspamd_cryptobox_fast_hash_init(rspamd_cryptobox_fast_hash_state_t * st,guint64 seed)1497 rspamd_cryptobox_fast_hash_init (rspamd_cryptobox_fast_hash_state_t *st,
1498 		guint64 seed)
1499 {
1500 	t1ha_context_t *rst = (t1ha_context_t *)st->opaque;
1501 	st->type = RSPAMD_CRYPTOBOX_T1HA;
1502 	t1ha2_init (rst, seed, 0);
1503 }
1504 
1505 void
rspamd_cryptobox_fast_hash_init_specific(rspamd_cryptobox_fast_hash_state_t * st,enum rspamd_cryptobox_fast_hash_type type,guint64 seed)1506 rspamd_cryptobox_fast_hash_init_specific (rspamd_cryptobox_fast_hash_state_t *st,
1507 										  enum rspamd_cryptobox_fast_hash_type type,
1508 										  guint64 seed)
1509 {
1510 	switch (type) {
1511 	case RSPAMD_CRYPTOBOX_T1HA:
1512 	case RSPAMD_CRYPTOBOX_HASHFAST:
1513 	case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
1514 		t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
1515 		st->type = RSPAMD_CRYPTOBOX_T1HA;
1516 		t1ha2_init (rst, seed, 0);
1517 		break;
1518 	}
1519 	case RSPAMD_CRYPTOBOX_XXHASH64: {
1520 		XXH64_state_t *xst = (XXH64_state_t *)  st->opaque;
1521 		st->type = RSPAMD_CRYPTOBOX_XXHASH64;
1522 		XXH64_reset (xst, seed);
1523 		break;
1524 	}
1525 	case RSPAMD_CRYPTOBOX_XXHASH32:
1526 	{
1527 		XXH32_state_t *xst = (XXH32_state_t *)  st->opaque;
1528 		st->type = RSPAMD_CRYPTOBOX_XXHASH32;
1529 		XXH32_reset (xst, seed);
1530 		break;
1531 	}
1532 	case RSPAMD_CRYPTOBOX_MUMHASH: {
1533 		struct _mum_iuf *iuf = (struct _mum_iuf *)  st->opaque;
1534 		st->type = RSPAMD_CRYPTOBOX_MUMHASH;
1535 		iuf->h = seed;
1536 		iuf->buf.ll = 0;
1537 		iuf->rem = 0;
1538 		break;
1539 	}
1540 	}
1541 }
1542 
1543 void
rspamd_cryptobox_fast_hash_update(rspamd_cryptobox_fast_hash_state_t * st,const void * data,gsize len)1544 rspamd_cryptobox_fast_hash_update (rspamd_cryptobox_fast_hash_state_t *st,
1545 		const void *data, gsize len)
1546 {
1547 	if (st->type == RSPAMD_CRYPTOBOX_T1HA) {
1548 		t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
1549 		t1ha2_update (rst, data, len);
1550 	}
1551 	else {
1552 		switch (st->type) {
1553 		case RSPAMD_CRYPTOBOX_XXHASH64: {
1554 			XXH64_state_t *xst = (XXH64_state_t *)  st->opaque;
1555 			XXH64_update (xst, data, len);
1556 			break;
1557 		}
1558 		case RSPAMD_CRYPTOBOX_XXHASH32:
1559 		{
1560 			XXH32_state_t *xst = (XXH32_state_t *)  st->opaque;
1561 			XXH32_update (xst, data, len);
1562 			break;
1563 		}
1564 		case RSPAMD_CRYPTOBOX_MUMHASH: {
1565 			struct _mum_iuf *iuf = (struct _mum_iuf *)  st->opaque;
1566 			gsize drem = len;
1567 			const guchar *p = data;
1568 
1569 			if (iuf->rem > 0) {
1570 				/* Process remainder */
1571 				if (drem >= iuf->rem) {
1572 					memcpy (iuf->buf.b + sizeof (iuf->buf.ll) - iuf->rem,
1573 							p, iuf->rem);
1574 					drem -= iuf->rem;
1575 					p += iuf->rem;
1576 					iuf->h = mum_hash_step (iuf->h, iuf->buf.ll);
1577 					iuf->rem = 0;
1578 				}
1579 				else {
1580 					memcpy (iuf->buf.b + sizeof (iuf->buf.ll) - iuf->rem, p, drem);
1581 					iuf->rem -= drem;
1582 					drem = 0;
1583 				}
1584 			}
1585 
1586 			while (drem >= sizeof (iuf->buf.ll)) {
1587 				memcpy (iuf->buf.b, p, sizeof (iuf->buf.ll));
1588 				iuf->h = mum_hash_step (iuf->h, iuf->buf.ll);
1589 				drem -= sizeof (iuf->buf.ll);
1590 				p += sizeof (iuf->buf.ll);
1591 			}
1592 
1593 			/* Leftover */
1594 			if (drem > 0) {
1595 				iuf->rem = sizeof (guint64) - drem;
1596 				iuf->buf.ll = 0;
1597 				memcpy (iuf->buf.b, p, drem);
1598 			}
1599 			break;
1600 		}
1601 		case RSPAMD_CRYPTOBOX_T1HA:
1602 		case RSPAMD_CRYPTOBOX_HASHFAST:
1603 		case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
1604 			t1ha_context_t *rst = (t1ha_context_t *)  st->opaque;
1605 			t1ha2_update (rst, data, len);
1606 			break;
1607 		}
1608 		}
1609 	}
1610 }
1611 
1612 guint64
rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t * st)1613 rspamd_cryptobox_fast_hash_final (rspamd_cryptobox_fast_hash_state_t *st)
1614 {
1615 	guint64 ret;
1616 
1617 	if (st->type == RSPAMD_CRYPTOBOX_T1HA) {
1618 		t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
1619 
1620 		return t1ha2_final (rst, NULL);
1621 	}
1622 	else {
1623 		switch (st->type) {
1624 		case RSPAMD_CRYPTOBOX_XXHASH64: {
1625 			XXH64_state_t *xst = (XXH64_state_t *)  st->opaque;
1626 			ret = XXH64_digest (xst);
1627 			break;
1628 		}
1629 		case RSPAMD_CRYPTOBOX_XXHASH32: {
1630 			XXH32_state_t *xst = (XXH32_state_t *)  st->opaque;
1631 			ret = XXH32_digest (xst);
1632 			break;
1633 		}
1634 		case RSPAMD_CRYPTOBOX_MUMHASH: {
1635 			struct _mum_iuf *iuf = (struct _mum_iuf *)  st->opaque;
1636 			iuf->h = mum_hash_step (iuf->h, iuf->buf.ll);
1637 			ret = mum_hash_finish (iuf->h);
1638 			break;
1639 		}
1640 		case RSPAMD_CRYPTOBOX_T1HA:
1641 		case RSPAMD_CRYPTOBOX_HASHFAST:
1642 		case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
1643 			t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
1644 
1645 			ret = t1ha2_final (rst, NULL);
1646 			break;
1647 		}
1648 		}
1649 	}
1650 
1651 	return ret;
1652 }
1653 
1654 /**
1655  * One in all function
1656  */
1657 static inline guint64
rspamd_cryptobox_fast_hash_machdep(const void * data,gsize len,guint64 seed)1658 rspamd_cryptobox_fast_hash_machdep (const void *data,
1659 		gsize len, guint64 seed)
1660 {
1661 	return t1ha2_atonce (data, len, seed);
1662 }
1663 
1664 static inline guint64
rspamd_cryptobox_fast_hash_indep(const void * data,gsize len,guint64 seed)1665 rspamd_cryptobox_fast_hash_indep (const void *data,
1666 		gsize len, guint64 seed)
1667 {
1668 	return t1ha2_atonce (data, len, seed);
1669 }
1670 
1671 guint64
rspamd_cryptobox_fast_hash(const void * data,gsize len,guint64 seed)1672 rspamd_cryptobox_fast_hash (const void *data,
1673 		gsize len, guint64 seed)
1674 {
1675 	return rspamd_cryptobox_fast_hash_machdep (data, len, seed);
1676 }
1677 
1678 guint64
rspamd_cryptobox_fast_hash_specific(enum rspamd_cryptobox_fast_hash_type type,const void * data,gsize len,guint64 seed)1679 rspamd_cryptobox_fast_hash_specific (
1680 		enum rspamd_cryptobox_fast_hash_type type,
1681 		const void *data,
1682 		gsize len, guint64 seed)
1683 {
1684 	switch (type) {
1685 	case RSPAMD_CRYPTOBOX_XXHASH32:
1686 		return XXH32 (data, len, seed);
1687 	case RSPAMD_CRYPTOBOX_XXHASH64:
1688 		return XXH64 (data, len, seed);
1689 	case RSPAMD_CRYPTOBOX_MUMHASH:
1690 		return mum_hash (data, len, seed);
1691 	case RSPAMD_CRYPTOBOX_T1HA:
1692 		return t1ha2_atonce (data, len, seed);
1693 	case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT:
1694 		return rspamd_cryptobox_fast_hash_indep (data, len, seed);
1695 	case RSPAMD_CRYPTOBOX_HASHFAST:
1696 	default:
1697 		return rspamd_cryptobox_fast_hash_machdep (data, len, seed);
1698 	}
1699 }
1700