paulmillr/noble-ciphers
GitHub: paulmillr/noble-ciphers
一个经过独立审计、极简且零依赖的 JavaScript 对称加密库,实现了 AES 与 ChaCha/Salsa20 系列算法及多种分组模式。
Stars: 408 | Forks: 27
# noble-ciphers
经过审计的、极简的 Salsa20、ChaCha 和 AES JS 实现。
- 🔒 由独立安全公司[**审计**](#security)
- 🔻 支持 Tree-shaking:未使用的代码将被排除在你的构建之外
- 🏎 快速:针对 JS 引擎的特性进行了手工优化
- 🔍 可靠:基于属性的 / 跨库的 / wycheproof 测试确保了正确性
- 💼 AES:ECB, CBC, CTR, CFB, GCM, SIV(抗 nonce 误用),AESKW, AESKWP
- 💃 Salsa20, ChaCha, XSalsa20, XChaCha, ChaCha8, ChaCha12, Poly1305
- 🥈 两种 AES 实现:纯 JS 或友好的 WebCrypto 封装
- 🪶 包含所有功能仅 11KB(gzipped),仅构建 ChaCha 为 3KB
### 此库属于 _noble_ 密码学
- 零或极少的依赖
- 高度可读的 TypeScript / JS 代码
- PGP 签名的版本发布和透明的 NPM 构建
- 所有库:
[ciphers](https://github.com/paulmillr/noble-ciphers),
[curves](https://github.com/paulmillr/noble-curves),
[hashes](https://github.com/paulmillr/noble-hashes),
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
[ed25519](https://github.com/paulmillr/noble-ed25519)
- WASM 版本:[awasm-noble](https://github.com/paulmillr/awasm-noble)
- [查看主页](https://paulmillr.com/noble/)
阅读资源、文档以及使用 noble 构建的应用
## 使用方法
我们支持所有主要平台和运行时。
对于 React Native,你可能需要一个
[getRandomValues 的 polyfill](https://github.com/LinusU/react-native-get-random-values)。
同时也提供了一个独立的文件
[noble-ciphers.js](https://github.com/paulmillr/noble-ciphers/releases)。
```
// import * from '@noble/ciphers'; // Error: use sub-imports, to ensure small app size
import { gcm, gcmsiv } from '@noble/ciphers/aes.js';
import { chacha20poly1305, xchacha20poly1305 } from '@noble/ciphers/chacha.js';
import { xsalsa20poly1305 } from '@noble/ciphers/salsa.js';
// Unauthenticated encryption: make sure to use HMAC or similar
import { ctr, cfb, cbc, ecb } from '@noble/ciphers/aes.js';
import { salsa20, xsalsa20 } from '@noble/ciphers/salsa.js';
import { chacha20, xchacha20, chacha8, chacha12 } from '@noble/ciphers/chacha.js';
import { aeskw, aeskwp } from '@noble/ciphers/aes.js'; // KW
import { bytesToHex, hexToBytes, managedNonce, randomBytes } from '@noble/ciphers/utils.js';
```
- [示例](#examples)
- [XChaCha20-Poly1305 加密](#xchacha20-poly1305-encryption)
- [AES-256-GCM 加密](#aes-256-gcm-encryption)
- [managedNonce:自动 nonce 处理](#managednonce-automatic-nonce-handling)
- [AES:gcm, siv, ctr, cfb, cbc, ecb, aeskw](#aes-gcm-siv-ctr-cfb-cbc-ecb-aeskw)
- [AES:友好的 WebCrypto 封装](#aes-friendly-webcrypto-wrapper)
- [重用数组作为输入和输出](#reuse-array-for-input-and-output)
- [使用密码进行加密](#use-password-for-encryption)
- [内部机制](#internals)
- [选择加密算法](#picking-a-cipher)
- [如何正确加密](#how-to-encrypt-properly)
- [Nonce](#nonces)
- [加密限制](#encryption-limits)
- [AES 分组模式](#aes-block-modes)
- [已实现的原语](#implemented-primitives)
- [安全性](#security)
- [速度](#speed)
- [升级](#upgrading)
- [贡献与测试](#contributing--testing)
- [许可证](#license)
## 示例
#### XChaCha20-Poly1305 加密
```
import { xchacha20poly1305 } from '@noble/ciphers/chacha.js';
import { randomBytes } from '@noble/ciphers/utils.js';
const key = randomBytes(32); // random key
// const key = new Uint8Array([ // existing key
// 169, 88, 160, 139, 168, 29, 147, 196, 14, 88, 237, 76, 243, 177, 109, 140,
// 195, 140, 80, 10, 216, 134, 215, 71, 191, 48, 20, 104, 189, 37, 38, 55,
// ]);
// import { hexToBytes } from '@noble/ciphers/utils.js'; // hex key
// const key = hexToBytes('4b7f89bac90a1086fef73f5da2cbe93b2fae9dfbf7678ae1f3e75fd118ddf999');
const nonce = randomBytes(24);
const chacha = xchacha20poly1305(key, nonce);
const data = new TextEncoder().encode('hello noble');
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext); // new TextDecoder().decode(data_) === data
```
#### AES-256-GCM 加密
```
import { gcm } from '@noble/ciphers/aes.js';
import { randomBytes } from '@noble/ciphers/utils.js';
const key = randomBytes(32);
const nonce = randomBytes(24);
const data = new TextEncoder().encode('hello noble');
const aes = gcm(key, nonce);
const ciphertext = aes.encrypt(data);
const data_ = aes.decrypt(ciphertext); // new TextDecoder().decode(data_) === data
```
#### managedNonce:自动 nonce 处理
我们提供了在内部管理 nonce 的 API,而不是将其暴露给库用户。
对于 `encrypt`:从 CSPRNG 中获取一个长度为 `nonceBytes` 的 buffer,并将其添加到加密密文之前。
对于 `decrypt`:密文的前 `nonceBytes` 字节将被视为 nonce。
```
import { xchacha20poly1305 } from '@noble/ciphers/chacha.js';
import { hexToBytes, managedNonce } from '@noble/ciphers/utils.js';
const key = hexToBytes('fa686bfdffd3758f6377abbc23bf3d9bdc1a0dda4a6e7f8dbdd579fa1ff6d7e1');
const chacha = managedNonce(xchacha20poly1305)(key); // manages nonces for you
const data = new TextEncoder().encode('hello noble');
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext);
```
#### AES:gcm, siv, ctr, cfb, cbc, ecb, aeskw
```
import { gcm, gcmsiv, aessiv, ctr, cfb, cbc, ecb } from '@noble/ciphers/aes.js';
import { randomBytes } from '@noble/ciphers/utils.js';
const plaintext = new Uint8Array(32).fill(16);
for (let cipher of [gcm, gcmsiv, aessiv]) {
const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
const nonce = randomBytes(12);
const ciphertext_ = cipher(key, nonce).encrypt(plaintext);
const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ctr, cbc, cfb]) {
const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
const nonce = randomBytes(16);
const ciphertext_ = cipher(key, nonce).encrypt(plaintext);
const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ecb]) {
const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
const ciphertext_ = cipher(key).encrypt(plaintext);
const plaintext_ = cipher(key).decrypt(ciphertext_);
}
// AESKW, AESKWP
import { aeskw, aeskwp } from '@noble/ciphers/aes.js';
import { hexToBytes } from '@noble/ciphers/utils.js';
const kek = hexToBytes('000102030405060708090A0B0C0D0E0F');
const keyData = hexToBytes('00112233445566778899AABBCCDDEEFF');
const ciphertext = aeskw(kek).encrypt(keyData);
```
#### AES:友好的 WebCrypto 封装
Noble 实现了 AES。有时人们希望改用内置的 `crypto.subtle`。然而,它的 API 非常糟糕。我们简化了对内置功能的访问。
```
import { gcm, ctr, cbc } from '@noble/ciphers/webcrypto.js';
import { randomBytes } from '@noble/ciphers/utils.js';
const plaintext = new Uint8Array(32).fill(16);
const key = randomBytes(32);
for (const cipher of [gcm]) {
const nonce = randomBytes(12);
const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);
const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ctr, cbc]) {
const nonce = randomBytes(16);
const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);
const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);
}
```
#### 重用数组作为输入和输出
为了避免额外的内存分配,可以在加密和解密调用之间
重用 Uint8Array。
```
import { chacha20poly1305 } from '@noble/ciphers/chacha.js';
import { randomBytes } from '@noble/ciphers/utils.js';
const key = randomBytes(32);
const nonce = randomBytes(12);
const chacha = chacha20poly1305(key, nonce);
const input = new TextEncoder().encode('hello noble'); // length == 12
const inputLength = input.length;
const tagLength = 16;
const buf = new Uint8Array(inputLength + tagLength);
const start = buf.subarray(0, inputLength);
start.set(input); // copy input to buf
chacha.encrypt(start, buf); // encrypt into `buf`
chacha.decrypt(buf, start); // decrypt into `start`
```
xsalsa20poly1305 也支持此功能,但由于其内部机制,
在加密 / 解密时需要额外 32 个字节。
#### 随机数生成
我们提供了用户空间的 CSPRNG(密码学安全的伪随机数生成器)。
最好将其使用限制在非生产、非关键的场景中:例如仅用于测试。
基于 ChaCha 的 CSPRNG 截至 2025 年还没有规范,这使其安全性较低。
```
import { randomBytes } from '@noble/ciphers/utils.js';
import { rngAesCtrDrbg256 } from '@noble/ciphers/aes.js';
import { rngChacha8, rngChacha20 } from '@noble/ciphers/chacha.js';
// 1. Best: WebCrypto
const rnd1 = randomBytes(32);
// 2. AES-CTR DRBG
const seed2 = randomBytes(48);
const rnd2 = rngAesCtrDrbg256(seed2).randomBytes(1024);
// 3. ChaCha8 CSPRNG
const seed3 = randomBytes(32);
const rnd3 = rngChacha8(seed3).randomBytes(1024);
```
#### 使用密码进行加密
将密码直接转换为 Uint8Array 是不安全的。
相反,应该应用如 PBKDF2 / Scrypt / Argon2id 等 KDF 拉伸函数
将密码转换为 AES 密钥。
确保除了密码外还使用了 salt(特定于应用的密钥)。
```
import { xchacha20poly1305 } from '@noble/ciphers/chacha.js';
import { managedNonce } from '@noble/ciphers/utils.js';
import { scrypt } from '@noble/hashes/scrypt.js';
// Convert password into 32-byte key using scrypt
const PASSWORD = 'correct-horse-battery-staple';
const APP_SPECIFIC_SECRET = 'salt-12345678-secret';
const SECURITY_LEVEL = 2 ** 20; // requires 1GB of RAM to calculate
// sync, but scryptAsync is also available
const key = scrypt(PASSWORD, APP_SPECIFIC_SECRET, {
N: SECURITY_LEVEL,
r: 8,
p: 1,
dkLen: 32,
maxmem: 2 ** 30 + 4096,
});
// Use random, managed nonce
const chacha = managedNonce(xchacha20poly1305)(key);
const data = new TextEncoder().encode('hello noble');
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext);
```
## 内部机制
### 选择加密算法
我们建议使用 **XChaCha20-Poly1305**,因为它非常快并且允许随机密钥。
**AES-GCM-SIV** 也是一个好主意,因为它提供了对 nonce 重用的抵抗力。
当这两种都不可用时,**AES-GCM** 是一个不错的选择。
### 如何正确加密
- 使用具有足够熵的不可预测的密钥
- 随机密钥必须使用密码学安全的随机数生成器(CSPRNG),而不是 `Math.random` 等
- 从 KDF 生成的非随机密钥也可以
- 重用密钥是可以的,但要注意密码学密钥磨损规则和[加密限制](#encryption-limits)
- 每次都使用新的 nonce 并且[不要重复使用它](#nonces)
- chacha 和 salsa20 适用于 _永远_ 不重复的顺序计数器:`01, 02...`
- xchacha 和 xsalsa20 可以改用随机 nonce
- AES-GCM 应该使用 12 字节的 nonce:更小的 nonce 存在安全风险
- 首选经过身份验证的加密(AEAD)
- 好的:chacha20poly1305, GCM, GCM-SIV, ChaCha+HMAC, CTR+HMAC, CBC+HMAC
- 不好的:chacha20, 原始 CTR, 原始 CBC
- 在未经身份验证的加密中,翻转位或密文替换不会被检测到
- 多项式 MAC 并非在所有情况下都是完美的:
它们缺乏随机密钥稳健性:MAC 可能会被伪造,并且无法
用于 PAKE 方案。请参阅
[隐形火蜥蜴攻击](https://keymaterial.net/2020/09/07/invisible-salamanders-in-aes-gcm-siv/)。
为了对抗火蜥蜴,可以将 `hash(key)` 包含在密文中,
然而,这会破坏密文的不可区分性:
攻击者会知道使用了哪个密钥——因此可以
改用 `HKDF(key, i)`。
- 不要在不同的协议之间重用密钥
- 例如,在 AES 中使用 ECDH 密钥可能是不好的
- 使用 hkdf 或至少使用 hash 函数来创建子密钥
### Nonce
大多数加密算法需要一个密钥和一个 nonce(又称初始化向量 / IV)来加密数据。
使用不同的明文重复 (密钥, nonce) 对将允许攻击者对其进行解密。
```
ciphertext_a = encrypt(plaintext_a, key, nonce)
ciphertext_b = encrypt(plaintext_b, key, nonce)
stream_diff = xor(ciphertext_a, ciphertext_b) # Break encryption
```
不重复 nonce 的一种方法是使用计数器:
```
for i in 0..:
ciphertext[i] = encrypt(plaintexts[i], key, i)
```
另一种是每次都生成随机 nonce:
```
for i in 0..:
rand_nonces[i] = random()
ciphertext[i] = encrypt(plaintexts[i], key, rand_nonces[i])
```
- 计数器是可以的,但并不总是能够存储当前的计数器值:
例如在去中心化、无法同步的系统中。
- 随机性是可以的,但有一个问题:
ChaCha20 和 AES-GCM 使用 96 位 / 12 字节的 nonce,这意味着更高的碰撞几率。
在上面的例子中,`random()` 可能会发生碰撞并产生重复的 nonce。
对于 GCM 允许的 64 位 nonce,碰撞几率甚至更高——不要使用它们。
- 要安全地使用随机 nonce,请利用 XSalsa20 或 XChaCha:
它们将 nonce 长度增加到了 192 位,最大程度地减少了碰撞的机会。
AES-SIV 也可以。在你无法使用扩展 nonce
算法的情况下,建议进行密钥轮换。hkdf 在这种情况下会非常有效。
### 加密限制
“受保护的消息”意味着被动攻击者成功将 AEAD 方案的密文输出与随机函数的输出区分开来的概率为 `2**-50`。
- 最大消息大小:
- AES-GCM:~68GB, `2**36-256`
- Salsa, ChaCha, XSalsa, XChaCha:~256GB, `2**38-64`
- 在同一密钥下,受保护消息的最大数量:
- AES-GCM:`2**32.5`
- Salsa, ChaCha:`2**46`,但只影响完整性(MAC),不影响机密性(加密)
- XSalsa, XChaCha:`2**72`
- 跨所有密钥的受保护消息的最大数量:
- AES-GCM:`2**69/B`,其中 B 是由一个密钥加密的最大块数。意思是
1KB 为 `2**59`,1MB 为 `2**49`,1GB 为 `2**39`
- Salsa, ChaCha, XSalsa, XChaCha:`2**100`
- 使用**随机 nonce**时,同一密钥下受保护消息的最大数量:
- 适用于带有 `managedNonce` 的 12 字节 nonce:AES-GCM, ChaCha
- 几率为 `2**-50` 时可发送 `2**23` (8M) 条消息,几率为 `2**-32.5` 时可发送 `2**32.5` (4B) 条消息
查看 [draft-irtf-cfrg-aead-limits](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/) 了解详情。
### 已实现的原语
- Salsa20 流密码,发布于 2005 年。
Salsa 的目标是实现不依赖 S-Box 的 AES 替代方案,
因为 S-Box 很难在常数时间内实现。
Salsa20 通常比 AES 更快,这对于运行缓慢、预算有限的手机来说意义重大。
- [XSalsa20](https://cr.yp.to/snuffle/xsalsa-20110204.pdf),扩展 nonce
变体发布于 2008 年。它将 nonce 从 96 位切换到 192 位,
并且可以安全地进行随机选择。
- Nacl / Libsodium 推广了术语“secretbox”,——它其实就是 xsalsa20poly1305。
我们提供了别名以及相应的 seal / open 方法。
"crypto_box" 和 "sealedbox" 可在 [noble-sodium](https://github.com/serenity-kit/noble-sodium) 包中找到。
- 查看 [PDF](https://cr.yp.to/snuffle/salsafamily-20071225.pdf)
和[网站](https://cr.yp.to/snuffle.html)。
- ChaCha20 流密码,发布于 2008 年。在 Salsa20 之后开发,
ChaCha 旨在增加每轮的扩散度。
- [XChaCha20](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha)
扩展 nonce 变体也已提供。与 XSalsa 类似,它可以安全地
与随机生成的 nonce 一起使用。
- 查看
[RFC 8439](https://www.rfc-editor.org/rfc/rfc8439),
[PDF](http://cr.yp.to/chacha/chacha-20080128.pdf) 和
[网站](https://cr.yp.to/chacha.html)。
- AES 是 Rijndael 分组密码的变体,由 NIST 于 2001 年标准化。
我们提供了现有最快的纯 JS 实现。
- 我们支持 AES-128, AES-192 和 AES-256:模式是根据
密钥长度(16, 24, 32)动态选择的。
- AES-GCM-SIV 抗 nonce 误用模式也已提供。我们的 SIV 实现
与 GCM 速度相同:没有性能损失。
该模式在 [RFC 8452](https://www.rfc-editor.org/rfc/rfc8452) 中有描述。
- 有一个独立的 AES-SIV 模式,在 [RFC 5297](https://www.rfc-editor.org/rfc/rfc5297) 中有描述
- 我们还有 AESKW 和 AESKWP,来自
[RFC 3394](https://www.rfc-editor.org/rfc/rfc3394) & [RFC 5649](https://www.rfc-editor.org/rfc/rfc5649)
- 格式保留加密算法 (FPE-FF1) 规范于
[NIST SP 800-38G](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)。
- 查看 [AES 分组模式](#aes-block-modes),
[FIPS 197](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf) 和
[原始提案](https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf)。
- 提供了多项式求值 MAC:Poly1305, AES-GCM 的 GHash 和 AES-SIV 的 Polyval。
- Poly1305([PDF](https://cr.yp.to/mac/poly1305-20050329.pdf),
[网站](https://cr.yp.to/mac.html))
是一种快速且并行的密钥消息认证码,适用于
各种应用。它已在
[RFC 8439](https://www.rfc-editor.org/rfc/rfc8439) 中标准化,现已用于 TLS 1.3。
- Ghash 用于 AES-GCM:参见 NIST SP 800-38G
- Polyval 用于 AES-GCM-SIV:参见 [RFC 8452](https://www.rfc-editor.org/rfc/rfc8452)
##### AES 分组模式
对于非确定性(非 ECB)方案,初始化向量(IV)会混入块/密钥;
并且每个轮次要么依赖于前一个块的密钥,要么依赖于某个计数器。
- **ECB** (电子密码本):确定性加密;相同的明文块产生相同的密文。由于模式泄露而不安全。
参见 [AES Penguin](https://words.filippo.io/the-ecb-penguin/)
- **CBC** (密码分组链接):每个明文块在加密前
与前一个密文块进行 XOR。难以使用:需要适当的填充和 IV。未经身份验证:需要 MAC。
- **CTR** (计数器模式):使用计数器和 IV(nonce)将
分组密码转换为流密码。高效且可并行化。每次加密需要一个唯一的 nonce。未经身份验证:需要 MAC。
- **GCM** (Galois/计数器模式):将 CTR 模式与多项式 MAC 相结合。高效且广泛使用。并不完美:
a) 保守的密钥磨损为 `2**32` (4B) 条消息。
b) 随机 nonce 下的密钥磨损更小:几率为 `2**-50` 时为 `2**23` (8M) 条消息。
c) MAC 可能会被伪造:参见 Poly1305 文档。
- **SIV** (合成 IV):具有抗 nonce 误用能力的 GCM;重复的 nonce 只会泄露明文
相同这一事实。同样受到 GCM 问题的影响:密钥磨损限制和 MAC 伪造。
- **XTS**:专为磁盘加密设计。
类似于 ECB(确定性),但具有对应于
扇区 i 和 16 字节块(扇区的一部分)j 的 `[i][j]` 调整参数。缺少 MAC。
## 安全性
该库已经过审计:
- 在 2026 年 4 月,2.2.0 版本,由我们自己进行(自我审计)
- 范围:所有内容
- [审计后的更改](https://github.com/paulmillr/noble-ciphers/compare/2.2.0..main)
- 在 2024 年 9 月,1.0.0 版本,独立由 [cure53](https://cure53.de) 进行
- PDF:[网站](https://cure53.de/audit-report_noble-crypto-libs.pdf),[仓库内](./audit/2024-09-cure53-audit-nbl4.pdf)
- [审计后的更改](https://github.com/paulmillr/noble-ciphers/compare/1.0.0..main)
- 范围:所有内容
- 该审计由 [OpenSats](https://opensats.org) 资助
它已经过基于属性的、跨库的和 Wycheproof 向量的测试,
并且在[单独的仓库](https://github.com/paulmillr/fuzzing)中进行了模糊测试。
如果你发现任何异常:请调查并报告。
### 常数时间性
我们的目标是算法层面的常数时间。_JIT 编译器_和_垃圾回收器_使得在脚本语言中实现“常数时间”的
[时序攻击](https://en.wikipedia.org/wiki/Timing_attack)抵抗性变得
极其困难。这意味着_任何其他 JS 库都无法具备常数时间性_。即使是静态类型的 Rust,一种没有 GC 的语言,
在某些情况下也[使得实现常数时间变得更加困难](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)。
如果你的目标是绝对安全,请不要使用任何 JS 库——包括对原生库的绑定。
请使用底层库和语言。
该库在 AES 中使用了 T-table,这会
[泄露访问时间](https://cr.yp.to/antiforgery/cachetiming-20050414.pdf)。
出于性能原因,[OpenSSL](https://github.com/openssl/openssl/blob/2f33265039cdbd0e4589c80970e02e208f3f94d2/crypto/aes/aes_core.c#L706) 和
[Go stdlib](https://cs.opensource.google/go/go/+/refs/tags/go1.22.6:src/crypto/aes/const.go;l=90) 中也是这么做的。
分析在 [hal-04652991](https://hal.science/hal-04652991/document) 中提到。
### 供应链安全
- **提交**使用 PGP 密钥签名以防伪造。请务必验证提交签名
- **发布**通过无 token 的 GitHub CI 和 Trusted Publishing 透明进行。请务必验证 [出处日志](https://docs.npmjs.com/generating-provenance-statements) 以确保真实性。
- **极少发布**的实践旨在最大程度地减少最终用户重新审计的需求。
- **依赖**被最小化并严格锁定,以降低供应链风险。
- 我们使用尽可能少的依赖。
- 版本范围已锁定,并使用 npm-diff 检查更改。
- **开发依赖**被排除在最终用户安装之外;它们仅用于开发和构建步骤。
对于此包,有 0 个依赖项;以及少数几个开发依赖项:
- jsbt 用于基准测试 / 测试 / 构建工具,由同一作者开发
- prettier, fast-check 和 typescript 用于代码质量 / 测试生成 / ts 编译
### 随机性
我们依赖于内置的
[`crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues),
它被认为是密码学安全的 PRNG。
浏览器过去曾存在弱点——而且可能再次发生——但实现用户空间的 CSPRNG 会更糟,因为不存在可靠的用户空间高质量熵源。
### 量子计算机
如果建成,具有密码学相关性的量子计算机将允许
利用 Grover 算法以 2^n/2 次操作而不是 2^n 次操作来破解密码。
这意味着 AES128 应该被替换为 AES256。Salsa 和 ChaCha 已经是安全的。
澳大利亚 ASD 禁止在 [2030 年之后](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism/cyber-security-guidelines/guidelines-cryptography)使用 AES128。
## 速度
```
npm run bench
```
基准测试是在 Apple M4 上测量的。
如果你需要真正典范的性能,请切换到 [awasm-noble](https://github.com/paulmillr/awasm-noble)。
```
64B
xsalsa20poly1305 x 735,835 ops/sec @ 1μs/op
chacha20poly1305 x 581,395 ops/sec @ 1μs/op
xchacha20poly1305 x 468,384 ops/sec @ 2μs/op
aes-256-gcm x 201,126 ops/sec @ 4μs/op
aes-256-gcm-siv x 162,284 ops/sec @ 6μs/op
# Unauthenticated encryption
salsa20 x 1,655,629 ops/sec @ 604ns/op
xsalsa20 x 1,400,560 ops/sec @ 714ns/op
chacha20 x 1,996,007 ops/sec @ 501ns/op
xchacha20 x 1,404,494 ops/sec @ 712ns/op
chacha8 x 2,145,922 ops/sec @ 466ns/op
chacha12 x 2,036,659 ops/sec @ 491ns/op
aes-ecb-256 x 1,019,367 ops/sec @ 981ns/op
aes-cbc-256 x 931,966 ops/sec @ 1μs/op
aes-ctr-256 x 954,198 ops/sec @ 1μs/op
1MB
xsalsa20poly1305 x 334 ops/sec @ 2ms/op
chacha20poly1305 x 333 ops/sec @ 2ms/op
xchacha20poly1305 x 334 ops/sec @ 2ms/op
aes-256-gcm x 94 ops/sec @ 10ms/op
aes-256-gcm-siv x 90 ops/sec @ 11ms/op
# Unauthenticated encryption
salsa20 x 831 ops/sec @ 1ms/op
xsalsa20 x 830 ops/sec @ 1ms/op
chacha20 x 804 ops/sec @ 1ms/op
xchacha20 x 797 ops/sec @ 1ms/op
chacha8 x 1,495 ops/sec @ 668μs/op
chacha12 x 1,148 ops/sec @ 871μs/op
aes-ecb-256 x 289 ops/sec @ 3ms/op
aes-cbc-256 x 114 ops/sec @ 8ms/op
aes-ctr-256 x 127 ops/sec @ 7ms/op
# 封装内置 webcrypto
webcrypto ctr-256 x 6,508 ops/sec @ 153μs/op
webcrypto cbc-256 x 1,820 ops/sec @ 549μs/op
webcrypto gcm-256 x 5,106 ops/sec @ 195μs/op
```
与其他实现进行比较:
```
xsalsa20poly1305 (encrypt, 1MB)
├─tweetnacl x 196 mb/sec
├─awasm-noble_threads x 2,318 mb/sec
├─awasm-noble_no_threads x 1,196 mb/sec
└─noble x 305 mb/sec
aes-ctr-256 (encrypt, 1MB)
├─stablelib x 123 mb/sec
├─aesjs x 42 mb/sec
├─awasm-noble_thread x 2,105 mb/sec
├─awasm-noble_no_threads x 272 mb/sec
├─noble_webcrypto x 5,965 mb/sec
└─noble x 124 mb/sec
```
## 升级
支持的 node.js 版本:
- v2:v20.19+(仅限 ESM)
- v1:v14.21+(ESM 和 CJS)
从 ciphers v1 升级时的 v2 更新日志:
- 该包现在是仅限 ESM 的。ESM 终于可以在 node v20.19+ 上从 common.js 加载了
- 所有模块必须使用 `.js` 扩展名
- 旧:`@noble/ciphers/aes`
- 新:`@noble/ciphers/aes.js`
- 这简化了在没有转译器的情况下在浏览器中原生工作
- webcrypto:将 `randomBytes` 和 `managedNonce` 移至 `utils.js`
- ghash, poly1305, polyval:仅允许 Uint8Array 作为 hash 输入,禁止 `string`
- utils:新增 abytes;移除 ahash, toBytes
- 移除模块 `_assert`(使用 `utils`)、`_micro` 和 `crypto`(使用 `webcrypto`)
- 将 TS 编译目标从 es2020 提升至 es2022
- 大幅改进错误消息,使其更具描述性
## 许可证
The MIT License (MIT)
Copyright (c) 2023 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
Copyright (c) 2016 Thomas Pornin
请参阅 LICENSE 文件。
标签:AES, ChaCha20, CMS安全, JavaScript, MITM代理, Salsa20, TypeScript, 加密库, 安全插件, 密码学, 手动系统调用, 数据可视化, 自动化攻击