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_secretstreamdi 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