This commit adds extensive documentation for previously undocumented APIs across multiple categories: **Utility APIs** (docs/api/utils.md): - Bun.nanoseconds() - high-precision timing - Bun.indexOfLine() - line boundary detection - Bun.shellEscape() - shell injection prevention - Bun.allocUnsafe() - unsafe memory allocation - Bun.shrink() - memory optimization - Bun.mmap() - memory-mapped file access - Bun.resolve()/resolveSync() - module resolution - Bun.unsafe namespace - low-level operations - Bun.CSRF - CSRF token generation/verification - Enhanced memory management APIs **Compression APIs** (new docs/guides/util/zstd.md + utils.md): - Bun.zstdCompress()/zstdCompressSync() - Bun.zstdDecompress()/zstdDecompressSync() - Performance comparisons and usage patterns **Hashing APIs** (docs/api/hashing.md): - Individual hash classes (MD4, MD5, SHA family) - Instance methods (.update(), .digest()) - Static methods (.hash(), .byteLength) - Security considerations for legacy algorithms **Binary Data APIs** (docs/api/binary-data.md): - Bun.CryptoHasher - hardware-accelerated hashing - Streaming and performance optimization examples **Shell APIs** (docs/runtime/shell.md): - Bun.createParsedShellScript() - script parsing - Bun.createShellInterpreter() - interpreter creation **Macro APIs** (docs/bundler/macros.md): - Bun.registerMacro() - internal macro registration **Embedded Files** (docs/bundler/executables.md): - Enhanced Bun.embeddedFiles documentation - HTTP serving and access patterns Total changes: 1,420+ lines of comprehensive documentation added across 7 files, with practical examples, security considerations, and performance guidance for all documented APIs. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
14 KiB
{% callout %}
Bun implements the createHash and createHmac functions from node:crypto in addition to the Bun-native APIs documented below.
{% /callout %}
Bun.password
Bun.password is a collection of utility functions for hashing and verifying passwords with various cryptographically secure algorithms.
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
The second argument to Bun.password.hash accepts a params object that lets you pick and configure the hashing algorithm.
const password = "super-secure-pa$$word";
// use argon2 (default)
const argonHash = await Bun.password.hash(password, {
algorithm: "argon2id", // "argon2id" | "argon2i" | "argon2d"
memoryCost: 4, // memory usage in kibibytes
timeCost: 3, // the number of iterations
});
// use bcrypt
const bcryptHash = await Bun.password.hash(password, {
algorithm: "bcrypt",
cost: 4, // number between 4-31
});
The algorithm used to create the hash is stored in the hash itself. When using bcrypt, the returned hash is encoded in Modular Crypt Format for compatibility with most existing bcrypt implementations; with argon2 the result is encoded in the newer PHC format.
The verify function automatically detects the algorithm based on the input hash and use the correct verification method. It can correctly infer the algorithm from both PHC- or MCF-encoded hashes.
const password = "super-secure-pa$$word";
const hash = await Bun.password.hash(password, {
/* config */
});
const isMatch = await Bun.password.verify(password, hash);
// => true
Synchronous versions of all functions are also available. Keep in mind that these functions are computationally expensive, so using a blocking API may degrade application performance.
const password = "super-secure-pa$$word";
const hash = Bun.password.hashSync(password, {
/* config */
});
const isMatch = Bun.password.verifySync(password, hash);
// => true
Salt
When you use Bun.password.hash, a salt is automatically generated and included in the hash.
bcrypt - Modular Crypt Format
In the following Modular Crypt Format hash (used by bcrypt):
Input:
await Bun.password.hash("hello", {
algorithm: "bcrypt",
});
Output:
$2b$10$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFi;
The format is composed of:
bcrypt:$2brounds:$10- rounds (log10 of the actual number of rounds)salt:$Lyj9kHYZtiyfxh2G60TEfeqs7xkkGiEFFDi3iJGc50ZG/XJ1sxIFihash:$GzJ8PuBi+K+BVojzPfS5mjnC8OpLGtv8KJqF99eP6a4
By default, the bcrypt library truncates passwords longer than 72 bytes. In Bun, if you pass Bun.password.hash a password longer than 72 bytes and use the bcrypt algorithm, the password will be hashed via SHA-512 before being passed to bcrypt.
await Bun.password.hash("hello".repeat(100), {
algorithm: "bcrypt",
});
So instead of sending bcrypt a 500-byte password silently truncated to 72 bytes, Bun will hash the password using SHA-512 and send the hashed password to bcrypt (only if it exceeds 72 bytes). This is a more secure default behavior.
argon2 - PHC format
In the following PHC format hash (used by argon2):
Input:
await Bun.password.hash("hello", {
algorithm: "argon2id",
});
Output:
$argon2id$v=19$m=65536,t=2,p=1$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOs$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI
The format is composed of:
algorithm:$argon2idversion:$v=19memory cost:65536iterations:t=2parallelism:p=1salt:$xXnlSvPh4ym5KYmxKAuuHVlDvy2QGHBNuI6bJJrRDOshash:$2YY6M48XmHn+s5NoBaL+ficzXajq2Yj8wut3r0vnrwI
Bun.hash
Bun.hash is a collection of utilities for non-cryptographic hashing. Non-cryptographic hashing algorithms are optimized for speed of computation over collision-resistance or security.
The standard Bun.hash functions uses Wyhash to generate a 64-bit hash from an input of arbitrary size.
Bun.hash("some data here");
// 11562320457524636935n
The input can be a string, TypedArray, DataView, ArrayBuffer, or 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));
Optionally, an integer seed can be specified as the second parameter. For 64-bit hashes seeds above Number.MAX_SAFE_INTEGER should be given as BigInt to avoid loss of precision.
Bun.hash("some data here", 1234);
// 15724820720172937558n
Additional hashing algorithms are available as properties on Bun.hash. The API is the same for each, only changing the return type from number for 32-bit hashes to bigint for 64-bit hashes.
Bun.hash.wyhash("data", 1234); // equivalent to 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 is a general-purpose utility class that lets you incrementally compute a hash of string or binary data using a range of cryptographic hash algorithms. The following algorithms are supported:
"blake2b256""blake2b512""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>, ... ]
Once initialized, data can be incrementally fed to to the hasher using .update(). This method accepts string, TypedArray, and ArrayBuffer.
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.update(new Uint8Array([1, 2, 3]));
hasher.update(new ArrayBuffer(10));
If a string is passed, an optional second parameter can be used to specify the encoding (default 'utf-8'). The following encodings are supported:
{% table %}
- Binary encodings
"base64""base64url""hex""binary"
- Character encodings
"utf8""utf-8""utf16le""latin1"
- Legacy character encodings
"ascii""binary""ucs2""ucs-2"
{% /table %}
hasher.update("hello world"); // defaults to utf8
hasher.update("hello world", "hex");
hasher.update("hello world", "base64");
hasher.update("hello world", "latin1");
After the data has been feed into the hasher, a final hash can be computed using .digest(). By default, this method returns a Uint8Array containing the hash.
const hasher = new Bun.CryptoHasher("sha256");
hasher.update("hello world");
hasher.digest();
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
The .digest() method can optionally return the hash as a string. To do so, specify an encoding:
hasher.digest("base64");
// => "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="
hasher.digest("hex");
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
Alternatively, the method can write the hash into a pre-existing TypedArray instance. This may be desirable in some performance-sensitive applications.
const arr = new Uint8Array(32);
hasher.digest(arr);
console.log(arr);
// => Uint8Array(32) [ 185, 77, 39, 185, 147, ... ]
HMAC in Bun.CryptoHasher
Bun.CryptoHasher can be used to compute HMAC digests. To do so, pass the key to the constructor.
const hasher = new Bun.CryptoHasher("sha256", "secret-key");
hasher.update("hello world");
console.log(hasher.digest("hex"));
// => "095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a67"
When using HMAC, a more limited set of algorithms are supported:
"blake2b512""md5""sha1""sha224""sha256""sha384""sha512-224""sha512-256""sha512"
Unlike the non-HMAC Bun.CryptoHasher, the HMAC Bun.CryptoHasher instance is not reset after .digest() is called, and attempting to use the same instance again will throw an error.
Other methods like .copy() and .update() are supported (as long as it's before .digest()), but methods like .digest() that finalize the hasher are not.
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"
Individual Hash Algorithm Classes
In addition to the generic Bun.CryptoHasher, Bun provides individual classes for each supported hash algorithm. These offer a more direct API and can be slightly more performant for specific use cases.
Available Hash Classes
The following individual hash classes are available:
Bun.MD4- MD4 hash algorithm (16 bytes)Bun.MD5- MD5 hash algorithm (16 bytes)Bun.SHA1- SHA-1 hash algorithm (20 bytes)Bun.SHA224- SHA-224 hash algorithm (28 bytes)Bun.SHA256- SHA-256 hash algorithm (32 bytes)Bun.SHA384- SHA-384 hash algorithm (48 bytes)Bun.SHA512- SHA-512 hash algorithm (64 bytes)Bun.SHA512_256- SHA-512/256 hash algorithm (32 bytes)
Instance Methods
Each hash class provides the same interface:
// Create a new hasher instance
const hasher = new Bun.SHA256();
// Update with data (can be called multiple times)
hasher.update("hello");
hasher.update(" world");
// Get the final hash
const hash = hasher.digest("hex");
console.log(hash);
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
The .update() method accepts strings, TypedArray, ArrayBuffer, and Blob objects:
const hasher = new Bun.SHA256();
hasher.update("hello");
hasher.update(new Uint8Array([32, 119, 111, 114, 108, 100])); // " world"
hasher.update(new ArrayBuffer(1));
const result = hasher.digest("hex");
The .digest() method can return the hash in different formats:
const hasher = new Bun.SHA256();
hasher.update("hello world");
// As a Uint8Array (default)
const bytes = hasher.digest();
// As a hex string
const hex = hasher.digest("hex");
// As a base64 string
const base64 = hasher.digest("base64");
// As a base64url string
const base64url = hasher.digest("base64url");
// Write directly into a TypedArray (more efficient)
const buffer = new Uint8Array(32);
hasher.digest(buffer);
{% callout %}
Important: Once .digest() is called on a hasher instance, it cannot be reused. Calling .update() or .digest() again will throw an error. Create a new instance for each hash operation.
{% /callout %}
Static Methods
Each hash class also provides a static .hash() method for one-shot hashing:
// Hash a string and return as hex
const hex = Bun.SHA256.hash("hello world", "hex");
// => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
// Hash and return as Uint8Array
const bytes = Bun.SHA256.hash("hello world");
// Hash directly into a buffer (most efficient)
const buffer = new Uint8Array(32);
Bun.SHA256.hash("hello world", buffer);
Properties
Each hash class has a static byteLength property indicating the output size:
console.log(Bun.SHA256.byteLength); // => 32
console.log(Bun.SHA1.byteLength); // => 20
console.log(Bun.MD5.byteLength); // => 16
Security Considerations
{% callout type="warning" %} Legacy Algorithms: MD4, MD5, and SHA1 are considered cryptographically broken and should not be used for security-sensitive applications. They are provided for compatibility with legacy systems only.
- MD4: Severely broken, avoid entirely
- MD5: Vulnerable to collision attacks, suitable only for checksums
- SHA1: Deprecated due to collision vulnerabilities, avoid for new applications
For new applications, use SHA-256 or higher. {% /callout %}
Performance Characteristics
The individual hash classes are optimized for performance:
- SHA-256: Excellent balance of security and performance, recommended for most use cases
- SHA-512: Faster than SHA-256 on 64-bit systems, larger output
- SHA-384: Truncated SHA-512, good compromise between SHA-256 and SHA-512
- SHA-224: Truncated SHA-256, smaller output when space is constrained
- SHA-512/256: Modern variant of SHA-512 with 256-bit output
Examples
Basic Usage
// Using instance methods for incremental hashing
const hasher = new Bun.SHA256();
hasher.update("The quick brown fox ");
hasher.update("jumps over the lazy dog");
const hash = hasher.digest("hex");
// Using static method for one-shot hashing
const quickHash = Bun.SHA256.hash("The quick brown fox jumps over the lazy dog", "hex");
// Both produce the same result
console.log(hash === quickHash); // => true
Hashing Large Data
// For large data, use the static method or write into a buffer
const data = new Uint8Array(1024 * 1024); // 1MB of data
crypto.getRandomValues(data);
// Method 1: Static method
const hash1 = Bun.SHA256.hash(data, "hex");
// Method 2: Write into existing buffer (avoids allocation)
const output = new Uint8Array(32);
Bun.SHA256.hash(data, output);
const hash2 = Array.from(output, byte => byte.toString(16).padStart(2, '0')).join('');
console.log(hash1 === hash2); // => true
Algorithm Comparison
const data = "hello world";
console.log("MD5: ", Bun.MD5.hash(data, "hex")); // 16 bytes
console.log("SHA1: ", Bun.SHA1.hash(data, "hex")); // 20 bytes
console.log("SHA224: ", Bun.SHA224.hash(data, "hex")); // 28 bytes
console.log("SHA256: ", Bun.SHA256.hash(data, "hex")); // 32 bytes
console.log("SHA384: ", Bun.SHA384.hash(data, "hex")); // 48 bytes
console.log("SHA512: ", Bun.SHA512.hash(data, "hex")); // 64 bytes
console.log("SHA512/256: ", Bun.SHA512_256.hash(data, "hex")); // 32 bytes