哈希
使用各种具备密码学安全性的算法对密码进行哈希处理和验证的实用函数
Bun.password
Bun.password 是一组使用多种密码学安全算法进行密码哈希和验证的实用函数集合。
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password);
// => $argon2id$v=19$m=65536,t=2,p=1$tFq+9AVr1bfPxQdh6E8DQRhEXg/M/SqYCNu6gVdRRNs$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
const isMatch = await Bun.password.verify(password, hash);
// => true
Bun.password.hash 的第二个参数是一个用于选择和配置哈希算法的参数对象。
const password = "super-secure-pa$$word";
// 使用 argon2(默认)
const argonHash = await Bun.password.hash(password, {
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
memoryCost: 8, // 内存使用量,单位为 kibibytes(最小为 8)
timeCost: 3, // 迭代次数
});
// 使用 bcrypt
const bcryptHash = await Bun.password.hash(password, {
algorithm: "bcrypt",
cost: 4, // 数值范围 4-31
});
用于创建哈希的算法会存储在哈希本身中。使用 bcrypt 时,Bun 会以 模块化密码格式 对返回的哈希进行编码,以兼容大多数现有的 bcrypt 实现。使用 argon2 时,Bun 会以较新的 PHC 格式 对结果进行编码。
verify 函数会从输入哈希中检测算法,无论其采用 PHC 格式还是 MCF 格式编码,并使用匹配的验证方法。
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password, {
/* 配置 */
});
const isMatch = await Bun.password.verify(password, hash);
// => true
所有函数也都提供同步版本。这些函数的计算成本较高,因此阻塞式 API 可能会降低应用程序性能。
const password = "super-secure-pa$$word";
const hash = Bun.password.hashSync(password, {
/* 配置 */
});
const isMatch = Bun.password.verifySync(password, hash);
// => true
盐值
Bun.password.hash 会自动生成盐值,并将其包含在哈希中。
bcrypt — 模块化密码格式
在下面的 模块化密码格式 哈希示例中使用了 bcrypt:
输入:
await Bun.password.hash("hello", {
algorithm: "bcrypt",
});
输出:
$2b$10$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi
格式由以下部分组成:
bcrypt:$2brounds:$10- 轮数(实际轮数的以 2 为底的对数)salt:Lyj9kHYZtiyfxh2G60TEfehash:qs7xkkGi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
默认情况下,bcrypt 库会截断长度超过 72 字节的密码。Bun.password.hash 使用 bcrypt 算法时,不会静默截断密码,而是会先使用 SHA-512 对任何长度超过 72 字节的密码进行哈希,然后再将其传递给 bcrypt。
await Bun.password.hash("hello".repeat(100), {
algorithm: "bcrypt",
});
argon2 - PHC 格式
以下为采用 PHC 格式 的哈希(使用 argon2):
输入:
await Bun.password.hash("hello", {
algorithm: "argon2id",
});
输出:
$argon2id$v=19$m=65536,t=2,p=1$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOs$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI
格式由以下部分组成:
- 算法:
$argon2id - 版本:
$v=19 - 内存成本:
65536 - 迭代次数:
t=2 - 并行度:
p=1 - 盐值:
$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOs - 哈希值:
$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI
Bun.hash
Bun.hash 是一组用于非密码学哈希的实用工具。非密码学哈希算法优化的是计算速度而非抗碰撞性或安全性。
标准的 Bun.hash 函数使用 Wyhash,从任意大小的输入生成 64 位哈希值。
Bun.hash("some data here");
// 11562320457524636935n
输入可以是字符串、TypedArray、DataView、ArrayBuffer 或 SharedArrayBuffer。
const arr = new Uint8Array([1, 2, 3, 4]);
Bun.hash("some data here");
Bun.hash(arr);
Bun.hash(arr.buffer);
Bun.hash(new DataView(arr.buffer));
第二个参数是可选的整数种子。对于 64 位哈希值,如果种子超过 Number.MAX_SAFE_INTEGER,请将其作为 BigInt 传递,以避免精度损失。
Bun.hash("some data here", 1234);
// 15724820720172937558n
其他哈希算法可作为 Bun.hash 的属性使用。每种算法的 API 都相同;32 位哈希值返回 number,64 位哈希值返回 bigint。
Bun.hash.wyhash("data", 1234); // 等同于 Bun.hash()
Bun.hash.crc32("data", 1234);
Bun.hash.adler32("data", 1234);
Bun.hash.cityHash32("data", 1234);
Bun.hash.cityHash64("data", 1234);
Bun.hash.xxHash32("data", 1234);
Bun.hash.xxHash64("data", 1234);
Bun.hash.xxHash3("data", 1234);
Bun.hash.murmur32v3("data", 1234);
Bun.hash.murmur32v2("data", 1234);
Bun.hash.murmur64v2("data", 1234);
Bun.hash.rapidhash("data", 1234);
Bun.CryptoHasher
Bun.CryptoHasher 使用密码学哈希算法对字符串或二进制数据进行增量哈希计算。它支持以下算法:
"blake2b256""blake2b512""blake2s256""md4""md5""ripemd160""sha1""sha224""sha256""sha384""sha512""sha512-224""sha512-256""sha3-224""sha3-256""sha3-384""sha3-512""shake128""shake256"
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.digest();
// Uint8Array(32) [ <byte>, <byte>, ... ]
使用 .update() 向哈希计算器增量传入数据,它接受 string、TypedArray 和 ArrayBuffer。
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.update(new Uint8Array([1, 2, 3]));
hasher.update(new ArrayBuffer(10));
对于字符串,可选的第二个参数用于指定编码(默认为 'utf-8')。支持以下编码:
| 类别 | 编码 |
|---|---|
| 二进制编码 | "base64" "base64url" "hex" |
| 字符编码 | "utf8" "utf-8" "utf16le" "latin1" |
| 旧版字符编码 | "ascii" "binary" "ucs2" "ucs-2" |
hasher.update("hello world"); // defaults to utf8
hasher.update("68656c6c6f", "hex");
hasher.update("hello world", "base64");
hasher.update("hello world", "latin1");
传入所有数据后,使用 .digest() 计算最终哈希值。默认情况下,此方法会返回一个包含哈希值的 Uint8Array。
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.digest();
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
要将哈希值作为字符串获取,请向 .digest() 传入编码:
hasher.digest("base64");
// => "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="
hasher.digest("hex");
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
此外,.digest() 还可以将哈希值写入现有的 TypedArray,而不是分配一个新的数组。
const arr = new Uint8Array(32);
hasher.digest(arr);
console.log(arr);
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
Bun.CryptoHasher 中的 HMAC
Bun.CryptoHasher 可以计算 HMAC 摘要。将密钥传入构造函数。
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
hasher.update("hello world");
console.log(hasher.digest("hex"));
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
HMAC 支持的算法集合更加有限:
"blake2b256""blake2b512""md4""md5""ripemd160""sha1""sha224""sha256""sha384""sha512""sha512-224""sha512-256""sha3-224""sha3-256""sha3-384""sha3-512"
与非 HMAC 的 Bun.CryptoHasher 不同,HMAC Bun.CryptoHasher 实例在调用 .digest() 后不会重置。再次使用同一实例会抛出错误。
只要在调用 .digest() 之前执行,.copy() 和 .update() 等其他方法也都受支持。
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
hasher.update("hello world");
const copy = hasher.copy();
copy.update("!");
console.log(copy.digest("hex"));
// => "3840176c3d8923f59ac402b7550404b28ab11cb0ef1fa199130a5c37864b5497"
console.log(hasher.digest("hex"));
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"