Vai al contenuto
HexaTransfer
Torna al blog
Crittografia e sicurezza

Crittografia WebAssembly: velocità crypto quasi nativa nel browser

Usa WebAssembly per velocità di crittografia quasi native. Confronta implementazioni WASM e quando usare WASM rispetto a JavaScript puro.

Le librerie crypto compilate in WebAssembly girano nel browser a circa il 60-80% della velocità nativa in C, ovvero 3-10x più rapidamente rispetto alle implementazioni in JavaScript puro. Per i primitivi crittografici assenti dalla Web Crypto API — ChaCha20-Poly1305, Argon2id, XChaCha20, i KEM post-quantistici come Kyber — WASM è la strada pratica verso performance effettivamente usabili. libsodium.js è l'opzione dominante: offre l'intera API di libsodium in un binario WASM da 200 KB. Per i primitivi già supportati dalla Web Crypto API come AES-256-GCM, l'implementazione nativa con accelerazione hardware batte WASM di gran lunga, quindi WASM non è sempre la scelta giusta. Questa guida spiega quando usarlo e come misurare i compromessi.

Quando la Web Crypto API nativa vince

Per gli algoritmi che Web Crypto già espone — AES-GCM, AES-CBC, AES-CTR, PBKDF2, HMAC, RSA-OAEP, ECDH, ECDSA, SHA-256/384/512 — il browser usa l'accelerazione hardware via AES-NI su x86 e le estensioni crypto ARMv8 su mobile. Throughput tipico per AES-256-GCM:

  • Web Crypto (Chrome su Apple Silicon): 1,7 GB/s
  • Web Crypto (Chrome su Intel x86 con AES-NI): 1,2 GB/s
  • libsodium WASM AES-GCM: 400-800 MB/s
  • OpenSSL nativo di riferimento: 3-5 GB/s

WASM non ha accesso ad AES-NI dall'interno della sandbox: ricade su implementazioni bitsliced di AES, più lente ma a tempo costante. Per tutto ciò che Web Crypto supporta, usala per prima.

Dove WASM fa la differenza

Per gli algoritmi assenti dalla Web Crypto:

  • ChaCha20-Poly1305: più veloce di AES su dispositivi senza AES-NI. Nessun supporto nativo nel browser nel 2026.
  • XChaCha20-Poly1305: nonce da 192 bit rendono sicuro l'uso random a qualsiasi scala.
  • Argon2id: la funzione PHC vincitrice per l'hashing delle password. Nessun supporto nativo nel browser.
  • X25519 / Ed25519: Safari 17 e Firefox 129 hanno aggiunto supporto nativo, ma WASM è ancora il percorso portabile.
  • BLAKE2b / BLAKE3: funzioni hash veloci non incluse in Web Crypto.
  • Kyber, Dilithium, SPHINCS+: primitivi post-quantistici; territorio esclusivo delle librerie.
  • Streaming AEAD: crypto_secretstream di libsodium gestisce la cifratura streaming di file grandi in modo pulito; Web Crypto non ha un equivalente.

Per questi algoritmi esistono implementazioni JavaScript, ma sono 5-20x più lente di WASM. Su un file da 1 GB con ChaCha20-Poly1305, WASM termina in ~2 secondi mentre JS puro ne impiega 15-40.

libsodium.js: il cavallo di battaglia

libsodium-wrappers (la libsodium compilata con Emscripten, con wrapper JS) è la libreria di riferimento. 200 KB WASM + ~50 KB di wrapper JS, compressi con gzip.

import _sodium from 'libsodium-wrappers';
await _sodium.ready;
const sodium = _sodium;

// Cifratura autenticata ChaCha20-Poly1305
const key = sodium.crypto_aead_xchacha20poly1305_ietf_keygen();
const nonce = sodium.randombytes_buf(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
const ciphertext = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
  plaintext, null, null, nonce, key
);

La build "sumo" (include più algoritmi) è ~600 KB; quella predefinita copre il 90% dei casi d'uso inclusi AEAD, password hashing (Argon2id), X25519 ed Ed25519.

Caricala dinamicamente in modo che il binario WASM non blocchi il render iniziale:

async function getSodium() {
  if (!window._sodium) {
    const mod = await import('libsodium-wrappers');
    await mod.ready;
    window._sodium = mod;
  }
  return window._sodium;
}

Streaming AEAD con crypto_secretstream

Per il trasferimento di file grandi, crypto_secretstream_xchacha20poly1305 di libsodium è lo streaming AEAD più pulito disponibile nel browser:

const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
const chunk1 = sodium.crypto_secretstream_xchacha20poly1305_push(
  state, plaintext1, null,
  sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
// L'ultimo chunk usa TAG_FINAL perché il destinatario rilevi troncamenti
const chunkLast = sodium.crypto_secretstream_xchacha20poly1305_push(
  state, plaintextLast, null,
  sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
);

Il marcatore TAG_FINAL permette al destinatario di rilevare attacchi di troncamento: se un attaccante elimina i chunk finali, la decifratura lato client fallisce. AES-GCM di Web Crypto non ha questa proprietà; dovresti costruire la rilevazione del troncamento da zero (conteggio dei chunk nell'AAD, o un hash complessivo verificato post-decifratura).

Argon2 nel browser

Per la derivazione della chiave da password nel browser, Argon2id via WASM è la best practice del 2026. Le opzioni:

  • argon2-browser: libreria WASM dedicata ad Argon2, ~200 KB
  • libsodium.js: Argon2id via crypto_pwhash, se già usi libsodium
  • @noble/hashes: Argon2id in puro JS, bundle di ~15 KB, 3-5x più lento di WASM

Esempio con argon2-browser:

import argon2 from 'argon2-browser';
const result = await argon2.hash({
  pass: password,
  salt: salt, // Uint8Array, 16+ byte
  type: argon2.ArgonType.Argon2id,
  time: 3,
  mem: 65536, // KiB, quindi 64 MiB
  parallelism: 4,
  hashLen: 32,
});
// result.hash è un Uint8Array usabile come chiave AES-256

Calibra i parametri in base all'attesa accettabile per i tuoi utenti. La baseline OWASP 2024 (m=19 MiB, t=2, p=1) gira in ~300-500 ms. Parametri più forti (m=64 MiB, t=3, p=4) richiedono ~1-2 secondi su hardware moderno.

Crypto post-quantistica via WASM

Kyber (key encapsulation) e Dilithium (firme) sono stati standardizzati dal NIST nel 2024 come ML-KEM e ML-DSA. Le implementazioni JavaScript esistono (pq-crystals ha un riferimento), ma le versioni WASM come liboqs-js sono più veloci e più verificabili.

Per il trasferimento file, i KEM post-quantistici permettono di incapsulare una chiave simmetrica con un primitivo a chiave pubblica quantum-safe. Gli schemi ibridi (ML-KEM + X25519) proteggono sia da attaccanti classici che futuri quantum. Chrome ha introdotto ML-KEM nelle handshake TLS nella versione 116 (2023), ma WASM a livello applicativo rimane il percorso per le chiavi dei contenuti dei file.

Dimensioni del bundle

I binari WASM vengono spediti come parte del bundle JS o recuperati in modo lazy. Dimensioni approssimative (gzippate):

  • libsodium.js predefinito: 200 KB
  • libsodium.js sumo: 600 KB
  • argon2-browser: 200 KB
  • liboqs-js (post-quantistico): 1 MB+

Per una landing page che cifra nel browser, 200-300 KB di WASM sono accettabili se caricati in lazy dopo l'interazione dell'utente. Usa hint rel="modulepreload" o la cache del service worker per rendere i caricamenti successivi istantanei.

Overhead di compilazione e avvio

WebAssembly.instantiate() analizza e compila il binario, il che richiede 20-100 ms per un modulo da 200 KB su desktop, 100-500 ms su mobile. Questo avviene una volta per sessione. Metti in cache il modulo compilato in IndexedDB via serializzazione WebAssembly.Module per caricamenti successivi più rapidi.

WebAssembly.instantiateStreaming() pipeline download e compilazione, risparmiando il 30-50% del tempo di avvio rispetto a instantiate() su una risposta recuperata:

const response = fetch('/sodium.wasm');
const { instance } = await WebAssembly.instantiateStreaming(response, importObject);

La ricetta pratica per il 2026

Per un'app di trasferimento file:

  • Usa Web Crypto per AES-256-GCM, PBKDF2, HMAC, SHA-256, RSA-OAEP se ti serve RSA
  • Usa libsodium.js via WASM per l'hashing delle password con Argon2id
  • Usa libsodium.js per la cifratura streaming di file grandi (crypto_secretstream)
  • Usa Ed25519/X25519 nativo dove supportato, fallback su libsodium altrimenti
  • Carica WASM in lazy dopo l'interazione utente per tenere leggero il bundle iniziale
  • Fai benchmark sui dispositivi target; non dare per scontato che i numeri desktop si ripetano su mobile

HexaTransfer usa Web Crypto AES-GCM per la cifratura bulk dei file perché il percorso con accelerazione hardware è il più veloce. WASM è riservato agli algoritmi che le API native non sanno fornire.

Provalo su hexatransfer.com — gratis, senza registrazione, fino a 10 GB.

Invia file di grandi dimensioni in modo sicuro con crittografia end-to-end

Trasferisci file fino a 10 GB gratuitamente con crittografia end-to-end. Nessun account necessario. I tuoi file vengono crittografati nel browser prima del caricamento — nessun altro può leggerli.

Invia un file