12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778 |
- /*
- * Copyright 2024 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /* Workaround for memset_s */
- #ifdef __APPLE__
- #define __STDC_WANT_LIB_EXT1__ 1
- #include <string.h>
- #endif
-
- #include "config.h"
- #include "cryptobox.h"
- #include "platform_config.h"
- #include "chacha20/chacha.h"
- #include "catena/catena.h"
- #include "base64/base64.h"
- #include "ottery.h"
- #include "printf.h"
- #define XXH_INLINE_ALL
- #define XXH_PRIVATE_API
- #include "xxhash.h"
- #define MUM_TARGET_INDEPENDENT_HASH 1 /* For 32/64 bit equal hashes */
- #include "../../contrib/mumhash/mum.h"
- #include "../../contrib/t1ha/t1ha.h"
- #ifdef HAVE_CPUID_H
- #include <cpuid.h>
- #endif
- #ifdef HAVE_OPENSSL
- #include <openssl/opensslv.h>
- /* Openssl >= 1.0.1d is required for GCM verification */
- #if OPENSSL_VERSION_NUMBER >= 0x1000104fL
- #define HAVE_USABLE_OPENSSL 1
- #endif
- #endif
-
- #ifdef HAVE_USABLE_OPENSSL
- #include <openssl/evp.h>
- #include <openssl/ec.h>
- #include <openssl/ecdh.h>
- #include <openssl/ecdsa.h>
- #include <openssl/rand.h>
- #define CRYPTOBOX_CURVE_NID NID_X9_62_prime256v1
- #endif
-
- #include <signal.h>
- #include <setjmp.h>
- #include <stdalign.h>
-
- #include <sodium.h>
-
- unsigned cpu_config = 0;
-
- static gboolean cryptobox_loaded = FALSE;
-
- static const guchar n0[16] = {0};
-
- #define CRYPTOBOX_ALIGNMENT 16
- #define cryptobox_align_ptr(p, a) \
- (void *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
-
- static void
- rspamd_cryptobox_cpuid(gint cpu[4], gint info)
- {
- uint32_t __attribute__((unused)) eax, __attribute__((unused)) ecx = 0, __attribute__((unused)) ebx = 0, __attribute__((unused)) edx = 0;
-
- eax = info;
- #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
- #if defined(__i386__) && defined(__PIC__)
-
- /* in case of PIC under 32-bit EBX cannot be clobbered */
-
- __asm__ volatile("movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi"
- : "=D"(ebx),
- "+a"(eax), "+c"(ecx), "=d"(edx));
- #else
- __asm__ volatile("cpuid"
- : "+b"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx));
- #endif
-
- cpu[0] = eax;
- cpu[1] = ebx;
- cpu[2] = ecx;
- cpu[3] = edx;
- #else
- memset(cpu, 0, sizeof(gint) * 4);
- #endif
- }
-
- static sig_atomic_t ok = 0;
- static jmp_buf j;
-
- __attribute__((noreturn)) static void
- rspamd_cryptobox_ill_handler(int signo)
- {
- ok = 0;
- longjmp(j, -1);
- }
-
- static gboolean
- rspamd_cryptobox_test_instr(gint instr)
- {
- void (*old_handler)(int);
- uint32_t rd;
-
- #if defined(__GNUC__)
- ok = 1;
- old_handler = signal(SIGILL, rspamd_cryptobox_ill_handler);
-
- if (setjmp(j) != 0) {
- signal(SIGILL, old_handler);
-
- return FALSE;
- }
-
- switch (instr) {
- #if defined HAVE_SSE2 && defined(__x86_64__)
- case CPUID_SSE2:
- __asm__ volatile("psubb %xmm0, %xmm0");
- break;
- case CPUID_RDRAND:
- /* Use byte code here for compatibility */
- __asm__ volatile(".byte 0x0f,0xc7,0xf0; setc %1"
- : "=a"(rd), "=qm"(ok)
- :
- : "edx");
- break;
- #endif
- #ifdef HAVE_SSE3
- case CPUID_SSE3:
- __asm__ volatile("movshdup %xmm0, %xmm0");
- break;
- #endif
- #ifdef HAVE_SSSE3
- case CPUID_SSSE3:
- __asm__ volatile("pshufb %xmm0, %xmm0");
- break;
- #endif
- #ifdef HAVE_SSE41
- case CPUID_SSE41:
- __asm__ volatile("pcmpeqq %xmm0, %xmm0");
- break;
- #endif
- #if defined HAVE_SSE42 && defined(__x86_64__)
- case CPUID_SSE42:
- __asm__ volatile("pushq %rax\n"
- "xorq %rax, %rax\n"
- "crc32 %rax, %rax\n"
- "popq %rax");
- break;
- #endif
- #ifdef HAVE_AVX
- case CPUID_AVX:
- __asm__ volatile("vpaddq %xmm0, %xmm0, %xmm0");
- break;
- #endif
- #ifdef HAVE_AVX2
- case CPUID_AVX2:
- __asm__ volatile("vpaddq %ymm0, %ymm0, %ymm0");
- break;
- #endif
- default:
- return FALSE;
- break;
- }
-
- signal(SIGILL, old_handler);
- #endif
-
- (void) rd; /* Silence warning */
-
- /* We actually never return here if SIGILL has been caught */
- return ok == 1;
- }
-
- struct rspamd_cryptobox_library_ctx *
- rspamd_cryptobox_init(void)
- {
- gint cpu[4], nid;
- const uint32_t osxsave_mask = (1 << 27);
- const uint32_t fma_movbe_osxsave_mask = ((1 << 12) | (1 << 22) | (1 << 27));
- const uint32_t avx2_bmi12_mask = (1 << 5) | (1 << 3) | (1 << 8);
- gulong bit;
- static struct rspamd_cryptobox_library_ctx *ctx;
- GString *buf;
-
- if (cryptobox_loaded) {
- /* Ignore reload attempts */
- return ctx;
- }
-
- cryptobox_loaded = TRUE;
- ctx = g_malloc0(sizeof(*ctx));
-
- rspamd_cryptobox_cpuid(cpu, 0);
- nid = cpu[0];
- rspamd_cryptobox_cpuid(cpu, 1);
-
- if (nid > 1) {
- if ((cpu[3] & ((uint32_t) 1 << 26))) {
- if (rspamd_cryptobox_test_instr(CPUID_SSE2)) {
- cpu_config |= CPUID_SSE2;
- }
- }
- if ((cpu[2] & ((uint32_t) 1 << 0))) {
- if (rspamd_cryptobox_test_instr(CPUID_SSE3)) {
- cpu_config |= CPUID_SSE3;
- }
- }
- if ((cpu[2] & ((uint32_t) 1 << 9))) {
- if (rspamd_cryptobox_test_instr(CPUID_SSSE3)) {
- cpu_config |= CPUID_SSSE3;
- }
- }
- if ((cpu[2] & ((uint32_t) 1 << 19))) {
- if (rspamd_cryptobox_test_instr(CPUID_SSE41)) {
- cpu_config |= CPUID_SSE41;
- }
- }
- if ((cpu[2] & ((uint32_t) 1 << 20))) {
- if (rspamd_cryptobox_test_instr(CPUID_SSE42)) {
- cpu_config |= CPUID_SSE42;
- }
- }
- if ((cpu[2] & ((uint32_t) 1 << 30))) {
- if (rspamd_cryptobox_test_instr(CPUID_RDRAND)) {
- cpu_config |= CPUID_RDRAND;
- }
- }
-
- /* OSXSAVE */
- if ((cpu[2] & osxsave_mask) == osxsave_mask) {
- if ((cpu[2] & ((uint32_t) 1 << 28))) {
- if (rspamd_cryptobox_test_instr(CPUID_AVX)) {
- cpu_config |= CPUID_AVX;
- }
- }
-
- if (nid >= 7 &&
- (cpu[2] & fma_movbe_osxsave_mask) == fma_movbe_osxsave_mask) {
- rspamd_cryptobox_cpuid(cpu, 7);
-
- if ((cpu[1] & avx2_bmi12_mask) == avx2_bmi12_mask) {
- if (rspamd_cryptobox_test_instr(CPUID_AVX2)) {
- cpu_config |= CPUID_AVX2;
- }
- }
- }
- }
- }
-
- buf = g_string_new("");
-
- for (bit = 0x1; bit != 0; bit <<= 1) {
- if (cpu_config & bit) {
- switch (bit) {
- case CPUID_SSE2:
- rspamd_printf_gstring(buf, "sse2, ");
- break;
- case CPUID_SSE3:
- rspamd_printf_gstring(buf, "sse3, ");
- break;
- case CPUID_SSSE3:
- rspamd_printf_gstring(buf, "ssse3, ");
- break;
- case CPUID_SSE41:
- rspamd_printf_gstring(buf, "sse4.1, ");
- break;
- case CPUID_SSE42:
- rspamd_printf_gstring(buf, "sse4.2, ");
- break;
- case CPUID_AVX:
- rspamd_printf_gstring(buf, "avx, ");
- break;
- case CPUID_AVX2:
- rspamd_printf_gstring(buf, "avx2, ");
- break;
- case CPUID_RDRAND:
- rspamd_printf_gstring(buf, "rdrand, ");
- break;
- default:
- break; /* Silence warning */
- }
- }
- }
-
- if (buf->len > 2) {
- /* Trim last chars */
- g_string_erase(buf, buf->len - 2, 2);
- }
-
- ctx->cpu_extensions = buf->str;
- g_string_free(buf, FALSE);
- ctx->cpu_config = cpu_config;
- g_assert(sodium_init() != -1);
-
- ctx->chacha20_impl = chacha_load();
- ctx->base64_impl = base64_load();
- #if defined(HAVE_USABLE_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER))
- /* Needed for old openssl api, not sure about LibreSSL */
- ERR_load_EC_strings();
- ERR_load_RAND_strings();
- ERR_load_EVP_strings();
- #endif
-
- return ctx;
- }
-
- void rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx *ctx)
- {
- if (ctx) {
- g_free(ctx->cpu_extensions);
- g_free(ctx);
- }
- }
-
- void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- ottery_rand_bytes(sk, rspamd_cryptobox_MAX_SKBYTES);
- sk[0] &= 248;
- sk[31] &= 127;
- sk[31] |= 64;
-
- crypto_scalarmult_base(pk, sk);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EC_KEY *ec_sec;
- const BIGNUM *bn_sec;
-
- const EC_POINT *ec_pub;
- gsize len;
-
- ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- g_assert(ec_sec != NULL);
- g_assert(EC_KEY_generate_key(ec_sec) != 0);
-
- bn_sec = EC_KEY_get0_private_key(ec_sec);
- g_assert(bn_sec != NULL);
- ec_pub = EC_KEY_get0_public_key(ec_sec);
- g_assert(ec_pub != NULL);
- #if OPENSSL_VERSION_MAJOR >= 3
- unsigned char *buf = NULL; /* Thanks openssl for this API (no) */
- len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub,
- POINT_CONVERSION_UNCOMPRESSED, &buf, NULL);
- g_assert(len <= (gint) rspamd_cryptobox_pk_bytes(mode));
- memcpy(pk, buf, len);
- OPENSSL_free(buf);
- #else
- BIGNUM *bn_pub;
- bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec),
- ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
- len = BN_num_bytes(bn_pub);
- g_assert(len <= (gint) rspamd_cryptobox_pk_bytes(mode));
- BN_bn2bin(bn_pub, pk);
- BN_free(bn_pub);
- #endif
-
- len = BN_num_bytes(bn_sec);
- g_assert(len <= (gint) sizeof(rspamd_sk_t));
- BN_bn2bin(bn_sec, sk);
-
- EC_KEY_free(ec_sec);
- #endif
- }
- }
-
- void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_sign_keypair(pk, sk);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EC_KEY *ec_sec;
- const BIGNUM *bn_sec;
- const EC_POINT *ec_pub;
- gsize len;
-
- ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- g_assert(ec_sec != NULL);
- g_assert(EC_KEY_generate_key(ec_sec) != 0);
-
- bn_sec = EC_KEY_get0_private_key(ec_sec);
- g_assert(bn_sec != NULL);
- ec_pub = EC_KEY_get0_public_key(ec_sec);
- g_assert(ec_pub != NULL);
-
- #if OPENSSL_VERSION_MAJOR >= 3
- unsigned char *buf = NULL; /* Thanks openssl for this API (no) */
- len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub,
- POINT_CONVERSION_UNCOMPRESSED, &buf, NULL);
- g_assert(len <= (gint) rspamd_cryptobox_pk_bytes(mode));
- memcpy(pk, buf, len);
- OPENSSL_free(buf);
- #else
- BIGNUM *bn_pub;
- bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec),
- ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
- len = BN_num_bytes(bn_pub);
- g_assert(len <= (gint) rspamd_cryptobox_pk_bytes(mode));
- BN_bn2bin(bn_pub, pk);
- BN_free(bn_pub);
- #endif
-
- len = BN_num_bytes(bn_sec);
- g_assert(len <= (gint) sizeof(rspamd_sk_t));
- BN_bn2bin(bn_sec, sk);
- EC_KEY_free(ec_sec);
- #endif
- }
- }
-
- #if OPENSSL_VERSION_MAJOR >= 3
- /* Compatibility function for OpenSSL 3.0 - thanks for breaking all API one more time */
- EC_POINT *ec_point_bn2point_compat(const EC_GROUP *group,
- const BIGNUM *bn, EC_POINT *point, BN_CTX *ctx)
- {
- size_t buf_len = 0;
- unsigned char *buf;
- EC_POINT *ret;
-
- if ((buf_len = BN_num_bytes(bn)) == 0)
- buf_len = 1;
- if ((buf = OPENSSL_malloc(buf_len)) == NULL) {
- return NULL;
- }
-
- if (!BN_bn2binpad(bn, buf, buf_len)) {
- OPENSSL_free(buf);
- return NULL;
- }
-
- if (point == NULL) {
- if ((ret = EC_POINT_new(group)) == NULL) {
- OPENSSL_free(buf);
- return NULL;
- }
- }
- else
- ret = point;
-
- if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) {
- if (ret != point)
- EC_POINT_clear_free(ret);
- OPENSSL_free(buf);
- return NULL;
- }
-
- OPENSSL_free(buf);
- return ret;
- }
- #else
- #define ec_point_bn2point_compat EC_POINT_bn2point
- #endif
-
- void rspamd_cryptobox_nm(rspamd_nm_t nm,
- const rspamd_pk_t pk, const rspamd_sk_t sk,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- guchar s[32];
- guchar e[32];
-
- memcpy(e, sk, 32);
- e[0] &= 248;
- e[31] &= 127;
- e[31] |= 64;
-
- if (crypto_scalarmult(s, e, pk) != -1) {
- hchacha(s, n0, nm, 20);
- }
-
- rspamd_explicit_memzero(e, 32);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EC_KEY *lk;
- EC_POINT *ec_pub;
- BIGNUM *bn_pub, *bn_sec;
- gint len;
- guchar s[32];
-
- lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- g_assert(lk != NULL);
-
- bn_pub = BN_bin2bn(pk, rspamd_cryptobox_pk_bytes(mode), NULL);
- g_assert(bn_pub != NULL);
- bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL);
- g_assert(bn_sec != NULL);
-
- g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1);
- ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL);
- g_assert(ec_pub != NULL);
- len = ECDH_compute_key(s, sizeof(s), ec_pub, lk, NULL);
- g_assert(len == sizeof(s));
-
- /* Still do hchacha iteration since we are not using SHA1 KDF */
- hchacha(s, n0, nm, 20);
-
- EC_KEY_free(lk);
- EC_POINT_free(ec_pub);
- BN_free(bn_sec);
- BN_free(bn_pub);
- #endif
- }
- }
-
- 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)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_sign_detached(sig, siglen_p, m, mlen, sk);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EC_KEY *lk;
- BIGNUM *bn_sec;
- EVP_MD_CTX *sha_ctx;
- unsigned char h[64];
- guint diglen = rspamd_cryptobox_signature_bytes(mode);
-
- /* Prehash */
- sha_ctx = EVP_MD_CTX_create();
- g_assert(EVP_DigestInit(sha_ctx, EVP_sha512()) == 1);
- EVP_DigestUpdate(sha_ctx, m, mlen);
- EVP_DigestFinal(sha_ctx, h, NULL);
-
- /* Key setup */
- lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- g_assert(lk != NULL);
- bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL);
- g_assert(bn_sec != NULL);
- g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1);
-
- /* ECDSA */
- g_assert(ECDSA_sign(0, h, sizeof(h), sig, &diglen, lk) == 1);
- g_assert(diglen <= sizeof(rspamd_signature_t));
-
- if (siglen_p) {
- *siglen_p = diglen;
- }
-
- EC_KEY_free(lk);
- EVP_MD_CTX_destroy(sha_ctx);
- BN_free(bn_sec);
- #endif
- }
- }
-
- bool rspamd_cryptobox_verify(const guchar *sig,
- gsize siglen,
- const guchar *m,
- gsize mlen,
- const rspamd_pk_t pk,
- enum rspamd_cryptobox_mode mode)
- {
- bool ret = false;
-
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- if (siglen == rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519)) {
- ret = (crypto_sign_verify_detached(sig, m, mlen, pk) == 0);
- }
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EC_KEY *lk;
- EC_POINT *ec_pub;
- BIGNUM *bn_pub;
- EVP_MD_CTX *sha_ctx;
- unsigned char h[64];
-
- /* Prehash */
- sha_ctx = EVP_MD_CTX_create();
- g_assert(EVP_DigestInit(sha_ctx, EVP_sha512()) == 1);
- EVP_DigestUpdate(sha_ctx, m, mlen);
- EVP_DigestFinal(sha_ctx, h, NULL);
-
- /* Key setup */
- lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- g_assert(lk != NULL);
- bn_pub = BN_bin2bn(pk, rspamd_cryptobox_pk_bytes(mode), NULL);
- g_assert(bn_pub != NULL);
- ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL);
- g_assert(ec_pub != NULL);
- g_assert(EC_KEY_set_public_key(lk, ec_pub) == 1);
-
- /* ECDSA */
- ret = ECDSA_verify(0, h, sizeof(h), sig, siglen, lk) == 1;
-
- EC_KEY_free(lk);
- EVP_MD_CTX_destroy(sha_ctx);
- BN_free(bn_pub);
- EC_POINT_free(ec_pub);
- #endif
- }
-
- return ret;
- }
-
- static gsize
- rspamd_cryptobox_encrypt_ctx_len(enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return sizeof(chacha_state) + CRYPTOBOX_ALIGNMENT;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- return sizeof(EVP_CIPHER_CTX *) + CRYPTOBOX_ALIGNMENT;
- #endif
- }
-
- return 0;
- }
-
- static gsize
- rspamd_cryptobox_auth_ctx_len(enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return sizeof(crypto_onetimeauth_state) + RSPAMD_ALIGNOF(crypto_onetimeauth_state);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- return sizeof(void *);
- #endif
- }
-
- return 0;
- }
-
- static void *
- rspamd_cryptobox_encrypt_init(void *enc_ctx, const rspamd_nonce_t nonce,
- const rspamd_nm_t nm,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- xchacha_init(s,
- (const chacha_key *) nm,
- (const chacha_iv24 *) nonce,
- 20);
-
- return s;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- memset(s, 0, sizeof(*s));
- *s = EVP_CIPHER_CTX_new();
- g_assert(EVP_EncryptInit_ex(*s, EVP_aes_256_gcm(), NULL, NULL, NULL) == 1);
- g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_IVLEN,
- rspamd_cryptobox_nonce_bytes(mode), NULL) == 1);
- g_assert(EVP_EncryptInit_ex(*s, NULL, NULL, nm, nonce) == 1);
-
- return s;
- #endif
- }
-
- return NULL;
- }
-
- static void *
- rspamd_cryptobox_auth_init(void *auth_ctx, void *enc_ctx,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
- guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- memset(subkey, 0, sizeof(subkey));
- chacha_update(enc_ctx, subkey, subkey, sizeof(subkey));
- crypto_onetimeauth_init(mac_ctx, subkey);
- rspamd_explicit_memzero(subkey, sizeof(subkey));
-
- return mac_ctx;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- auth_ctx = enc_ctx;
-
- return auth_ctx;
- #endif
- }
-
- return NULL;
- }
-
- static gboolean
- rspamd_cryptobox_encrypt_update(void *enc_ctx, const guchar *in, gsize inlen,
- guchar *out, gsize *outlen,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- gsize r;
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
-
- r = chacha_update(s, in, out, inlen);
-
- if (outlen != NULL) {
- *outlen = r;
- }
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = enc_ctx;
- gint r;
-
- r = inlen;
- g_assert(EVP_EncryptUpdate(*s, out, &r, in, inlen) == 1);
-
- if (outlen) {
- *outlen = r;
- }
-
- return TRUE;
- #endif
- }
-
- return FALSE;
- }
-
- static gboolean
- rspamd_cryptobox_auth_update(void *auth_ctx, const guchar *in, gsize inlen,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- crypto_onetimeauth_update(mac_ctx, in, inlen);
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- return TRUE;
- #endif
- }
-
- return FALSE;
- }
-
- static gsize
- rspamd_cryptobox_encrypt_final(void *enc_ctx, guchar *out, gsize remain,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- return chacha_final(s, out);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = enc_ctx;
- gint r = remain;
-
- g_assert(EVP_EncryptFinal_ex(*s, out, &r) == 1);
-
- return r;
- #endif
- }
-
- return 0;
- }
-
- static gboolean
- rspamd_cryptobox_auth_final(void *auth_ctx, rspamd_mac_t sig,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- crypto_onetimeauth_final(mac_ctx, sig);
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = auth_ctx;
-
- g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_GET_TAG,
- sizeof(rspamd_mac_t), sig) == 1);
-
- return TRUE;
- #endif
- }
-
- return FALSE;
- }
-
- static void *
- rspamd_cryptobox_decrypt_init(void *enc_ctx, const rspamd_nonce_t nonce,
- const rspamd_nm_t nm,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
-
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- xchacha_init(s,
- (const chacha_key *) nm,
- (const chacha_iv24 *) nonce,
- 20);
-
- return s;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- memset(s, 0, sizeof(*s));
- *s = EVP_CIPHER_CTX_new();
- g_assert(EVP_DecryptInit_ex(*s, EVP_aes_256_gcm(), NULL, NULL, NULL) == 1);
- g_assert(EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_IVLEN,
- rspamd_cryptobox_nonce_bytes(mode), NULL) == 1);
- g_assert(EVP_DecryptInit_ex(*s, NULL, NULL, nm, nonce) == 1);
-
- return s;
- #endif
- }
-
- return NULL;
- }
-
- static void *
- rspamd_cryptobox_auth_verify_init(void *auth_ctx, void *enc_ctx,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
- guchar RSPAMD_ALIGNED(32) subkey[CHACHA_BLOCKBYTES];
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- memset(subkey, 0, sizeof(subkey));
- chacha_update(enc_ctx, subkey, subkey, sizeof(subkey));
- crypto_onetimeauth_init(mac_ctx, subkey);
- rspamd_explicit_memzero(subkey, sizeof(subkey));
-
- return mac_ctx;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- auth_ctx = enc_ctx;
-
- return auth_ctx;
- #endif
- }
-
- return NULL;
- }
-
- static gboolean
- rspamd_cryptobox_decrypt_update(void *enc_ctx, const guchar *in, gsize inlen,
- guchar *out, gsize *outlen,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- gsize r;
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- r = chacha_update(s, in, out, inlen);
-
- if (outlen != NULL) {
- *outlen = r;
- }
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = enc_ctx;
- gint r;
-
- r = outlen ? *outlen : inlen;
- g_assert(EVP_DecryptUpdate(*s, out, &r, in, inlen) == 1);
-
- if (outlen) {
- *outlen = r;
- }
-
- return TRUE;
- #endif
- }
- }
-
- static gboolean
- rspamd_cryptobox_auth_verify_update(void *auth_ctx,
- const guchar *in, gsize inlen,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- crypto_onetimeauth_update(mac_ctx, in, inlen);
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- /* We do not need to authenticate as a separate process */
- return TRUE;
- #else
- #endif
- }
-
- return FALSE;
- }
-
- static gboolean
- rspamd_cryptobox_decrypt_final(void *enc_ctx, guchar *out, gsize remain,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- chacha_state *s;
-
- s = cryptobox_align_ptr(enc_ctx, CRYPTOBOX_ALIGNMENT);
- chacha_final(s, out);
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = enc_ctx;
- gint r = remain;
-
- if (EVP_DecryptFinal_ex(*s, out, &r) < 0) {
- return FALSE;
- }
-
- return TRUE;
- #endif
- }
-
- return FALSE;
- }
-
- static gboolean
- rspamd_cryptobox_auth_verify_final(void *auth_ctx, const rspamd_mac_t sig,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- rspamd_mac_t mac;
- crypto_onetimeauth_state *mac_ctx;
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- crypto_onetimeauth_final(mac_ctx, mac);
-
- if (crypto_verify_16(mac, sig) != 0) {
- return FALSE;
- }
-
- return TRUE;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = auth_ctx;
-
- if (EVP_CIPHER_CTX_ctrl(*s, EVP_CTRL_GCM_SET_TAG, 16, (guchar *) sig) != 1) {
- return FALSE;
- }
-
- return TRUE;
- #endif
- }
-
- return FALSE;
- }
-
-
- static void
- rspamd_cryptobox_cleanup(void *enc_ctx, void *auth_ctx,
- enum rspamd_cryptobox_mode mode)
- {
- if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- crypto_onetimeauth_state *mac_ctx;
-
- mac_ctx = cryptobox_align_ptr(auth_ctx, CRYPTOBOX_ALIGNMENT);
- rspamd_explicit_memzero(mac_ctx, sizeof(*mac_ctx));
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- EVP_CIPHER_CTX **s = enc_ctx;
-
- EVP_CIPHER_CTX_cleanup(*s);
- EVP_CIPHER_CTX_free(*s);
- #endif
- }
- }
-
- void 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)
- {
- gsize r;
- void *enc_ctx, *auth_ctx;
-
- enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode));
- auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode));
-
- enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm, mode);
- auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx, mode);
-
- rspamd_cryptobox_encrypt_update(enc_ctx, data, len, data, &r, mode);
- rspamd_cryptobox_encrypt_final(enc_ctx, data + r, len - r, mode);
-
- rspamd_cryptobox_auth_update(auth_ctx, data, len, mode);
- rspamd_cryptobox_auth_final(auth_ctx, sig, mode);
-
- rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode);
- }
-
- static void
- rspamd_cryptobox_flush_outbuf(struct rspamd_cryptobox_segment *st,
- const guchar *buf, gsize len, gsize offset)
- {
- gsize cpy_len;
-
- while (len > 0) {
- cpy_len = MIN(len, st->len - offset);
- memcpy(st->data + offset, buf, cpy_len);
- st++;
- buf += cpy_len;
- len -= cpy_len;
- offset = 0;
- }
- }
-
- 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)
- {
- struct rspamd_cryptobox_segment *cur = segments, *start_seg = segments;
- guchar outbuf[CHACHA_BLOCKBYTES * 16];
- void *enc_ctx, *auth_ctx;
- guchar *out, *in;
- gsize r, remain, inremain, seg_offset;
-
- enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode));
- auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode));
-
- enc_ctx = rspamd_cryptobox_encrypt_init(enc_ctx, nonce, nm, mode);
- auth_ctx = rspamd_cryptobox_auth_init(auth_ctx, enc_ctx, mode);
-
- remain = sizeof(outbuf);
- out = outbuf;
- inremain = cur->len;
- seg_offset = 0;
-
- for (;;) {
- if (cur - segments == (gint) cnt) {
- break;
- }
-
- if (cur->len <= remain) {
- memcpy(out, cur->data, cur->len);
- remain -= cur->len;
- out += cur->len;
- cur++;
-
- if (remain == 0) {
- rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf),
- outbuf, NULL, mode);
- rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf),
- mode);
- rspamd_cryptobox_flush_outbuf(start_seg, outbuf,
- sizeof(outbuf), seg_offset);
- start_seg = cur;
- seg_offset = 0;
- remain = sizeof(outbuf);
- out = outbuf;
- }
- }
- else {
- memcpy(out, cur->data, remain);
- rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf),
- outbuf, NULL, mode);
- rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf),
- mode);
- rspamd_cryptobox_flush_outbuf(start_seg, outbuf, sizeof(outbuf),
- seg_offset);
- seg_offset = 0;
-
- inremain = cur->len - remain;
- in = cur->data + remain;
- out = outbuf;
- remain = 0;
- start_seg = cur;
-
- while (inremain > 0) {
- if (sizeof(outbuf) <= inremain) {
- memcpy(outbuf, in, sizeof(outbuf));
- rspamd_cryptobox_encrypt_update(enc_ctx,
- outbuf,
- sizeof(outbuf),
- outbuf,
- NULL,
- mode);
- rspamd_cryptobox_auth_update(auth_ctx,
- outbuf,
- sizeof(outbuf),
- mode);
- memcpy(in, outbuf, sizeof(outbuf));
- in += sizeof(outbuf);
- inremain -= sizeof(outbuf);
- remain = sizeof(outbuf);
- }
- else {
- memcpy(outbuf, in, inremain);
- remain = sizeof(outbuf) - inremain;
- out = outbuf + inremain;
- inremain = 0;
- }
- }
-
- seg_offset = cur->len - (sizeof(outbuf) - remain);
- cur++;
- }
- }
-
- rspamd_cryptobox_encrypt_update(enc_ctx, outbuf, sizeof(outbuf) - remain,
- outbuf, &r, mode);
- out = outbuf + r;
- rspamd_cryptobox_encrypt_final(enc_ctx, out, sizeof(outbuf) - remain - r,
- mode);
-
- rspamd_cryptobox_auth_update(auth_ctx, outbuf, sizeof(outbuf) - remain,
- mode);
- rspamd_cryptobox_auth_final(auth_ctx, sig, mode);
-
- rspamd_cryptobox_flush_outbuf(start_seg, outbuf, sizeof(outbuf) - remain,
- seg_offset);
- rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode);
- }
-
- 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)
- {
- gsize r = 0;
- gboolean ret = TRUE;
- void *enc_ctx, *auth_ctx;
-
- enc_ctx = g_alloca(rspamd_cryptobox_encrypt_ctx_len(mode));
- auth_ctx = g_alloca(rspamd_cryptobox_auth_ctx_len(mode));
-
- enc_ctx = rspamd_cryptobox_decrypt_init(enc_ctx, nonce, nm, mode);
- auth_ctx = rspamd_cryptobox_auth_verify_init(auth_ctx, enc_ctx, mode);
-
- rspamd_cryptobox_auth_verify_update(auth_ctx, data, len, mode);
-
- if (!rspamd_cryptobox_auth_verify_final(auth_ctx, sig, mode)) {
- ret = FALSE;
- }
- else {
- rspamd_cryptobox_decrypt_update(enc_ctx, data, len, data, &r, mode);
- ret = rspamd_cryptobox_decrypt_final(enc_ctx, data + r, len - r, mode);
- }
-
- rspamd_cryptobox_cleanup(enc_ctx, auth_ctx, mode);
-
- return ret;
- }
-
- 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)
- {
- guchar nm[rspamd_cryptobox_MAX_NMBYTES];
- gboolean ret;
-
- rspamd_cryptobox_nm(nm, pk, sk, mode);
- ret = rspamd_cryptobox_decrypt_nm_inplace(data, len, nonce, nm, sig, mode);
-
- rspamd_explicit_memzero(nm, sizeof(nm));
-
- return ret;
- }
-
- 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)
- {
- guchar nm[rspamd_cryptobox_MAX_NMBYTES];
-
- rspamd_cryptobox_nm(nm, pk, sk, mode);
- rspamd_cryptobox_encrypt_nm_inplace(data, len, nonce, nm, sig, mode);
- rspamd_explicit_memzero(nm, sizeof(nm));
- }
-
- 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)
- {
- guchar nm[rspamd_cryptobox_MAX_NMBYTES];
-
- rspamd_cryptobox_nm(nm, pk, sk, mode);
- rspamd_cryptobox_encryptv_nm_inplace(segments, cnt, nonce, nm, sig, mode);
- rspamd_explicit_memzero(nm, sizeof(nm));
- }
-
-
- void rspamd_cryptobox_siphash(unsigned char *out, const unsigned char *in,
- unsigned long long inlen,
- const rspamd_sipkey_t k)
- {
- crypto_shorthash_siphash24(out, in, inlen, k);
- }
-
- /*
- * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
- * Code based on IEEE Std 802.11-2007, Annex H.4.2.
- */
- 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)
- {
- guint8 *asalt, obuf[crypto_generichash_blake2b_BYTES_MAX];
- guint8 d1[crypto_generichash_blake2b_BYTES_MAX],
- d2[crypto_generichash_blake2b_BYTES_MAX];
- unsigned int i, j;
- unsigned int count;
- gsize r;
-
- if (rounds < 1 || key_len == 0) {
- return FALSE;
- }
- if (salt_len == 0 || salt_len > G_MAXSIZE - 4) {
- return FALSE;
- }
-
- asalt = g_malloc(salt_len + 4);
- memcpy(asalt, salt, salt_len);
-
- for (count = 1; key_len > 0; count++) {
- asalt[salt_len + 0] = (count >> 24) & 0xff;
- asalt[salt_len + 1] = (count >> 16) & 0xff;
- asalt[salt_len + 2] = (count >> 8) & 0xff;
- asalt[salt_len + 3] = count & 0xff;
-
- if (pass_len <= crypto_generichash_blake2b_KEYBYTES_MAX) {
- crypto_generichash_blake2b(d1, sizeof(d1), asalt, salt_len + 4,
- pass, pass_len);
- }
- else {
- guint8 k[crypto_generichash_blake2b_BYTES_MAX];
-
- /*
- * We use additional blake2 iteration to store large key
- * XXX: it is not compatible with the original implementation but safe
- */
- crypto_generichash_blake2b(k, sizeof(k), pass, pass_len,
- NULL, 0);
- crypto_generichash_blake2b(d1, sizeof(d1), asalt, salt_len + 4,
- k, sizeof(k));
- }
-
- memcpy(obuf, d1, sizeof(obuf));
-
- for (i = 1; i < rounds; i++) {
- if (pass_len <= crypto_generichash_blake2b_KEYBYTES_MAX) {
- crypto_generichash_blake2b(d2, sizeof(d2), d1, sizeof(d1),
- pass, pass_len);
- }
- else {
- guint8 k[crypto_generichash_blake2b_BYTES_MAX];
-
- /*
- * We use additional blake2 iteration to store large key
- * XXX: it is not compatible with the original implementation but safe
- */
- crypto_generichash_blake2b(k, sizeof(k), pass, pass_len,
- NULL, 0);
- crypto_generichash_blake2b(d2, sizeof(d2), d1, sizeof(d1),
- k, sizeof(k));
- }
-
- memcpy(d1, d2, sizeof(d1));
-
- for (j = 0; j < sizeof(obuf); j++) {
- obuf[j] ^= d1[j];
- }
- }
-
- r = MIN(key_len, crypto_generichash_blake2b_BYTES_MAX);
- memcpy(key, obuf, r);
- key += r;
- key_len -= r;
- }
-
- rspamd_explicit_memzero(asalt, salt_len + 4);
- g_free(asalt);
- rspamd_explicit_memzero(d1, sizeof(d1));
- rspamd_explicit_memzero(d2, sizeof(d2));
- rspamd_explicit_memzero(obuf, sizeof(obuf));
-
- return TRUE;
- }
-
- 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)
- {
- gboolean ret = FALSE;
-
- switch (type) {
- case RSPAMD_CRYPTOBOX_CATENA:
- if (catena(pass, pass_len, salt, salt_len, "rspamd", 6,
- 4, complexity, complexity, key_len, key) == 0) {
- ret = TRUE;
- }
- break;
- case RSPAMD_CRYPTOBOX_PBKDF2:
- default:
- ret = rspamd_cryptobox_pbkdf2(pass, pass_len, salt, salt_len, key,
- key_len, complexity);
- break;
- }
-
- return ret;
- }
-
- guint rspamd_cryptobox_pk_bytes(enum rspamd_cryptobox_mode mode)
- {
- if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return 32;
- }
- else {
- return 65;
- }
- }
-
- guint rspamd_cryptobox_pk_sig_bytes(enum rspamd_cryptobox_mode mode)
- {
- if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return 32;
- }
- else {
- return 65;
- }
- }
-
- guint rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode)
- {
- if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return 24;
- }
- else {
- return 16;
- }
- }
-
-
- guint rspamd_cryptobox_sk_bytes(enum rspamd_cryptobox_mode mode)
- {
- return 32;
- }
-
- guint rspamd_cryptobox_sk_sig_bytes(enum rspamd_cryptobox_mode mode)
- {
- if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return 64;
- }
- else {
- return 32;
- }
- }
-
- guint rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode)
- {
- static guint ssl_keylen;
-
- if (G_UNLIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
- return 64;
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert(0);
- #else
- if (ssl_keylen == 0) {
- EC_KEY *lk;
- lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
- ssl_keylen = ECDSA_size(lk);
- EC_KEY_free(lk);
- }
- #endif
- return ssl_keylen;
- }
- }
-
- guint rspamd_cryptobox_nm_bytes(enum rspamd_cryptobox_mode mode)
- {
- return 32;
- }
-
- guint rspamd_cryptobox_mac_bytes(enum rspamd_cryptobox_mode mode)
- {
- return 16;
- }
-
- void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *p, const guchar *key, gsize keylen)
- {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p,
- RSPAMD_ALIGNOF(crypto_generichash_blake2b_state));
- crypto_generichash_blake2b_init(st, key, keylen,
- crypto_generichash_blake2b_BYTES_MAX);
- }
-
- /**
- * Update hash with data portion
- */
- void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *p, const guchar *data, gsize len)
- {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p,
- RSPAMD_ALIGNOF(crypto_generichash_blake2b_state));
- crypto_generichash_blake2b_update(st, data, len);
- }
-
- /**
- * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
- */
- void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *p, guchar *out)
- {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p,
- RSPAMD_ALIGNOF(crypto_generichash_blake2b_state));
- crypto_generichash_blake2b_final(st, out, crypto_generichash_blake2b_BYTES_MAX);
- }
-
- /**
- * One in all function
- */
- void rspamd_cryptobox_hash(guchar *out,
- const guchar *data,
- gsize len,
- const guchar *key,
- gsize keylen)
- {
- crypto_generichash_blake2b(out, crypto_generichash_blake2b_BYTES_MAX,
- data, len, key, keylen);
- }
-
- G_STATIC_ASSERT(sizeof(t1ha_context_t) <=
- sizeof(((rspamd_cryptobox_fast_hash_state_t *) NULL)->opaque));
- G_STATIC_ASSERT(sizeof(struct XXH3_state_s) <=
- sizeof(((rspamd_cryptobox_fast_hash_state_t *) NULL)->opaque));
-
-
- struct RSPAMD_ALIGNED(16) _mum_iuf {
- union {
- int64_t ll;
- unsigned char b[sizeof(uint64_t)];
- } buf;
- int64_t h;
- unsigned rem;
- };
-
- rspamd_cryptobox_fast_hash_state_t *
- rspamd_cryptobox_fast_hash_new(void)
- {
- rspamd_cryptobox_fast_hash_state_t *nst;
- int ret = posix_memalign((void **) &nst, RSPAMD_ALIGNOF(rspamd_cryptobox_fast_hash_state_t),
- sizeof(rspamd_cryptobox_fast_hash_state_t));
-
- if (ret != 0) {
- abort();
- }
-
- return nst;
- }
-
- void rspamd_cryptobox_fast_hash_free(rspamd_cryptobox_fast_hash_state_t *st)
- {
- free(st);
- }
-
- void rspamd_cryptobox_fast_hash_init(rspamd_cryptobox_fast_hash_state_t *st,
- uint64_t seed)
- {
- XXH3_state_t *xst = (XXH3_state_t *) st->opaque;
- st->type = RSPAMD_CRYPTOBOX_XXHASH3;
- XXH3_INITSTATE(xst);
- XXH3_64bits_reset_withSeed(xst, seed);
- }
-
- void rspamd_cryptobox_fast_hash_init_specific(rspamd_cryptobox_fast_hash_state_t *st,
- enum rspamd_cryptobox_fast_hash_type type,
- uint64_t seed)
- {
- switch (type) {
- case RSPAMD_CRYPTOBOX_T1HA:
- case RSPAMD_CRYPTOBOX_HASHFAST:
- case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
- t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
- st->type = RSPAMD_CRYPTOBOX_T1HA;
- t1ha2_init(rst, seed, 0);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH64: {
- XXH64_state_t *xst = (XXH64_state_t *) st->opaque;
- memset(xst, 0, sizeof(*xst));
- st->type = RSPAMD_CRYPTOBOX_XXHASH64;
- XXH64_reset(xst, seed);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH32: {
- XXH32_state_t *xst = (XXH32_state_t *) st->opaque;
- memset(xst, 0, sizeof(*xst));
- st->type = RSPAMD_CRYPTOBOX_XXHASH32;
- XXH32_reset(xst, seed);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH3: {
- XXH3_state_t *xst = (XXH3_state_t *) st->opaque;
- XXH3_INITSTATE(xst);
- st->type = RSPAMD_CRYPTOBOX_XXHASH3;
- XXH3_64bits_reset_withSeed(xst, seed);
- break;
- }
- case RSPAMD_CRYPTOBOX_MUMHASH: {
- struct _mum_iuf *iuf = (struct _mum_iuf *) st->opaque;
- st->type = RSPAMD_CRYPTOBOX_MUMHASH;
- iuf->h = seed;
- iuf->buf.ll = 0;
- iuf->rem = 0;
- break;
- }
- }
- }
-
- void rspamd_cryptobox_fast_hash_update(rspamd_cryptobox_fast_hash_state_t *st,
- const void *data, gsize len)
- {
- if (st->type == RSPAMD_CRYPTOBOX_T1HA) {
- t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
- t1ha2_update(rst, data, len);
- }
- else {
- switch (st->type) {
- case RSPAMD_CRYPTOBOX_XXHASH64: {
- XXH64_state_t *xst = (XXH64_state_t *) st->opaque;
- XXH64_update(xst, data, len);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH32: {
- XXH32_state_t *xst = (XXH32_state_t *) st->opaque;
- XXH32_update(xst, data, len);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH3: {
- XXH3_state_t *xst = (XXH3_state_t *) st->opaque;
- XXH3_64bits_update(xst, data, len);
- break;
- }
- case RSPAMD_CRYPTOBOX_MUMHASH: {
- struct _mum_iuf *iuf = (struct _mum_iuf *) st->opaque;
- gsize drem = len;
- const guchar *p = data;
-
- if (iuf->rem > 0) {
- /* Process remainder */
- if (drem >= iuf->rem) {
- memcpy(iuf->buf.b + sizeof(iuf->buf.ll) - iuf->rem,
- p, iuf->rem);
- drem -= iuf->rem;
- p += iuf->rem;
- iuf->h = mum_hash_step(iuf->h, iuf->buf.ll);
- iuf->rem = 0;
- }
- else {
- memcpy(iuf->buf.b + sizeof(iuf->buf.ll) - iuf->rem, p, drem);
- iuf->rem -= drem;
- drem = 0;
- }
- }
-
- while (drem >= sizeof(iuf->buf.ll)) {
- memcpy(iuf->buf.b, p, sizeof(iuf->buf.ll));
- iuf->h = mum_hash_step(iuf->h, iuf->buf.ll);
- drem -= sizeof(iuf->buf.ll);
- p += sizeof(iuf->buf.ll);
- }
-
- /* Leftover */
- if (drem > 0) {
- iuf->rem = sizeof(uint64_t) - drem;
- iuf->buf.ll = 0;
- memcpy(iuf->buf.b, p, drem);
- }
- break;
- }
- case RSPAMD_CRYPTOBOX_T1HA:
- case RSPAMD_CRYPTOBOX_HASHFAST:
- case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
- t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
- t1ha2_update(rst, data, len);
- break;
- }
- }
- }
- }
-
- uint64_t
- rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t *st)
- {
- uint64_t ret;
-
- if (st->type == RSPAMD_CRYPTOBOX_T1HA) {
- t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
-
- return t1ha2_final(rst, NULL);
- }
- else {
- switch (st->type) {
- case RSPAMD_CRYPTOBOX_XXHASH64: {
- XXH64_state_t *xst = (XXH64_state_t *) st->opaque;
- ret = XXH64_digest(xst);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH32: {
- XXH32_state_t *xst = (XXH32_state_t *) st->opaque;
- ret = XXH32_digest(xst);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH3: {
- XXH3_state_t *xst = (XXH3_state_t *) st->opaque;
- ret = XXH3_64bits_digest(xst);
- break;
- }
- case RSPAMD_CRYPTOBOX_MUMHASH: {
- struct _mum_iuf *iuf = (struct _mum_iuf *) st->opaque;
- iuf->h = mum_hash_step(iuf->h, iuf->buf.ll);
- ret = mum_hash_finish(iuf->h);
- break;
- }
- case RSPAMD_CRYPTOBOX_T1HA:
- case RSPAMD_CRYPTOBOX_HASHFAST:
- case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT: {
- t1ha_context_t *rst = (t1ha_context_t *) st->opaque;
-
- ret = t1ha2_final(rst, NULL);
- break;
- }
- }
- }
-
- return ret;
- }
-
- /**
- * One in all function
- */
- static inline uint64_t
- rspamd_cryptobox_fast_hash_machdep(const void *data,
- gsize len, uint64_t seed)
- {
- return XXH3_64bits_withSeed(data, len, seed);
- }
-
- static inline uint64_t
- rspamd_cryptobox_fast_hash_indep(const void *data,
- gsize len, uint64_t seed)
- {
- return XXH3_64bits_withSeed(data, len, seed);
- }
-
- uint64_t
- rspamd_cryptobox_fast_hash(const void *data,
- gsize len, uint64_t seed)
- {
- return rspamd_cryptobox_fast_hash_machdep(data, len, seed);
- }
-
- uint64_t
- rspamd_cryptobox_fast_hash_specific(
- enum rspamd_cryptobox_fast_hash_type type,
- const void *data,
- gsize len, uint64_t seed)
- {
- switch (type) {
- case RSPAMD_CRYPTOBOX_XXHASH32:
- return XXH32(data, len, seed);
- case RSPAMD_CRYPTOBOX_XXHASH3:
- return XXH3_64bits_withSeed(data, len, seed);
- case RSPAMD_CRYPTOBOX_XXHASH64:
- return XXH64(data, len, seed);
- case RSPAMD_CRYPTOBOX_MUMHASH:
- return mum_hash(data, len, seed);
- case RSPAMD_CRYPTOBOX_T1HA:
- return t1ha2_atonce(data, len, seed);
- case RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT:
- return rspamd_cryptobox_fast_hash_indep(data, len, seed);
- case RSPAMD_CRYPTOBOX_HASHFAST:
- default:
- return rspamd_cryptobox_fast_hash_machdep(data, len, seed);
- }
- }
|