aboutsummaryrefslogtreecommitdiff
path: root/test/bun.js/crypto-scrypt.test.js
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-13 00:15:29 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-13 00:15:29 -0800
commit5741d4f9b41ae136b315b55260175135aa12b2a0 (patch)
tree541cb575f585ce02276a080d333a6c840d9ff8c0 /test/bun.js/crypto-scrypt.test.js
parent1bed749d8cdc83bbc53636b11b552b4ed0b2264f (diff)
downloadbun-5741d4f9b41ae136b315b55260175135aa12b2a0.tar.gz
bun-5741d4f9b41ae136b315b55260175135aa12b2a0.tar.zst
bun-5741d4f9b41ae136b315b55260175135aa12b2a0.zip
[crypto] Implement `scryptSync`
Fixes https://github.com/oven-sh/bun/issues/1228
Diffstat (limited to '')
-rw-r--r--test/bun.js/crypto-scrypt.test.js265
1 files changed, 265 insertions, 0 deletions
diff --git a/test/bun.js/crypto-scrypt.test.js b/test/bun.js/crypto-scrypt.test.js
new file mode 100644
index 000000000..4b9f632c0
--- /dev/null
+++ b/test/bun.js/crypto-scrypt.test.js
@@ -0,0 +1,265 @@
+// most of these tests are taken from Node.js
+// thank you Node.js team for the tests
+import { expect, it } from "bun:test";
+const crypto = require("crypto");
+
+const assert = {
+ strictEqual: (a, b) => {
+ expect(a).toEqual(b);
+ },
+ deepStrictEqual: (a, b) => {
+ expect(a).toEqual(b);
+ },
+ throws: (fn, err) => {
+ try {
+ fn();
+ throw "Fail";
+ } catch (e) {
+ if (err.name) {
+ expect(e?.name).toEqual(err.name);
+ }
+
+ // if (err.message) {
+ // expect(err.message.test(e?.message)).toBeTruthy();
+ // }
+ if (err.code) {
+ expect(e?.code).toEqual(err.code);
+ }
+
+ expect(e).not.toEqual("Fail");
+ return;
+ }
+ },
+};
+
+const good = [
+ // Zero-length key is legal, functions as a parameter validation check.
+ {
+ pass: "",
+ salt: "",
+ keylen: 0,
+ N: 16,
+ p: 1,
+ r: 1,
+ expected: "",
+ },
+ // Test vectors from https://tools.ietf.org/html/rfc7914#page-13 that
+ // should pass. Note that the test vector with N=1048576 is omitted
+ // because it takes too long to complete and uses over 1 GB of memory.
+ {
+ pass: "",
+ salt: "",
+ keylen: 64,
+ N: 16,
+ p: 1,
+ r: 1,
+ expected:
+ "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442" +
+ "fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906",
+ },
+ {
+ pass: "password",
+ salt: "NaCl",
+ keylen: 64,
+ N: 1024,
+ p: 16,
+ r: 8,
+ expected:
+ "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162" +
+ "2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640",
+ },
+ {
+ pass: "pleaseletmein",
+ salt: "SodiumChloride",
+ keylen: 64,
+ N: 16384,
+ p: 1,
+ r: 8,
+ expected:
+ "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2" +
+ "d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887",
+ },
+ {
+ pass: "",
+ salt: "",
+ keylen: 64,
+ cost: 16,
+ parallelization: 1,
+ blockSize: 1,
+ expected:
+ "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442" +
+ "fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906",
+ },
+ {
+ pass: "password",
+ salt: "NaCl",
+ keylen: 64,
+ cost: 1024,
+ parallelization: 16,
+ blockSize: 8,
+ expected:
+ "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b373162" +
+ "2eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640",
+ },
+ {
+ pass: "pleaseletmein",
+ salt: "SodiumChloride",
+ keylen: 64,
+ cost: 16384,
+ parallelization: 1,
+ blockSize: 8,
+ expected:
+ "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2" +
+ "d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887",
+ },
+];
+
+// Test vectors that should fail.
+const bad = [
+ { N: 1, p: 1, r: 1 }, // N < 2
+ { N: 3, p: 1, r: 1 }, // Not power of 2.
+ { N: 1, cost: 1 }, // Both N and cost
+ // TODO: these should error, but I don't quite understand why.
+ // { p: 1, parallelization: 1 }, // Both p and parallelization
+ // { r: 1, blockSize: 1 }, // Both r and blocksize
+];
+
+// Test vectors where 128*N*r exceeds maxmem.
+const toobig = [
+ { N: 2 ** 16, p: 1, r: 1 }, // N >= 2**(r*16)
+ { N: 2, p: 2 ** 30, r: 1 }, // p > (2**30-1)/r
+ { N: 2 ** 20, p: 1, r: 8 },
+ { N: 2 ** 10, p: 1, r: 8, maxmem: 2 ** 20 },
+];
+
+const badargs = [
+ {
+ args: [],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"password"/ */ },
+ },
+ {
+ args: [null],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"password"/ */ },
+ },
+ {
+ args: [""],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"salt"/ */ },
+ },
+ {
+ args: ["", null],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"salt"/ */ },
+ },
+ {
+ args: ["", ""],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"keylen"/ */ },
+ },
+ {
+ args: ["", "", null],
+ expected: { code: "ERR_INVALID_ARG_TYPE" /*message: /"keylen"/ */ },
+ },
+ // TODO: throw on these
+ // {
+ // args: ["", "", 0.42],
+ // expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
+ // },
+ // {
+ // args: ["", "", -42],
+ // expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
+ // },
+ // {
+ // args: ["", "", 2147485780],
+ // expected: { code: "ERR_OUT_OF_RANGE" /*message: /"keylen"/ */ },
+ // },
+];
+
+it("scrypt good", () => {
+ for (const options of good) {
+ const { pass, salt, keylen, expected } = options;
+ const actual = crypto.scryptSync(pass, salt, keylen, options);
+ assert.strictEqual(actual.toString("hex"), expected);
+ }
+});
+
+it("scrypt bad", () => {
+ for (const options of bad) {
+ const expected = {
+ message: /Invalid scrypt param/,
+ };
+ assert.throws(
+ () => crypto.scryptSync("pass", "salt", 1, options),
+ expected,
+ );
+ }
+});
+
+it("scrypt toobig", () => {
+ for (const options of toobig) {
+ const expected = {
+ message: /Invalid scrypt param/,
+ };
+ assert.throws(
+ () => crypto.scryptSync("pass", "salt", 1, options),
+ expected,
+ );
+ }
+});
+
+it("scrypt defaults eql", () => {
+ {
+ const defaults = { N: 16384, p: 1, r: 8 };
+ const expected = crypto.scryptSync("pass", "salt", 1, defaults);
+ const actual = crypto.scryptSync("pass", "salt", 1);
+ assert.deepStrictEqual(actual.toString("hex"), expected.toString("hex"));
+ }
+});
+
+// TODO: DEFAULT_ENCODING is read-only
+// it("scrypt defaults encoding", () => {
+// {
+// const defaultEncoding = crypto.DEFAULT_ENCODING;
+// const defaults = { N: 16384, p: 1, r: 8 };
+// const expected = crypto.scryptSync("pass", "salt", 1, defaults);
+
+// const testEncoding = "latin1";
+// crypto.DEFAULT_ENCODING = testEncoding;
+// const actual = crypto.scryptSync("pass", "salt", 1);
+// assert.deepStrictEqual(actual, expected.toString(testEncoding));
+
+// crypto.DEFAULT_ENCODING = defaultEncoding;
+// }
+// });
+
+it("scrypt badargs", () => {
+ {
+ for (const { args, expected } of badargs) {
+ assert.throws(() => crypto.scryptSync(...args), expected);
+ }
+ }
+
+ {
+ const expected = { code: "ERR_INVALID_ARG_TYPE" };
+ assert.throws(() => crypto.scryptSync("", "", 42, null), expected);
+ // assert.throws(() => crypto.scryptSync("", "", 42, {}, null), expected);
+ // assert.throws(() => crypto.scryptSync("", "", 42, {}), expected);
+ // assert.throws(() => crypto.scryptSync("", "", 42, {}, {}), expected);
+ }
+
+ // {
+ // // Values for maxmem that do not fit in 32 bits but that are still safe
+ // // integers should be allowed.
+ // crypto.scrypt(
+ // "",
+ // "",
+ // 4,
+ // { maxmem: 2 ** 52 },
+ // common.mustSucceed((actual) => {
+ // assert.strictEqual(actual.toString("hex"), "d72c87d0");
+ // }),
+ // );
+
+ // // Values that exceed Number.isSafeInteger should not be allowed.
+ // assert.throws(() => crypto.scryptSync("", "", 0, { maxmem: 2 ** 53 }), {
+ // code: "ERR_OUT_OF_RANGE",
+ // });
+ // }
+});