mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
* feat: add static crypto utility support * fix: match Node crypto digest errors
74 lines
3.7 KiB
JavaScript
74 lines
3.7 KiB
JavaScript
// The island's node:crypto shim, differentially against Node: the
|
|
// hashing slice byte-exact (md5/sha1/sha256 digests and HMACs ride the
|
|
// same C implementations the static lowerings use), pbkdf2 over the HMAC
|
|
// bridge, Node's exact error shapes for unknown digests / finalized
|
|
// hashes / timingSafeEqual length mismatches, and shape-only checks for
|
|
// the randomness surface (values are random; lengths and types are not).
|
|
import crypto, { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
|
|
export async function report() {
|
|
const lines = [];
|
|
const push = (label, v) => lines.push(label + " " + v);
|
|
const errOf = (fn) => {
|
|
try {
|
|
fn();
|
|
return "no-throw";
|
|
} catch (e) {
|
|
return (e.code || e.name) + ":" + e.message;
|
|
}
|
|
};
|
|
const unsupportedAlgorithm = () => "nope";
|
|
|
|
for (const alg of ["md5", "sha1", "sha256"]) {
|
|
push(alg + "-empty:", createHash(alg).digest("hex"));
|
|
push(alg + "-abc:", createHash(alg).update("abc").digest("hex"));
|
|
push(alg + "-chunks:", createHash(alg).update("a").update(Buffer.from("bc")).digest("base64"));
|
|
push(alg + "-unicode:", createHash(alg).update("héllo ☃").digest("hex"));
|
|
push(alg + "-hexin:", createHash(alg).update("deadbeef", "hex").digest("hex"));
|
|
push(alg + "-hmac:", createHmac(alg, "key").update("The quick brown fox").digest("hex"));
|
|
push(alg + "-hmac-longkey:", createHmac(alg, "k".repeat(100)).update("data").digest("hex"));
|
|
}
|
|
const h = createHash("sha256").update("ab");
|
|
const h2 = h.copy();
|
|
h.update("X");
|
|
h2.update("c");
|
|
push("copy:", h2.digest("hex"));
|
|
const fin = createHash("sha1");
|
|
fin.digest();
|
|
push("digest-twice:", errOf(() => fin.digest("hex")));
|
|
push("bad-alg:", errOf(() => createHash(unsupportedAlgorithm())));
|
|
push("one-shot:", crypto.hash("sha256", "abc") + "|" + crypto.hash("sha1", Buffer.from("abc"), "base64"));
|
|
push("digest-buffer:", Buffer.isBuffer(createHash("sha1").update("x").digest()));
|
|
|
|
push("tse:", timingSafeEqual(Buffer.from([1, 2]), Buffer.from([1, 2])) + "|" + timingSafeEqual(Buffer.from([1, 2]), Buffer.from([1, 3])));
|
|
push("tse-len:", errOf(() => timingSafeEqual(Buffer.from([1]), Buffer.from([1, 2]))));
|
|
|
|
const rb = randomBytes(16);
|
|
push("random-shape:", rb.length + "|" + Buffer.isBuffer(rb) + "|" + randomBytes(0).length);
|
|
push("random-neg:", errOf(() => randomBytes(-1)));
|
|
const rf = Buffer.alloc(8);
|
|
const rfr = crypto.randomFillSync(rf, 2, 4);
|
|
push("randomfill:", (rfr === rf) + "|" + rf.readUInt16LE(0) + "|" + rf.readUInt16LE(6));
|
|
let intsOk = true;
|
|
for (let i = 0; i < 100; i++) {
|
|
const v = crypto.randomInt(3, 6);
|
|
if (v < 3 || v >= 6 || !Number.isInteger(v)) intsOk = false;
|
|
}
|
|
push("randomint:", intsOk + "|" + errOf(() => crypto.randomInt(5, 2)));
|
|
push("uuid:", /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(randomUUID()));
|
|
|
|
push("pbkdf2:", crypto.pbkdf2Sync("password", "salt", 3, 20, "sha256").toString("hex"));
|
|
push("pbkdf2-sha1:", crypto.pbkdf2Sync("pw", "st", 2, 25, "sha1").toString("hex"));
|
|
const cb = await new Promise((res) => crypto.pbkdf2("password", "salt", 2, 8, "sha256", (err, dk) => res((err === null ? "null" : String(err)) + ":" + dk.toString("hex"))));
|
|
push("pbkdf2-cb:", cb);
|
|
let callbackSync = true;
|
|
const rbPending = new Promise((res) => randomBytes(4, (err, b) => res(callbackSync + ":" + (err === null ? "null" : String(err)) + ":" + b.length)));
|
|
callbackSync = false;
|
|
const rbcb = await rbPending;
|
|
push("randombytes-cb:", rbcb);
|
|
|
|
push("hashes:", ["md5", "sha1", "sha256"].every((a) => crypto.getHashes().includes(a)));
|
|
push("constants:", crypto.constants.RSA_PKCS1_PADDING + "," + crypto.constants.RSA_PKCS1_OAEP_PADDING);
|
|
return lines.join("\n");
|
|
}
|