From 410dbcf1d5a2f6e566d4b0bf0c28e9df970b56be Mon Sep 17 00:00:00 2001 From: larabr Date: Thu, 12 Oct 2023 10:10:28 +0200 Subject: [PATCH] Fix Node 20 tests: always use NodeCrypto over WebCrypto (#1692) This is also to uniform behaviour across Node versions for now. --- .github/workflows/tests.yml | 2 +- src/crypto/mode/gcm.js | 38 ++++++++++++++++++------------------- src/crypto/random.js | 6 +++--- test/crypto/crypto.js | 2 +- test/crypto/gcm.js | 4 ++-- test/general/packet.js | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5feaa21a..feed0fbe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: node: strategy: matrix: - node-version: [14.x, 16.x, 18.x] + node-version: [14.x, 16.x, 18.x, 20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ name: Node ${{ matrix.node-version }} diff --git a/src/crypto/mode/gcm.js b/src/crypto/mode/gcm.js index 5751ad67..25c7a059 100644 --- a/src/crypto/mode/gcm.js +++ b/src/crypto/mode/gcm.js @@ -47,6 +47,25 @@ async function GCM(cipher, key) { throw new Error('GCM mode supports only AES cipher'); } + if (util.getNodeCrypto()) { // Node crypto library + return { + encrypt: async function(pt, iv, adata = new Uint8Array()) { + const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-gcm', key, iv); + en.setAAD(adata); + const ct = Buffer.concat([en.update(pt), en.final(), en.getAuthTag()]); // append auth tag to ciphertext + return new Uint8Array(ct); + }, + + decrypt: async function(ct, iv, adata = new Uint8Array()) { + const de = new nodeCrypto.createDecipheriv('aes-' + (key.length * 8) + '-gcm', key, iv); + de.setAAD(adata); + de.setAuthTag(ct.slice(ct.length - tagLength, ct.length)); // read auth tag at end of ciphertext + const pt = Buffer.concat([de.update(ct.slice(0, ct.length - tagLength)), de.final()]); + return new Uint8Array(pt); + } + }; + } + if (util.getWebCrypto() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support const _key = await webCrypto.importKey('raw', key, { name: ALGO }, false, ['encrypt', 'decrypt']); @@ -69,25 +88,6 @@ async function GCM(cipher, key) { }; } - if (util.getNodeCrypto()) { // Node crypto library - return { - encrypt: async function(pt, iv, adata = new Uint8Array()) { - const en = new nodeCrypto.createCipheriv('aes-' + (key.length * 8) + '-gcm', key, iv); - en.setAAD(adata); - const ct = Buffer.concat([en.update(pt), en.final(), en.getAuthTag()]); // append auth tag to ciphertext - return new Uint8Array(ct); - }, - - decrypt: async function(ct, iv, adata = new Uint8Array()) { - const de = new nodeCrypto.createDecipheriv('aes-' + (key.length * 8) + '-gcm', key, iv); - de.setAAD(adata); - de.setAuthTag(ct.slice(ct.length - tagLength, ct.length)); // read auth tag at end of ciphertext - const pt = Buffer.concat([de.update(ct.slice(0, ct.length - tagLength)), de.final()]); - return new Uint8Array(pt); - } - }; - } - return { encrypt: async function(pt, iv, adata) { return AES_GCM.encrypt(pt, key, iv, adata); diff --git a/src/crypto/random.js b/src/crypto/random.js index 9d3afe80..022bb4aa 100644 --- a/src/crypto/random.js +++ b/src/crypto/random.js @@ -33,11 +33,11 @@ const nodeCrypto = util.getNodeCrypto(); */ export function getRandomBytes(length) { const buf = new Uint8Array(length); - if (typeof crypto !== 'undefined' && crypto.getRandomValues) { - crypto.getRandomValues(buf); - } else if (nodeCrypto) { + if (nodeCrypto) { const bytes = nodeCrypto.randomBytes(buf.length); buf.set(bytes); + } else if (typeof crypto !== 'undefined' && crypto.getRandomValues) { + crypto.getRandomValues(buf); } else { throw new Error('No secure random number generator available.'); } diff --git a/test/crypto/crypto.js b/test/crypto/crypto.js index 68009ec3..8c5417bc 100644 --- a/test/crypto/crypto.js +++ b/test/crypto/crypto.js @@ -255,7 +255,7 @@ module.exports = () => describe('API functional testing', function() { // test using webCrypto const sinonSandbox = sandbox.create(); const webCrypto = util.getWebCrypto(); - if (webCrypto) { + if (webCrypto && !util.getNodeCrypto()) { const webCryptoSpy = sinonSandbox.spy(webCrypto, 'encrypt'); try { await testCFB('12345678901234567890123456789012345678901234567890', { ...openpgp.config, minBytesForWebCrypto: 0 }); diff --git a/test/crypto/gcm.js b/test/crypto/gcm.js index 9896e3c4..d3b0f01b 100644 --- a/test/crypto/gcm.js +++ b/test/crypto/gcm.js @@ -47,8 +47,8 @@ module.exports = () => describe('Symmetric AES-GCM (experimental)', function() { const key = crypto.generateSessionKey(algo); const iv = crypto.random.getRandomBytes(crypto.mode.gcm.ivLength); - const nativeEncryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'encrypt') : sinonSandbox.spy(nodeCrypto, 'createCipheriv'); - const nativeDecryptSpy = webCrypto ? sinonSandbox.spy(webCrypto, 'decrypt') : sinonSandbox.spy(nodeCrypto, 'createDecipheriv'); + const nativeEncryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createCipheriv') : sinonSandbox.spy(webCrypto, 'encrypt'); + const nativeDecryptSpy = nodeCrypto ? sinonSandbox.spy(nodeCrypto, 'createDecipheriv') : sinonSandbox.spy(webCrypto, 'decrypt'); nativeEncrypt || disableNative(); let modeInstance = await crypto.mode.gcm(algo, key); diff --git a/test/general/packet.js b/test/general/packet.js index 251e2e25..212e874f 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -202,7 +202,7 @@ module.exports = () => describe('Packet', function() { it('Sym. encrypted AEAD protected packet is encrypted in parallel (AEAD, GCM)', async function() { const webCrypto = util.getWebCrypto(); - if (!webCrypto) return; + if (!webCrypto || util.getNodeCrypto()) return; const encryptStub = cryptStub(webCrypto, 'encrypt'); const decryptStub = cryptStub(webCrypto, 'decrypt');