From 87f627a47d20e02b0620575327ff462e5f228da3 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Tue, 11 Jun 2024 12:07:25 -0400 Subject: [PATCH 1/6] wip --- test/benchmark/main.mjs | 56 +++++++++++++++ test/benchmark/mongocrypt_binary_t.bench.mjs | 76 ++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 test/benchmark/main.mjs create mode 100644 test/benchmark/mongocrypt_binary_t.bench.mjs diff --git a/test/benchmark/main.mjs b/test/benchmark/main.mjs new file mode 100644 index 0000000..e72f98c --- /dev/null +++ b/test/benchmark/main.mjs @@ -0,0 +1,56 @@ +/* eslint-disable no-console */ +import util from 'node:util'; +import process from 'node:process'; +import path from 'node:path'; +import child_process, { spawn } from 'node:child_process'; +import events from 'node:events'; +import url from 'node:url'; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +/** Resolves to the root of this repository */ +function resolveRoot(...paths) { + return path.resolve(__dirname, '..', '..', ...paths); +} + +/** `xtrace` style command runner, uses spawn so that stdio is inherited */ +async function run(command, args = [], options = {}) { + const commandDetails = `+ ${command} ${args.join(' ')}${options.cwd ? ` (in: ${options.cwd})` : ''}`; + console.error(commandDetails); + const proc = child_process.spawn(command, args, { + shell: process.platform === 'win32', + stdio: 'inherit', + cwd: resolveRoot('.'), + ...options + }); + await events.once(proc, 'exit'); + + if (proc.exitCode !== 0) throw new Error(`CRASH(${proc.exitCode}): ${commandDetails}`); +} + +function parseArguments() { + const options = { + help: { short: 'h', type: 'boolean', default: false } + }; + + const args = util.parseArgs({ args: process.argv.slice(2), options, allowPositionals: false }); + + if (args.values.help) { + console.log( + `${path.basename(process.argv[1])} ${[...Object.keys(options)] + .filter(k => k !== 'help') + .map(k => `[--${k}=${options[k].type}]`) + .join(' ')}` + ); + process.exit(0); + } + + return {}; +} + +async function main() { + parseArguments(); + bench({ spawn: true }); +} + +await main(); diff --git a/test/benchmark/mongocrypt_binary_t.bench.mjs b/test/benchmark/mongocrypt_binary_t.bench.mjs new file mode 100644 index 0000000..00fa974 --- /dev/null +++ b/test/benchmark/mongocrypt_binary_t.bench.mjs @@ -0,0 +1,76 @@ +import process from 'node:process'; +import { MongoClient, ClientEncryption } from 'mongodb'; + +let { MONGODB_URI = '', CRYPT_SHARED_LIB_PATH = '' } = process.env; +MONGODB_URI.length === 0 ? 'mongodb://127.0.0.1:27017' : MONGODB_URI; +const extraOptions = + CRYPT_SHARED_LIB_PATH.length !== 0 ? { cryptSharedLibPath: CRYPT_SHARED_LIB_PATH } : undefined; + +const LOCAL_KEY = Buffer.from( + 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', + 'base64' +); + +const $jsonSchema = { + properties: { + encrypted: { + encrypt: { + keyId: [{ $binary: { base64: 'LOCALAAAAAAAAAAAAAAAAA==', subType: '04' } }], + bsonType: 'string', + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + } + } + }, + bsonType: 'object' +}; + +let client; + +let ae = { + autoEncryption: { + keyVaultNamespace: 'keyvault.datakeys', + kmsProviders: { local: { key: LOCAL_KEY } }, + bypassAutoEncryption: false, + keyVaultClient: undefined, + extraOptions + } +}; + +async function setupCollection() { + const client = new MongoClient(MONGODB_URI); + const collectionName = 'test_fle_bench'; + const db = client.db('test_fle_bench'); + await db.dropCollection(collectionName).catch(() => {}); + + const clientEncryption = new ClientEncryption(client, { + keyVaultNamespace: 'keyvault.datakeys', + kmsProviders: { local: { key: LOCAL_KEY } } + }); + + const encryptedFields = { + escCollection: 'esc', + eccCollection: 'ecc', + ecocCollection: 'ecoc', + fields: Array.from({ length: 5000 }, (_, i) => ({ + path: `key${i.toString().padStart(4, '0')}`, + bsonType: 'string' + })) + }; + + const { collection } = await clientEncryption.createEncryptedCollection(db, collectionName, { + provider: 'local', + createCollectionOptions: { encryptedFields } + }); + + return collection; +} + +async function main() { + const collection = await setupCollection(); + + await client + .db('test_fle_bench') + .createCollection('test_fle_bench', { validator: { $jsonSchema } }); +} + +export async function bench(options) {} From c7e2a00d230ae34a88528d9ac7f8e6fd495881b2 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Jun 2024 18:06:17 -0400 Subject: [PATCH 2/6] chore(NODE-5455): benchmark FLE --- package-lock.json | 8 +- package.json | 2 +- test/benchmark/main.mjs | 56 -------- test/benchmark/mongocrypt_binary_t.bench.mjs | 76 ---------- test/benchmarks/bench.mjs | 141 +++++++++++++++++++ test/benchmarks/crypto_callbacks.mjs | 87 ++++++++++++ test/benchmarks/keyDocument.json | 24 ++++ 7 files changed, 257 insertions(+), 137 deletions(-) delete mode 100644 test/benchmark/main.mjs delete mode 100644 test/benchmark/mongocrypt_binary_t.bench.mjs create mode 100644 test/benchmarks/bench.mjs create mode 100644 test/benchmarks/crypto_callbacks.mjs create mode 100644 test/benchmarks/keyDocument.json diff --git a/package-lock.json b/package-lock.json index fadf63e..219556c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "@types/mocha": "^10.0.6", "@types/node": "^20.12.7", "@typescript-eslint/eslint-plugin": "^7.7.0", - "bson": "^6.6.0", + "bson": "^6.7.0", "chai": "^4.4.1", "chai-subset": "^1.6.0", "clang-format": "^1.8.0", @@ -1537,9 +1537,9 @@ "dev": true }, "node_modules/bson": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.6.0.tgz", - "integrity": "sha512-BVINv2SgcMjL4oYbBuCQTpE3/VKOSxrOA8Cj/wQP7izSzlBGVomdm+TcUd0Pzy0ytLSSDweCKQ6X3f5veM5LQA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", + "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", "dev": true, "engines": { "node": ">=16.20.1" diff --git a/package.json b/package.json index 590c879..868c48c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@types/mocha": "^10.0.6", "@types/node": "^20.12.7", "@typescript-eslint/eslint-plugin": "^7.7.0", - "bson": "^6.6.0", + "bson": "^6.7.0", "chai": "^4.4.1", "chai-subset": "^1.6.0", "clang-format": "^1.8.0", diff --git a/test/benchmark/main.mjs b/test/benchmark/main.mjs deleted file mode 100644 index e72f98c..0000000 --- a/test/benchmark/main.mjs +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable no-console */ -import util from 'node:util'; -import process from 'node:process'; -import path from 'node:path'; -import child_process, { spawn } from 'node:child_process'; -import events from 'node:events'; -import url from 'node:url'; - -const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); - -/** Resolves to the root of this repository */ -function resolveRoot(...paths) { - return path.resolve(__dirname, '..', '..', ...paths); -} - -/** `xtrace` style command runner, uses spawn so that stdio is inherited */ -async function run(command, args = [], options = {}) { - const commandDetails = `+ ${command} ${args.join(' ')}${options.cwd ? ` (in: ${options.cwd})` : ''}`; - console.error(commandDetails); - const proc = child_process.spawn(command, args, { - shell: process.platform === 'win32', - stdio: 'inherit', - cwd: resolveRoot('.'), - ...options - }); - await events.once(proc, 'exit'); - - if (proc.exitCode !== 0) throw new Error(`CRASH(${proc.exitCode}): ${commandDetails}`); -} - -function parseArguments() { - const options = { - help: { short: 'h', type: 'boolean', default: false } - }; - - const args = util.parseArgs({ args: process.argv.slice(2), options, allowPositionals: false }); - - if (args.values.help) { - console.log( - `${path.basename(process.argv[1])} ${[...Object.keys(options)] - .filter(k => k !== 'help') - .map(k => `[--${k}=${options[k].type}]`) - .join(' ')}` - ); - process.exit(0); - } - - return {}; -} - -async function main() { - parseArguments(); - bench({ spawn: true }); -} - -await main(); diff --git a/test/benchmark/mongocrypt_binary_t.bench.mjs b/test/benchmark/mongocrypt_binary_t.bench.mjs deleted file mode 100644 index 00fa974..0000000 --- a/test/benchmark/mongocrypt_binary_t.bench.mjs +++ /dev/null @@ -1,76 +0,0 @@ -import process from 'node:process'; -import { MongoClient, ClientEncryption } from 'mongodb'; - -let { MONGODB_URI = '', CRYPT_SHARED_LIB_PATH = '' } = process.env; -MONGODB_URI.length === 0 ? 'mongodb://127.0.0.1:27017' : MONGODB_URI; -const extraOptions = - CRYPT_SHARED_LIB_PATH.length !== 0 ? { cryptSharedLibPath: CRYPT_SHARED_LIB_PATH } : undefined; - -const LOCAL_KEY = Buffer.from( - 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', - 'base64' -); - -const $jsonSchema = { - properties: { - encrypted: { - encrypt: { - keyId: [{ $binary: { base64: 'LOCALAAAAAAAAAAAAAAAAA==', subType: '04' } }], - bsonType: 'string', - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - } - } - }, - bsonType: 'object' -}; - -let client; - -let ae = { - autoEncryption: { - keyVaultNamespace: 'keyvault.datakeys', - kmsProviders: { local: { key: LOCAL_KEY } }, - bypassAutoEncryption: false, - keyVaultClient: undefined, - extraOptions - } -}; - -async function setupCollection() { - const client = new MongoClient(MONGODB_URI); - const collectionName = 'test_fle_bench'; - const db = client.db('test_fle_bench'); - await db.dropCollection(collectionName).catch(() => {}); - - const clientEncryption = new ClientEncryption(client, { - keyVaultNamespace: 'keyvault.datakeys', - kmsProviders: { local: { key: LOCAL_KEY } } - }); - - const encryptedFields = { - escCollection: 'esc', - eccCollection: 'ecc', - ecocCollection: 'ecoc', - fields: Array.from({ length: 5000 }, (_, i) => ({ - path: `key${i.toString().padStart(4, '0')}`, - bsonType: 'string' - })) - }; - - const { collection } = await clientEncryption.createEncryptedCollection(db, collectionName, { - provider: 'local', - createCollectionOptions: { encryptedFields } - }); - - return collection; -} - -async function main() { - const collection = await setupCollection(); - - await client - .db('test_fle_bench') - .createCollection('test_fle_bench', { validator: { $jsonSchema } }); -} - -export async function bench(options) {} diff --git a/test/benchmarks/bench.mjs b/test/benchmarks/bench.mjs new file mode 100644 index 0000000..068a154 --- /dev/null +++ b/test/benchmarks/bench.mjs @@ -0,0 +1,141 @@ +// @ts-check +/* eslint-disable no-console */ +import path from 'node:path'; +import url from 'node:url'; +import process from 'node:process'; +import fs from 'node:fs'; +import { EJSON, BSON } from 'bson'; +import { cryptoCallbacks } from './crypto_callbacks.mjs'; +import { MongoCrypt } from '../../lib/index.js'; + +const NEED_MONGO_KEYS = 3; +const READY = 5; +const ERROR = 0; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +let { CRYPT_SHARED_LIB_PATH = '' } = process.env; +const cryptSharedLibPath = CRYPT_SHARED_LIB_PATH.length !== 0 ? CRYPT_SHARED_LIB_PATH : undefined; + +const warmupSecs = 2; +const testInSecs = 57; +const fieldCount = 1500; + +const LOCAL_KEY = new Uint8Array([ + 0x9d, 0x94, 0x4b, 0x0d, 0x93, 0xd0, 0xc5, 0x44, 0xa5, 0x72, 0xfd, 0x32, 0x1b, 0x94, 0x30, 0x90, + 0x23, 0x35, 0x73, 0x7c, 0xf0, 0xf6, 0xc2, 0xf4, 0xda, 0x23, 0x56, 0xe7, 0x8f, 0x04, 0xcc, 0xfa, + 0xde, 0x75, 0xb4, 0x51, 0x87, 0xf3, 0x8b, 0x97, 0xd7, 0x4b, 0x44, 0x3b, 0xac, 0x39, 0xa2, 0xc6, + 0x4d, 0x91, 0x00, 0x3e, 0xd1, 0xfa, 0x4a, 0x30, 0xc1, 0xd2, 0xc6, 0x5e, 0xfb, 0xac, 0x41, 0xf2, + 0x48, 0x13, 0x3c, 0x9b, 0x50, 0xfc, 0xa7, 0x24, 0x7a, 0x2e, 0x02, 0x63, 0xa3, 0xc6, 0x16, 0x25, + 0x51, 0x50, 0x78, 0x3e, 0x0f, 0xd8, 0x6e, 0x84, 0xa6, 0xec, 0x8d, 0x2d, 0x24, 0x47, 0xe5, 0xaf +]); + +const padNum = i => i.toString().padStart(4, '0'); +const kmsProviders = { local: { key: LOCAL_KEY } }; +const algorithm = 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'; +const keyDocument = EJSON.parse( + await fs.promises.readFile(path.join(__dirname, 'keyDocument.json'), 'utf8'), + { relaxed: false } +); + +function createEncryptedDocument(mongoCrypt) { + const { _id: keyId } = keyDocument; + + const encrypted = {}; + + for (let i = 0; i < fieldCount; i++) { + const key = `key${padNum(i + 1)}`; + const v = `value ${padNum(i + 1)}`; + + const ctx = mongoCrypt.makeExplicitEncryptionContext(BSON.serialize({ v }), { + keyId: keyId.buffer, + algorithm + }); + + if (ctx.state === NEED_MONGO_KEYS) { + ctx.addMongoOperationResponse(BSON.serialize(keyDocument)); + ctx.finishMongoOperation(); + } + + console.assert(ctx.state === READY); + const result = ctx.finalize(); + console.assert(ctx.state !== ERROR); + const { v: encryptedValue } = BSON.deserialize(result); + encrypted[key] = encryptedValue; + } + + return encrypted; +} + +function measureMedianOpsPerSecOfDecrypt(mongoCrypt, toDecrypt, seconds) { + let operationsPerSecond = []; + + for (let second = 0; second < seconds; second++) { + const startTime = performance.now(); + /** @type {number | null} */ + let operations = 0; + + while (performance.now() - startTime < 1000) { + const ctx = mongoCrypt.makeDecryptionContext(toDecrypt); + if (ctx.state === NEED_MONGO_KEYS) { + // We ran over a minute + operations = null; + break; + } + + if (ctx.state !== READY) throw new Error(`NOT READY: ${ctx.state}`); + + ctx.finalize(); + operations += 1; + } + + if (operations != null) operationsPerSecond.push(operations); + } + + console.log('samples taken: ', operationsPerSecond.length); + operationsPerSecond.sort((a, b) => a - b); + return operationsPerSecond[Math.floor(operationsPerSecond.length / 2)]; +} + +function main() { + console.log( + `BenchmarkRunner is using ` + + `libmongocryptVersion=${MongoCrypt.libmongocryptVersion}, ` + + `warmupSecs=${warmupSecs}, ` + + `testInSecs=${testInSecs}` + ); + + const mongoCryptOptions = { + kmsProviders: BSON.serialize(kmsProviders), + cryptoCallbacks + }; + if (cryptSharedLibPath) mongoCryptOptions.cryptSharedLibPath = cryptSharedLibPath; + + const mongoCrypt = new MongoCrypt(mongoCryptOptions); + + const encrypted = createEncryptedDocument(mongoCrypt); + const toDecrypt = BSON.serialize(encrypted); + + const created_at = new Date(); + + // warmup + measureMedianOpsPerSecOfDecrypt(mongoCrypt, toDecrypt, warmupSecs); + // bench + const medianOpsPerSec = measureMedianOpsPerSecOfDecrypt(mongoCrypt, toDecrypt, testInSecs); + + const completed_at = new Date(); + + console.log(`Decrypting 1500 fields median ops/sec : ${medianOpsPerSec}`); + + const perfSend = { + info: { test_name: 'javascript_decrypt_1500' }, + created_at, + completed_at, + artifacts: [], + metrics: [{ name: 'medianOpsPerSec', type: 'THROUGHPUT', value: medianOpsPerSec }], + sub_tests: [] + }; + console.log(perfSend); +} + +main(); diff --git a/test/benchmarks/crypto_callbacks.mjs b/test/benchmarks/crypto_callbacks.mjs new file mode 100644 index 0000000..1190351 --- /dev/null +++ b/test/benchmarks/crypto_callbacks.mjs @@ -0,0 +1,87 @@ +import crypto from 'node:crypto'; + +function makeAES256Hook(method, mode) { + return function (key, iv, input, output) { + let result; + try { + const cipher = crypto[method](mode, key, iv); + cipher.setAutoPadding(false); + result = cipher.update(input); + const final = cipher.final(); + if (final.length > 0) { + result = Buffer.concat([result, final]); + } + } catch (e) { + return e; + } + result.copy(output); + return result.length; + }; +} + +function randomHook(buffer, count) { + try { + crypto.randomFillSync(buffer, 0, count); + } catch (e) { + return e; + } + return count; +} + +function sha256Hook(input, output) { + let result; + try { + result = crypto.createHash('sha256').update(input).digest(); + } catch (e) { + return e; + } + result.copy(output); + return result.length; +} + +function makeHmacHook(algorithm) { + return (key, input, output) => { + let result; + try { + result = crypto.createHmac(algorithm, key).update(input).digest(); + } catch (e) { + return e; + } + result.copy(output); + return result.length; + }; +} + +function signRsaSha256Hook(key, input, output) { + let result; + try { + const signer = crypto.createSign('sha256WithRSAEncryption'); + const privateKey = Buffer.from( + `-----BEGIN PRIVATE KEY-----\n${key.toString('base64')}\n-----END PRIVATE KEY-----\n` + ); + result = signer.update(input).end().sign(privateKey); + } catch (e) { + return e; + } + result.copy(output); + return result.length; +} + +const aes256CbcEncryptHook = makeAES256Hook('createCipheriv', 'aes-256-cbc'); +const aes256CbcDecryptHook = makeAES256Hook('createDecipheriv', 'aes-256-cbc'); +const aes256CtrEncryptHook = makeAES256Hook('createCipheriv', 'aes-256-ctr'); +const aes256CtrDecryptHook = makeAES256Hook('createDecipheriv', 'aes-256-ctr'); +const hmacSha512Hook = makeHmacHook('sha512'); +const hmacSha256Hook = makeHmacHook('sha256'); + +export const cryptoCallbacks = { + randomHook, + sha256Hook, + signRsaSha256Hook, + aes256CbcEncryptHook, + aes256CbcDecryptHook, + aes256CtrEncryptHook, + aes256CtrDecryptHook, + hmacSha512Hook, + hmacSha256Hook +}; diff --git a/test/benchmarks/keyDocument.json b/test/benchmarks/keyDocument.json new file mode 100644 index 0000000..8ab2724 --- /dev/null +++ b/test/benchmarks/keyDocument.json @@ -0,0 +1,24 @@ +{ + "_id": { + "$binary": { + "base64": "YWFhYWFhYWFhYWFhYWFhYQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ACR7Hm33dDOAAD7l2ubZhSpSUWK8BkALUY+qW3UgBAEcTV8sBwZnaAWnzDsmrX55dgmYHWfynDlJogC/e33u6pbhyXvFTs5ow9OLCuCWBJ39T/Ivm3kMaZJybkejY0V+uc4UEdHvVVz/SbitVnzs2WXdMGmo1/HmDRrxGYZjewFslquv8wtUHF5pyB+QDlQBd/al9M444/8bJZFbMSmtIg==", + "subType": "00" + } + }, + "creationDate": { + "$date": "2023-08-21T14:28:20.875Z" + }, + "updateDate": { + "$date": "2023-08-21T14:28:20.875Z" + }, + "status": 0, + "masterKey": { + "provider": "local" + } +} From f87296a72eb62f4b332f5fce5d5742b67c75e429 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 12 Jun 2024 18:10:00 -0400 Subject: [PATCH 3/6] chore: print runtime and hw info --- test/benchmarks/bench.mjs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/benchmarks/bench.mjs b/test/benchmarks/bench.mjs index 068a154..22ad8c1 100644 --- a/test/benchmarks/bench.mjs +++ b/test/benchmarks/bench.mjs @@ -1,5 +1,6 @@ // @ts-check /* eslint-disable no-console */ +import os from 'node:os'; import path from 'node:path'; import url from 'node:url'; import process from 'node:process'; @@ -98,6 +99,21 @@ function measureMedianOpsPerSecOfDecrypt(mongoCrypt, toDecrypt, seconds) { } function main() { + const hw = os.cpus(); + const ram = os.totalmem() / 1024 ** 3; + const platform = { name: hw[0].model, cores: hw.length, ram: `${ram}GB` }; + + const systemInfo = () => + [ + `\n- cpu: ${platform.name}`, + `- node: ${process.version}`, + `- cores: ${platform.cores}`, + `- arch: ${os.arch()}`, + `- os: ${process.platform} (${os.release()})`, + `- ram: ${platform.ram}\n` + ].join('\n'); + console.log(systemInfo()); + console.log( `BenchmarkRunner is using ` + `libmongocryptVersion=${MongoCrypt.libmongocryptVersion}, ` + From a68889e344cad95fd5d2441bf6c1ac8e24119128 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 13 Jun 2024 11:10:39 -0400 Subject: [PATCH 4/6] perf: make use of mongocrypt_binary_t fields instead of getter functions --- addon/mongocrypt.cc | 25 +++++++++++-------------- test/benchmarks/bench.mjs | 8 ++------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/addon/mongocrypt.cc b/addon/mongocrypt.cc index 4ed2a8a..3428495 100644 --- a/addon/mongocrypt.cc +++ b/addon/mongocrypt.cc @@ -45,14 +45,11 @@ std::unique_ptr Uint8ArrayToBinary } Uint8Array BufferFromBinary(Env env, mongocrypt_binary_t* binary) { - const uint8_t* data = mongocrypt_binary_data(binary); - size_t len = mongocrypt_binary_len(binary); - return Buffer::Copy(env, data, len); + return Buffer::Copy(env, (uint8_t*)binary->data, binary->len); } Uint8Array BufferWithLengthOf(Env env, mongocrypt_binary_t* binary) { - size_t len = mongocrypt_binary_len(binary); - return Buffer::New(env, len); + return Buffer::New(env, binary->len); } Uint8Array Uint8ArrayFromValue(Napi::Value v, std::string argument_name) { @@ -64,13 +61,13 @@ Uint8Array Uint8ArrayFromValue(Napi::Value v, std::string argument_name) { } void CopyBufferData(mongocrypt_binary_t* out, Uint8Array buffer, size_t count) { - assert(count <= mongocrypt_binary_len(out)); + assert(count <= out->len); assert(count <= buffer.ByteLength()); - memcpy(mongocrypt_binary_data(out), buffer.Data(), count); + memcpy(out->data, buffer.Data(), count); } void CopyBufferData(mongocrypt_binary_t* out, Uint8Array buffer) { - CopyBufferData(out, buffer, mongocrypt_binary_len(out)); + CopyBufferData(out, buffer, out->len); } std::string errorStringFromStatus(mongocrypt_t* crypt) { @@ -184,12 +181,12 @@ static bool aes_256_generic_hook(MongoCrypt* mongoCrypt, Uint8Array keyBuffer = BufferFromBinary(env, key); Uint8Array ivBuffer = BufferFromBinary(env, iv); Uint8Array inBuffer = BufferFromBinary(env, in); - Uint8Array outBuffer = BufferWithLengthOf(env, out); + Uint8Array outputBuffer = BufferWithLengthOf(env, out); Value result; try { result = - hook.Call(std::initializer_list{keyBuffer, ivBuffer, inBuffer, outBuffer}); + hook.Call(std::initializer_list{keyBuffer, ivBuffer, inBuffer, outputBuffer}); } catch (...) { return false; } @@ -200,7 +197,7 @@ static bool aes_256_generic_hook(MongoCrypt* mongoCrypt, } *bytes_written = result.ToNumber().Uint32Value(); - CopyBufferData(out, outBuffer, *bytes_written); + CopyBufferData(out, outputBuffer, *bytes_written); return true; } @@ -262,11 +259,11 @@ bool MongoCrypt::setupCryptoHooks() { HandleScope scope(env); Function hook = mongoCrypt->GetCallback("randomHook"); - Uint8Array outBuffer = BufferWithLengthOf(env, out); + Uint8Array outputBuffer = BufferWithLengthOf(env, out); Napi::Value result; try { result = - hook.Call(std::initializer_list{outBuffer, Number::New(env, count)}); + hook.Call(std::initializer_list{outputBuffer, Number::New(env, count)}); } catch (...) { return false; } @@ -276,7 +273,7 @@ bool MongoCrypt::setupCryptoHooks() { return false; } - CopyBufferData(out, outBuffer); + CopyBufferData(out, outputBuffer); return true; }; diff --git a/test/benchmarks/bench.mjs b/test/benchmarks/bench.mjs index 22ad8c1..2a61cdd 100644 --- a/test/benchmarks/bench.mjs +++ b/test/benchmarks/bench.mjs @@ -15,8 +15,7 @@ const ERROR = 0; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); -let { CRYPT_SHARED_LIB_PATH = '' } = process.env; -const cryptSharedLibPath = CRYPT_SHARED_LIB_PATH.length !== 0 ? CRYPT_SHARED_LIB_PATH : undefined; +const { CRYPT_SHARED_LIB_PATH: cryptSharedLibPath = '' } = process.env; const warmupSecs = 2; const testInSecs = 57; @@ -121,10 +120,7 @@ function main() { `testInSecs=${testInSecs}` ); - const mongoCryptOptions = { - kmsProviders: BSON.serialize(kmsProviders), - cryptoCallbacks - }; + const mongoCryptOptions = { kmsProviders: BSON.serialize(kmsProviders), cryptoCallbacks }; if (cryptSharedLibPath) mongoCryptOptions.cryptSharedLibPath = cryptSharedLibPath; const mongoCrypt = new MongoCrypt(mongoCryptOptions); From de52a5ccb3e442a6be8f4d4edb21b77c37bce393 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 13 Jun 2024 11:14:47 -0400 Subject: [PATCH 5/6] chore: lint --- addon/mongocrypt.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/mongocrypt.cc b/addon/mongocrypt.cc index 3428495..70046ca 100644 --- a/addon/mongocrypt.cc +++ b/addon/mongocrypt.cc @@ -185,8 +185,8 @@ static bool aes_256_generic_hook(MongoCrypt* mongoCrypt, Value result; try { - result = - hook.Call(std::initializer_list{keyBuffer, ivBuffer, inBuffer, outputBuffer}); + result = hook.Call( + std::initializer_list{keyBuffer, ivBuffer, inBuffer, outputBuffer}); } catch (...) { return false; } From 6decb68f372e2bdb387b9f0f37160d44b05decde Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 13 Jun 2024 14:33:57 -0400 Subject: [PATCH 6/6] chore: fix assertions make crypto configurable --- test/benchmarks/bench.mjs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/benchmarks/bench.mjs b/test/benchmarks/bench.mjs index 2a61cdd..7062a5d 100644 --- a/test/benchmarks/bench.mjs +++ b/test/benchmarks/bench.mjs @@ -15,7 +15,8 @@ const ERROR = 0; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); -const { CRYPT_SHARED_LIB_PATH: cryptSharedLibPath = '' } = process.env; +const { CRYPT_SHARED_LIB_PATH: cryptSharedLibPath = '', BENCH_WITH_NATIVE_CRYPTO = '' } = + process.env; const warmupSecs = 2; const testInSecs = 57; @@ -57,9 +58,9 @@ function createEncryptedDocument(mongoCrypt) { ctx.finishMongoOperation(); } - console.assert(ctx.state === READY); + if (ctx.state !== READY) throw new Error(`not ready: [${ctx.state}] ${ctx.status.message}`); const result = ctx.finalize(); - console.assert(ctx.state !== ERROR); + if (ctx.state === ERROR) throw new Error(`error: [${ctx.state}] ${ctx.status.message}`); const { v: encryptedValue } = BSON.deserialize(result); encrypted[key] = encryptedValue; } @@ -120,7 +121,8 @@ function main() { `testInSecs=${testInSecs}` ); - const mongoCryptOptions = { kmsProviders: BSON.serialize(kmsProviders), cryptoCallbacks }; + const mongoCryptOptions = { kmsProviders: BSON.serialize(kmsProviders) }; + if (!BENCH_WITH_NATIVE_CRYPTO) mongoCryptOptions.cryptoCallbacks = cryptoCallbacks; if (cryptSharedLibPath) mongoCryptOptions.cryptSharedLibPath = cryptSharedLibPath; const mongoCrypt = new MongoCrypt(mongoCryptOptions);