執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

雜湊

使用各種具備密碼學安全性的演算法對密碼進行雜湊處理和驗證的實用函式


Bun.password

Bun.password 是一組使用多種密碼學安全演算法進行密碼雜湊和驗證的實用函式集合。

TypeScript
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 的第二個引數是一個用於選擇和設定雜湊演算法的引數物件。

TypeScript
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 格式編碼,並使用匹配的驗證方法。

TypeScript
const password = "super-secure-pa$$word";

const hash = await Bun.password.hash(password, {
  /* 設定 */
});

const isMatch = await Bun.password.verify(password, hash);
// => true

所有函式也都提供同步版本。這些函式的計算成本較高,因此阻塞式 API 可能會降低應用程式效能。

TypeScript
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:

輸入:

TypeScript
await Bun.password.hash("hello", {
  algorithm: "bcrypt",
});

輸出:

shell
$2b$10$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi

格式由以下部分組成:

  • bcrypt:$2b
  • rounds:$10 - 輪數(實際輪數的以 2 為底的對數)
  • salt:Lyj9kHYZtiyfxh2G60TEfe
  • hash:qs7xkkGi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4

預設情況下,bcrypt 庫會截斷長度超過 72 位元組的密碼。Bun.password.hash 使用 bcrypt 演算法時,不會靜默截斷密碼,而是會先使用 SHA-512 對任何長度超過 72 位元組的密碼進行雜湊,然後再將其傳遞給 bcrypt。

TypeScript
await Bun.password.hash("hello".repeat(100), {
  algorithm: "bcrypt",
});

argon2 - PHC 格式

以下為採用 PHC 格式 的雜湊(使用 argon2):

輸入:

TypeScript
await Bun.password.hash("hello", {
  algorithm: "argon2id",
});

輸出:

shell
$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 位雜湊值。

TypeScript
Bun.hash("some data here");
// 11562320457524636935n

輸入可以是字串、TypedArray、DataView、ArrayBuffer 或 SharedArrayBuffer。

TypeScript
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 傳遞,以避免精度損失。

TypeScript
Bun.hash("some data here", 1234);
// 15724820720172937558n

其他雜湊演算法可作為 Bun.hash 的屬性使用。每種演算法的 API 都相同;32 位雜湊值傳回 number,64 位雜湊值傳回 bigint。

TypeScript
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"
TypeScript
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.digest();
// Uint8Array(32) [ <byte>, <byte>, ... ]

使用 .update() 向雜湊計算器增量傳入資料,它接受 string、TypedArray 和 ArrayBuffer。

TypeScript
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"
TypeScript
hasher.update("hello world"); // defaults to utf8
hasher.update("68656c6c6f", "hex");
hasher.update("hello world", "base64");
hasher.update("hello world", "latin1");

傳入所有資料後,使用 .digest() 計算最終雜湊值。預設情況下,此方法會傳回一個包含雜湊值的 Uint8Array。

TypeScript
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");

hasher.digest();
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]

要將雜湊值作為字串獲取,請向 .digest() 傳入編碼:

TypeScript
hasher.digest("base64");
// => "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="

hasher.digest("hex");
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

此外,.digest() 還可以將雜湊值寫入現有的 TypedArray,而不是分配一個新的陣列。

TypeScript
const arr = new Uint8Array(32);

hasher.digest(arr);

console.log(arr);
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]

Bun.CryptoHasher 中的 HMAC

Bun.CryptoHasher 可以計算 HMAC 摘要。將金鑰傳入建構函式。

TypeScript
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() 等其他方法也都受支援。

TypeScript
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"