diff options
| author | 2022-12-13 00:15:29 -0800 | |
|---|---|---|
| committer | 2022-12-13 00:15:29 -0800 | |
| commit | 5741d4f9b41ae136b315b55260175135aa12b2a0 (patch) | |
| tree | 541cb575f585ce02276a080d333a6c840d9ff8c0 /test/bun.js/crypto-scrypt.test.js | |
| parent | 1bed749d8cdc83bbc53636b11b552b4ed0b2264f (diff) | |
| download | bun-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.js | 265 |
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", + // }); + // } +}); |
