diff --git a/src/node/hooks/express.js b/src/node/hooks/express.js index b64ab5f3d..98be763c2 100644 --- a/src/node/hooks/express.js +++ b/src/node/hooks/express.js @@ -1,7 +1,7 @@ 'use strict'; const _ = require('underscore'); -const SecretRotator = require('../utils/SecretRotator'); +const SecretRotator = require('../security/SecretRotator'); const cookieParser = require('cookie-parser'); const events = require('events'); const express = require('express'); diff --git a/src/node/utils/SecretRotator.js b/src/node/security/SecretRotator.js similarity index 100% rename from src/node/utils/SecretRotator.js rename to src/node/security/SecretRotator.js diff --git a/src/node/security/crypto.js b/src/node/security/crypto.js new file mode 100644 index 000000000..ebe918509 --- /dev/null +++ b/src/node/security/crypto.js @@ -0,0 +1,15 @@ +'use strict'; + +const crypto = require('crypto'); +const util = require('util'); + + +/** + * Promisified version of Node.js's crypto.hkdf. + */ +exports.hkdf = util.promisify(crypto.hkdf); + +/** + * Promisified version of Node.js's crypto.randomBytes + */ +exports.randomBytes = util.promisify(crypto.randomBytes); \ No newline at end of file diff --git a/src/node/utils/crypto.js b/src/node/utils/crypto.js deleted file mode 100644 index 071b450b1..000000000 --- a/src/node/utils/crypto.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const {Buffer} = require('buffer'); -const crypto = require('crypto'); -const util = require('util'); - -// TODO: Delete this once support for Node.js < 15.0.0 is dropped. -const hkdfFallback = async (digest, ikm, salt, info, keylen) => { - // https://datatracker.ietf.org/doc/html/rfc5869#section-2.2 - const prkHmac = crypto.createHmac(digest, salt); - prkHmac.update(ikm); - const prk = prkHmac.digest(); - - // https://datatracker.ietf.org/doc/html/rfc5869#section-2.3 - let len = 0; - const t = [Buffer.alloc(0)]; - while (len < keylen) { - const hmac = crypto.createHmac(digest, prk); - hmac.update(t[t.length - 1]); - hmac.update(info); - hmac.update(Buffer.from([t.length % 256])); - const tn = hmac.digest(); - t.push(tn); - len += tn.length; - } - const buf = Buffer.concat(t); - return (buf.byteOffset === 0 && buf.buffer.byteLength === keylen - ? buf : Uint8Array.prototype.slice.call(buf, 0, keylen)).buffer; -}; - -/** - * Promisified version of Node.js's crypto.hkdf. - */ -exports.hkdf = crypto.hkdf ? util.promisify(crypto.hkdf) : hkdfFallback; - -/** - * Promisified version of Node.js's crypto.randomBytes - */ -exports.randomBytes = util.promisify(crypto.randomBytes); - -exports.exportedForTesting = { - hkdfFallback, -}; diff --git a/src/tests/backend/specs/SecretRotator.js b/src/tests/backend/specs/SecretRotator.js index a371a4724..1831ef71f 100644 --- a/src/tests/backend/specs/SecretRotator.js +++ b/src/tests/backend/specs/SecretRotator.js @@ -1,9 +1,9 @@ 'use strict'; -const SecretRotator = require('../../../node/utils/SecretRotator'); +const SecretRotator = require('../../../node/security/SecretRotator'); const assert = require('assert').strict; const common = require('../common'); -const crypto = require('../../../node/utils/crypto'); +const crypto = require('../../../node/security/crypto'); const db = require('../../../node/db/DB'); const logger = common.logger; diff --git a/src/tests/backend/specs/crypto.js b/src/tests/backend/specs/crypto.js index 6472b2e85..cde096f01 100644 --- a/src/tests/backend/specs/crypto.js +++ b/src/tests/backend/specs/crypto.js @@ -2,40 +2,10 @@ const assert = require('assert').strict; const {Buffer} = require('buffer'); -const crypto = require('../../../node/utils/crypto'); +const crypto = require('../../../node/security/crypto'); const nodeCrypto = require('crypto'); const util = require('util'); const nodeHkdf = nodeCrypto.hkdf ? util.promisify(nodeCrypto.hkdf) : null; const ab2hex = (ab) => Buffer.from(ab).toString('hex'); - -describe(__filename, function () { - describe('hkdf fallback', function () { - before(async function () { - if (!nodeHkdf) this.skip(); - }); - - const testCases = [ - ['minimal', 'sha256', 1, 0, 0, 1], - ['huge', 'sha512', 1024, 1024, 1024, 16320], - ]; - - for (const [desc, digest, ikmLen, saltLen, infoLen, keyLen] of testCases) { - for (const strings of [false, true]) { - it(`${desc} (${strings ? 'strings' : 'buffers'})`, async function () { - let isi = await Promise.all([ - crypto.randomBytes(ikmLen), - crypto.randomBytes(saltLen), - crypto.randomBytes(infoLen), - ]); - if (strings) isi = isi.map((b) => b.toString('hex').slice(0, b.length)); - const args = [digest, ...isi, keyLen]; - assert.equal( - ab2hex(await crypto.exportedForTesting.hkdfFallback(...args)), - ab2hex(await nodeHkdf(...args))); - }); - } - } - }); -});