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