Bibliotecas de cifrado JavaScript: mejores opciones para devs
Compara las mejores bibliotecas de cifrado JS para aplicaciones web. De tweetnacl a libsodium.js, encuentra la correcta para tu proyecto.
Las mejores bibliotecas de cifrado JavaScript para trabajo de transferencia de archivos en 2026 son: libsodium.js para cobertura amplia y velocidad WASM, @noble/ciphers y @noble/curves para implementaciones en JS puro con auditorías recientes, tweetnacl para tamaño de bundle reducido con primitivos compatibles con NaCl, crypto-js para compatibilidad heredada (evítalo en código nuevo), y la Web Crypto API nativa para todo lo que soporta. Esta guía las compara en cobertura de algoritmos, tamaño de bundle, historial de auditorías, compatibilidad navegador/Node, y rendimiento real en cargas de trabajo de cifrado de archivos. La elección correcta depende de si despliegas en navegadores, construyes en Node, necesitas ChaCha20-Poly1305 o Argon2, o puedes vivir dentro de los límites de Web Crypto.
Tabla de comparativa
| Biblioteca | Tamaño (gzipped) | Backend | Algoritmos clave | Auditada | ¿Moderna? | |---|---|---|---|---|---| | Web Crypto API | 0 KB (nativa) | Nativa del navegador | AES-GCM, PBKDF2, RSA, ECDH, HMAC | Sí (por fabricantes de navegadores) | Sí, pero sin ChaCha/Argon2 | | libsodium.js | 200 KB WASM / 400 KB JS | WASM + fallback JS | Todo lo de libsodium | Sí (múltiples) | Sí | | @noble/ciphers | 8 KB | JS puro | AES, ChaCha20, Poly1305, GCM-SIV | Sí (Cure53 2023) | Sí | | @noble/curves | 35 KB | JS puro | Ed25519, X25519, secp256k1, BLS | Sí (Trail of Bits, Cure53) | Sí | | tweetnacl | 15 KB | JS puro | Curve25519, Ed25519, XSalsa20-Poly1305 | Sí (auditoría NaCl original) | Mayormente, sin ChaCha20 | | crypto-js | 50 KB | JS puro | AES-CBC, SHA, HMAC, PBKDF2 | Sin auditoría actual | No, sin mantenimiento desde 2023 | | node:crypto | 0 KB (nativa Node) | Nativa Node (OpenSSL) | Completo | Sí (OpenSSL) | Sí |
libsodium.js: la navaja suiza
libsodium.js (la compilación Emscripten de libsodium) es la opción por defecto cuando Web Crypto no es suficiente. Cubre XChaCha20-Poly1305, Ed25519, X25519, Argon2id, BLAKE2b y la API crypto_secretstream para AEAD en streaming. La compilación WASM corre a aproximadamente el 50-70% de la velocidad nativa de libsodium en hardware típico.
import _sodium from 'libsodium-wrappers';
await _sodium.ready;
const sodium = _sodium;
const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
const chunk = sodium.crypto_secretstream_xchacha20poly1305_push(
state, new Uint8Array([1,2,3]), null,
sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
La API en streaming es la funcionalidad estrella para transferencias de archivos grandes. Puedes cifrar un archivo de 5 GB fragmento a fragmento sin cargarlo todo en memoria, y cada fragmento lleva su propia etiqueta de autenticación para que la corrupción se detecte por fragmento, no solo al final.
Contras: 200 KB de WASM es mucho que enviar. Usa importaciones dinámicas (await import('libsodium-wrappers')) para que la biblioteca solo se cargue cuando realmente se necesita el cifrado. La compilación sumo (incluye todos los algoritmos) supera los 600 KB; usa la compilación por defecto salvo que necesites los extras.
@noble: pequeño, auditado, moderno
La familia @noble de Paul Miller (@noble/ciphers, @noble/curves, @noble/hashes) es el estado del arte actual en criptografía JavaScript pura. Auditada por Cure53 (ciphers, 2023) y Trail of Bits (curves, 2022), sin dependencias, tree-shakeable, TypeScript nativo.
import { gcm } from '@noble/ciphers/aes';
import { randomBytes } from '@noble/ciphers/webcrypto';
const key = randomBytes(32);
const nonce = randomBytes(12);
const ciphertext = gcm(key, nonce).encrypt(plaintext);
@noble no usa WASM, así que el impacto en el bundle es pequeño (8 KB para ciphers). El rendimiento es un 30-50% más lento que el WASM de libsodium para AES-GCM en bulk, pero suficiente para la mayoría de escenarios de transferencia. El enfoque en JS puro también significa que funciona de forma idéntica en navegadores, Node, Deno, Bun y React Native sin problemas con módulos nativos.
Usa @noble cuando el tamaño del bundle importe, cuando quieras una biblioteca JS pura tree-shakeable, o cuando estés en una plataforma donde WASM tiene problemas.
tweetnacl: el minimalista
tweetnacl-js porta la biblioteca C TweetNaCl de Daniel J. Bernstein a JavaScript. 15 KB gzipped. Cubre el intercambio de claves Curve25519, firmas Ed25519 y cifrado autenticado XSalsa20-Poly1305. Auditada como parte del esfuerzo NaCl original, aunque no recientemente.
import nacl from 'tweetnacl';
const key = nacl.randomBytes(32);
const nonce = nacl.randomBytes(24);
const ciphertext = nacl.secretbox(plaintext, nonce, key);
La API es deliberadamente pequeña: si necesitas más de lo que NaCl proporciona (por ejemplo, AES-GCM para interoperabilidad con sistemas no JS), busca en otro lado. Para aplicaciones de protocolo NaCl puro, tweetnacl sigue siendo una opción razonable, aunque @noble/ciphers más @noble/curves cubre el mismo terreno con mantenimiento más actual.
crypto-js: no la uses en código nuevo
crypto-js dominó el cifrado en navegadores en 2015. En 2026 es un pasivo. La última versión con significado fue 2021 (4.1.1); el repositorio quedó efectivamente archivado en 2023. Por defecto usa AES-CBC con una derivación de clave insegura (esquema tipo EVP_BytesToKey de OpenSSL), que deriva claves mediante unas pocas rondas de MD5. CVE-2023-46233 marcó los valores por defecto débiles de PBKDF2.
Si mantienes código heredado que usa crypto-js, migrar a @noble/ciphers o Web Crypto es sencillo y vale la pena el esfuerzo. Si empiezas de cero en 2026, omite crypto-js por completo.
node:crypto para código de servidor
El módulo integrado crypto de Node envuelve OpenSSL y tiene la cobertura de algoritmos más amplia de todo lo que hay en esta lista. En Node 18+, require('crypto').webcrypto expone una API compatible con Web Crypto, así que el código isomorfo funciona en servidor y cliente.
import { createCipheriv, randomBytes } from 'crypto';
const key = randomBytes(32);
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', key, iv);
const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const tag = cipher.getAuthTag();
Para descifrado en el servidor de archivos cifrados con Web Crypto, este es el camino más limpio. Si tu servicio de transferencia descifra algo en el servidor (poco frecuente en diseños zero-knowledge, pero habitual en sistemas heredados que migran a cifrado), usa node:crypto.
Rendimiento en cifrado real de archivos
Benchmarks en un MacBook Air M2 cifrando un buffer de 100 MB con AES-256-GCM:
- Web Crypto API (Chrome 120): 340 ms (acelerado por hardware)
- Web Crypto API (Safari 17): 280 ms (acelerado por hardware en Apple Silicon)
- libsodium.js WASM: 420 ms
- @noble/ciphers: 1.850 ms (sin aceleración de hardware en JS puro)
- tweetnacl (XSalsa20): 1.200 ms
- node:crypto: 180 ms (OpenSSL nativo)
Conclusión: Web Crypto gana para archivos grandes porque usa AES-NI. El JS puro es adecuado para cargas útiles pequeñas pero añade segundos en transferencias de varios gigabytes. Para una subida de 5 GB, la diferencia entre Web Crypto y @noble/ciphers podría ser 2 minutos frente a 10 minutos de tiempo de cifrado.
Hash de contraseñas: Argon2 o nada
PBKDF2 es el mínimo exigible pero Argon2id es mejor. Opciones:
- argon2-browser: implementación de referencia compilada a WASM, 200 KB
- @noble/hashes: Argon2id en JS puro, 15 KB, más lento pero sin dependencias
- libsodium.js: Argon2id a través de
crypto_pwhash, 200 KB pero ya lo tienes si usas libsodium
Usa Argon2id con al menos 3 iteraciones, 64 MiB de memoria y 4 de paralelismo para claves de cifrado derivadas de contraseña en contextos de navegador (guía OWASP 2024).
Cómo elegir según tu stack
- Construyes una transferencia de archivos simple con cifrado AES-GCM: usa Web Crypto directamente, sin librería. HexaTransfer sigue este patrón.
- Necesitas ChaCha20-Poly1305 o AEAD en streaming: libsodium.js.
- Eres cuidadoso con WASM o despliegas en bundlers con restricciones: @noble/ciphers + @noble/curves.
- Usas claves de protocolo NaCl (p. ej., sealed boxes para recepción de archivos cifrados): @noble o libsodium, no crypto-js.
- Migras desde crypto-js: muévete a @noble si el tamaño del bundle importa, libsodium.js en caso contrario.
- Necesitas firmas post-cuánticas o KEM: no hay ninguna librería JS madura todavía; revisa @noble/post-quantum (en prerelease a principios de 2026).
Señales de auditoría y mantenimiento
Antes de adoptar una biblioteca de cifrado, comprueba:
- Fecha del último commit (cualquier cosa con más de 18 meses de inactividad es un riesgo)
- Informes de auditoría públicos (Cure53, Trail of Bits, NCC Group)
- Issue tracker para problemas de seguridad sin resolver
- Número de dependencias (menos = superficie de ataque menor)
- Descargas semanales en npm (más = más ojos sobre el código)
El ecosistema JavaScript ha sufrido incidentes de cadena de suministro (event-stream, ua-parser-js, colors) que hacen de las dependencias mínimas una propiedad de seguridad. Las bibliotecas de cifrado con cero dependencias en tiempo de ejecución (@noble, tweetnacl) son más fáciles de auditar de extremo a extremo que las que incorporan polyfills y utilidades.
Pruébalo en hexatransfer.com — gratis, sin cuenta, hasta 10 GB.
Envía archivos grandes de forma segura con cifrado de extremo a extremo
Transfiere archivos de hasta 10 GB gratis con cifrado de extremo a extremo. Sin necesidad de cuenta. Tus archivos se cifran en tu navegador antes de subirlos: nadie más puede leerlos.
Enviar un archivo