123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707 |
- /*-
- * Copyright 2016 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"
- #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)
- {
- guint32 eax, ecx = 0, ebx = 0, 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);
- guint32 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) {
- #ifdef HAVE_SSE2
- 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
- #ifdef HAVE_SSE42
- 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 guint32 osxsave_mask = (1 << 27);
- const guint32 fma_movbe_osxsave_mask = ((1 << 12) | (1 << 22) | (1 << 27));
- const guint32 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] & ((guint32)1 << 26))) {
- if (rspamd_cryptobox_test_instr (CPUID_SSE2)) {
- cpu_config |= CPUID_SSE2;
- }
- }
- if ((cpu[2] & ((guint32)1 << 0))) {
- if (rspamd_cryptobox_test_instr (CPUID_SSE3)) {
- cpu_config |= CPUID_SSE3;
- }
- }
- if ((cpu[2] & ((guint32)1 << 9))) {
- if (rspamd_cryptobox_test_instr (CPUID_SSSE3)) {
- cpu_config |= CPUID_SSSE3;
- }
- }
- if ((cpu[2] & ((guint32)1 << 19))) {
- if (rspamd_cryptobox_test_instr (CPUID_SSE41)) {
- cpu_config |= CPUID_SSE41;
- }
- }
- if ((cpu[2] & ((guint32)1 << 20))) {
- if (rspamd_cryptobox_test_instr (CPUID_SSE42)) {
- cpu_config |= CPUID_SSE42;
- }
- }
- if ((cpu[2] & ((guint32)1 << 30))) {
- if (rspamd_cryptobox_test_instr (CPUID_RDRAND)) {
- cpu_config |= CPUID_RDRAND;
- }
- }
-
- /* OSXSAVE */
- if ((cpu[2] & osxsave_mask) == osxsave_mask) {
- if ((cpu[2] & ((guint32)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;
- BIGNUM *bn_pub;
- const EC_POINT *ec_pub;
- gint 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);
- bn_pub = EC_POINT_point2bn (EC_KEY_get0_group (ec_sec),
- ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
-
- len = BN_num_bytes (bn_sec);
- g_assert (len <= (gint)sizeof (rspamd_sk_t));
- BN_bn2bin (bn_sec, sk);
- len = BN_num_bytes (bn_pub);
- g_assert (len <= (gint)rspamd_cryptobox_pk_bytes (mode));
- BN_bn2bin (bn_pub, pk);
- BN_free (bn_pub);
- 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;
- BIGNUM *bn_pub;
- const EC_POINT *ec_pub;
- gint 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);
- bn_pub = EC_POINT_point2bn (EC_KEY_get0_group (ec_sec),
- ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
-
- len = BN_num_bytes (bn_sec);
- g_assert (len <= (gint)sizeof (rspamd_sk_t));
- BN_bn2bin (bn_sec, sk);
- len = BN_num_bytes (bn_pub);
- g_assert (len <= (gint)rspamd_cryptobox_pk_bytes (mode));
- BN_bn2bin (bn_pub, pk);
- BN_free (bn_pub);
- EC_KEY_free (ec_sec);
- #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 (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 (sig, siglen_p, m, mlen, sk);
- }
- else {
- #ifndef HAVE_USABLE_OPENSSL
- g_assert (0);
- #else
- EC_KEY *lk;
- BIGNUM *bn_sec, *kinv = NULL, *rp = NULL;
- 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_setup (lk, NULL, &kinv, &rp) == 1);
- g_assert (ECDSA_sign_ex (0, h, sizeof (h), sig,
- &diglen, kinv, rp, 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);
- BN_free (kinv);
- BN_free (rp);
-
- #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 (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) + _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 (void *p, const guchar *key, gsize keylen)
- {
- if (key != NULL && keylen > 0) {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
- _Alignof(crypto_generichash_blake2b_state));
- crypto_generichash_blake2b_init (st, key, keylen,
- crypto_generichash_blake2b_BYTES_MAX);
- }
- else {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
- _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 (void *p, const guchar *data, gsize len)
- {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
- _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 (void *p, guchar *out)
- {
- crypto_generichash_blake2b_state *st = cryptobox_align_ptr (p,
- _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 (XXH64_state_t) <=
- sizeof (((rspamd_cryptobox_fast_hash_state_t *)NULL)->opaque));
-
-
- struct RSPAMD_ALIGNED(16) _mum_iuf {
- union {
- gint64 ll;
- unsigned char b[sizeof (guint64)];
- } buf;
- gint64 h;
- unsigned rem;
- };
-
- void
- rspamd_cryptobox_fast_hash_init (rspamd_cryptobox_fast_hash_state_t *st,
- guint64 seed)
- {
- t1ha_context_t *rst = (t1ha_context_t *)st->opaque;
- st->type = RSPAMD_CRYPTOBOX_T1HA;
- t1ha2_init (rst, seed, 0);
- }
-
- void
- rspamd_cryptobox_fast_hash_init_specific (rspamd_cryptobox_fast_hash_state_t *st,
- enum rspamd_cryptobox_fast_hash_type type,
- guint64 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;
- st->type = RSPAMD_CRYPTOBOX_XXHASH64;
- XXH64_reset (xst, seed);
- break;
- }
- case RSPAMD_CRYPTOBOX_XXHASH32:
- {
- XXH32_state_t *xst = (XXH32_state_t *) st->opaque;
- st->type = RSPAMD_CRYPTOBOX_XXHASH32;
- XXH32_reset (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 (G_LIKELY (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_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 (guint64) - 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;
- }
- }
- }
- }
-
- guint64
- rspamd_cryptobox_fast_hash_final (rspamd_cryptobox_fast_hash_state_t *st)
- {
- guint64 ret;
-
- if (G_LIKELY (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_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 guint64
- rspamd_cryptobox_fast_hash_machdep (const void *data,
- gsize len, guint64 seed)
- {
- return t1ha2_atonce (data, len, seed);
- }
-
- static inline guint64
- rspamd_cryptobox_fast_hash_indep (const void *data,
- gsize len, guint64 seed)
- {
- return t1ha2_atonce (data, len, seed);
- }
-
- guint64
- rspamd_cryptobox_fast_hash (const void *data,
- gsize len, guint64 seed)
- {
- return rspamd_cryptobox_fast_hash_machdep (data, len, seed);
- }
-
- guint64
- rspamd_cryptobox_fast_hash_specific (
- enum rspamd_cryptobox_fast_hash_type type,
- const void *data,
- gsize len, guint64 seed)
- {
- switch (type) {
- case RSPAMD_CRYPTOBOX_XXHASH32:
- return XXH32 (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);
- }
- }
|