JavaScript加密库:开发者的最佳选择
比较Web应用的最佳JS加密库。从tweetnacl到libsodium.js,为您的项目找到合适的加密库。
2026 年文件传输场景下最值得使用的 JavaScript 加密库,按适用场景排列如下:libsodium.js 覆盖最广且有 WASM 加速;@noble/ciphers 和 @noble/curves 提供经过现代审计的纯 JS 实现;tweetnacl 体积最小且兼容 NaCl 原语;crypto-js 仅用于维护遗留代码(新项目避免使用);原生 Web Crypto API 适用于它所支持的所有场景。本文从算法覆盖度、包体积、审计历史、浏览器与 Node 兼容性,以及文件加密的实际性能等维度展开对比,帮你找到正确的选择。
对比一览
| 库 | 体积(gzip 后) | 后端 | 主要算法 | 已审计 | 是否现代 | |---|---|---|---|---|---| | Web Crypto API | 0 KB(原生) | 浏览器原生 | AES-GCM、PBKDF2、RSA、ECDH、HMAC | 是(各浏览器厂商) | 是,但不含 ChaCha/Argon2 | | libsodium.js | 200 KB WASM / 400 KB JS | WASM + JS 回退 | libsodium 全套 | 是(多次审计) | 是 | | @noble/ciphers | 8 KB | 纯 JS | AES、ChaCha20、Poly1305、GCM-SIV | 是(Cure53 2023) | 是 | | @noble/curves | 35 KB | 纯 JS | Ed25519、X25519、secp256k1、BLS | 是(Trail of Bits、Cure53) | 是 | | tweetnacl | 15 KB | 纯 JS | Curve25519、Ed25519、XSalsa20-Poly1305 | 是(原 NaCl 审计) | 基本是,缺少 ChaCha20 | | crypto-js | 50 KB | 纯 JS | AES-CBC、SHA、HMAC、PBKDF2 | 无当前审计 | 否,2023 年后停止维护 | | node:crypto | 0 KB(Node 原生) | Node 原生(OpenSSL) | 覆盖全面 | 是(OpenSSL) | 是 |
libsodium.js:功能最全的选择
libsodium.js(libsodium 的 Emscripten 编译版本)是 Web Crypto 不够用时的默认选择。它涵盖 XChaCha20-Poly1305、Ed25519、X25519、Argon2id、BLAKE2b,以及用于流式 AEAD 的 crypto_secretstream API。WASM 版本在典型硬件上运行速度约为原生 libsodium 的 50–70%。
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
);
流式 API 是大文件传输的杀手级特性。加密 5 GB 文件时无需将全部内容加载进内存,每个块携带独立认证标签,损坏在块级别即可检出,无需等到最后。
权衡:200 KB 的 WASM 包体积不小。使用动态导入(await import('libsodium-wrappers'))可做到按需加载。sumo 版本(包含所有算法)超过 600 KB,非必要时坚持使用默认版本。
@noble:小巧、已审计、现代
Paul Miller 的 @noble 家族(@noble/ciphers、@noble/curves、@noble/hashes)是当前纯 JavaScript 密码学库的最优选。已通过 Cure53 审计(ciphers,2023 年)和 Trail of Bits 审计(curves,2022 年),零依赖,支持 tree-shaking,TypeScript 原生。
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 不使用 WASM,对包体积影响极小(ciphers 仅 8 KB)。批量 AES-GCM 的性能比 libsodium WASM 慢 30–50%,但对大多数传输场景已足够。纯 JS 的好处是在浏览器、Node、Deno、Bun 和 React Native 上行为完全一致,无需担心原生模块兼容问题。
包体积敏感、需要 tree-shaking 的纯 JS 项目,或 WASM 存在边缘问题的平台,推荐使用 @noble。
tweetnacl:极简主义之选
tweetnacl-js 将 Daniel J. Bernstein 的 TweetNaCl C 库移植到 JavaScript,gzip 后仅 15 KB。覆盖 Curve25519 密钥交换、Ed25519 签名和 XSalsa20-Poly1305 认证加密。作为原始 NaCl 工作的一部分,曾经过审计,但最近没有更新。
import nacl from 'tweetnacl';
const key = nacl.randomBytes(32);
const nonce = nacl.randomBytes(24);
const ciphertext = nacl.secretbox(plaintext, nonce, key);
API 刻意保持极简:如果需要 NaCl 以外的功能(例如与非 JS 系统互操作的 AES-GCM),应另寻他处。对于纯 NaCl 协议应用,tweetnacl 仍是合理选择,但 @noble/ciphers 加上 @noble/curves 覆盖相同功能且维护更积极。
crypto-js:新项目请勿使用
crypto-js 在 2015 年曾统治浏览器密码学。到 2026 年,它已成为风险来源。最后一次有意义的发布是 2021 年(4.1.1),代码库实际上在 2023 年进入归档状态。它默认使用 AES-CBC,密码派生采用不安全的 OpenSSL EVP_BytesToKey 风格方案(通过几轮 MD5 推导密钥)。CVE-2023-46233 指出了其 PBKDF2 默认值的安全问题。
如果你在维护使用了 crypto-js 的遗留代码,迁移到 @noble/ciphers 或 Web Crypto 并不复杂,这项工作很有价值。2026 年的新项目,直接跳过 crypto-js。
node:crypto:服务器端代码的标准选择
Node 内置的 crypto 模块封装了 OpenSSL,在算法覆盖度上居于列表首位。Node 18+ 中,require('crypto').webcrypto 暴露了兼容 Web Crypto 的 API,可在服务器和客户端共用同构代码。
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();
对于在服务器端解密 Web Crypto 加密文件的场景,这是最简洁的路径。如果文件传输服务需要服务端解密(零知识架构中很少见,但遗留系统迁移时偶有需求),使用 node:crypto。
实际文件加密性能
在 MacBook Air M2 上对 100 MB 缓冲区执行 AES-256-GCM 加密的基准测试:
- Web Crypto API(Chrome 120):340 ms(硬件加速)
- Web Crypto API(Safari 17):280 ms(Apple Silicon 硬件加速)
- libsodium.js WASM:420 ms
- @noble/ciphers:1,850 ms(纯 JS 无硬件加速)
- tweetnacl(XSalsa20):1,200 ms
- node:crypto:180 ms(原生 OpenSSL)
结论:Web Crypto 凭借 AES-NI 硬件加速赢得大文件场景。纯 JS 处理小负载没问题,但多吉字节传输会增加数分钟的加密时间。加密 5 GB 文件,Web Crypto 与 @noble/ciphers 的差距可能是 2 分钟对比 10 分钟。
密码哈希:Argon2 是更好的选择
PBKDF2 是基础保障,但 Argon2id 更优。可选方案:
- argon2-browser:WASM 编译的参考实现,约 200 KB
- @noble/hashes:纯 JS 的 Argon2id,15 KB,速度稍慢但纯粹
- libsodium.js:通过
crypto_pwhash提供 Argon2id,200 KB,但若已使用 libsodium 则无额外开销
浏览器场景中密码派生密钥,建议采用至少 3 次迭代、64 MiB 内存、4 并行度的 Argon2id(OWASP 2024 指南)。
根据技术栈做选择
- 构建简单的 AES-GCM 加密文件传输:直接使用 Web Crypto,无需引入库。HexaTransfer 采用此模式。
- 需要 ChaCha20-Poly1305 或流式 AEAD:libsodium.js。
- 对 WASM 有顾虑,或打包器限制严格:@noble/ciphers + @noble/curves。
- 使用 NaCl 协议密钥(如用于加密文件接收的密封盒):@noble 或 libsodium,而非 crypto-js。
- 从 crypto-js 迁移:包体积敏感则选 @noble,否则选 libsodium.js。
- 需要后量子签名或 KEM:目前尚无成熟 JS 库;可关注 @noble/post-quantum(2026 年初仍为预发布版本)。
审计与维护信号
引入密码学库前,检查以下几点:
- 最后提交日期(超过 18 个月未活跃是风险信号)
- 公开审计报告(Cure53、Trail of Bits、NCC Group)
- Issue 跟踪器中是否有未解决的安全问题
- 依赖项数量(越少意味着攻击面越小)
- npm 周下载量(越高意味着越多人在审视代码)
JavaScript 生态曾发生过供应链安全事件(event-stream、ua-parser-js、colors),这使得最小依赖成为一项安全属性。零运行时依赖的密码学库(@noble 家族、tweetnacl)比那些引入了 polyfill 和工具函数的库更容易端到端审计。
在 hexatransfer.com 上试试 — 免费、无需注册、最多 10 GB。