From b6200b9dd44dca49efbe4253a7e25f01bae12ca6 Mon Sep 17 00:00:00 2001 From: marco-ippolito Date: Thu, 30 Nov 2023 13:13:26 +0100 Subject: [PATCH] crypto: end of life createCipher and createDecipher --- benchmark/crypto/cipher-stream.js | 101 ------- doc/api/crypto.md | 129 +------- doc/api/deprecations.md | 14 +- lib/crypto.js | 20 -- lib/internal/crypto/cipher.js | 13 - src/crypto/crypto_cipher.cc | 9 - test/parallel/test-crypto-authenticated.js | 113 ------- test/parallel/test-crypto-cipher-decipher.js | 283 ------------------ test/parallel/test-crypto-classes.js | 2 - test/parallel/test-crypto.js | 24 -- .../test-process-emit-warning-from-native.js | 52 ---- 11 files changed, 10 insertions(+), 750 deletions(-) delete mode 100644 benchmark/crypto/cipher-stream.js delete mode 100644 test/parallel/test-crypto-cipher-decipher.js delete mode 100644 test/parallel/test-process-emit-warning-from-native.js diff --git a/benchmark/crypto/cipher-stream.js b/benchmark/crypto/cipher-stream.js deleted file mode 100644 index 4e794f7afdbaac..00000000000000 --- a/benchmark/crypto/cipher-stream.js +++ /dev/null @@ -1,101 +0,0 @@ -'use strict'; -const common = require('../common.js'); - -const bench = common.createBenchmark(main, { - writes: [500], - cipher: ['AES192', 'AES256'], - type: ['asc', 'utf', 'buf'], - len: [2, 1024, 102400, 1024 * 1024], - api: ['legacy', 'stream'], -}, { - flags: ['--no-warnings'], -}); - -function main({ api, cipher, type, len, writes }) { - if (api === 'stream' && /^v0\.[0-8]\./.test(process.version)) { - console.error('Crypto streams not available until v0.10'); - // Use the legacy, just so that we can compare them. - api = 'legacy'; - } - - const crypto = require('crypto'); - const assert = require('assert'); - const alice = crypto.getDiffieHellman('modp5'); - const bob = crypto.getDiffieHellman('modp5'); - - alice.generateKeys(); - bob.generateKeys(); - - const pubEnc = /^v0\.[0-8]/.test(process.version) ? 'binary' : null; - const alice_secret = alice.computeSecret(bob.getPublicKey(), pubEnc, 'hex'); - const bob_secret = bob.computeSecret(alice.getPublicKey(), pubEnc, 'hex'); - - // alice_secret and bob_secret should be the same - assert(alice_secret === bob_secret); - - const alice_cipher = crypto.createCipher(cipher, alice_secret); - const bob_cipher = crypto.createDecipher(cipher, bob_secret); - - let message; - let encoding; - switch (type) { - case 'asc': - message = 'a'.repeat(len); - encoding = 'ascii'; - break; - case 'utf': - message = 'ΓΌ'.repeat(len / 2); - encoding = 'utf8'; - break; - case 'buf': - message = Buffer.alloc(len, 'b'); - break; - default: - throw new Error(`unknown message type: ${type}`); - } - - const fn = api === 'stream' ? streamWrite : legacyWrite; - - // Write data as fast as possible to alice, and have bob decrypt. - // use old API for comparison to v0.8 - bench.start(); - fn(alice_cipher, bob_cipher, message, encoding, writes); -} - -function streamWrite(alice, bob, message, encoding, writes) { - let written = 0; - bob.on('data', (c) => { - written += c.length; - }); - - bob.on('end', () => { - // Gbits - const bits = written * 8; - const gbits = bits / (1024 * 1024 * 1024); - bench.end(gbits); - }); - - alice.pipe(bob); - - while (writes-- > 0) - alice.write(message, encoding); - - alice.end(); -} - -function legacyWrite(alice, bob, message, encoding, writes) { - let written = 0; - let enc, dec; - for (let i = 0; i < writes; i++) { - enc = alice.update(message, encoding); - dec = bob.update(enc); - written += dec.length; - } - enc = alice.final(); - dec = bob.update(enc); - written += dec.length; - dec = bob.final(); - written += dec.length; - const gbits = written / (1024 * 1024 * 1024); - bench.end(gbits); -} diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 3175d391032ae4..02e4951221dcad 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -319,7 +319,7 @@ used in one of two ways: * Using the [`cipher.update()`][] and [`cipher.final()`][] methods to produce the encrypted data. -The [`crypto.createCipher()`][] or [`crypto.createCipheriv()`][] methods are +The [`crypto.createCipheriv()`][] method is used to create `Cipher` instances. `Cipher` objects are not to be created directly using the `new` keyword. @@ -651,7 +651,7 @@ used in one of two ways: * Using the [`decipher.update()`][] and [`decipher.final()`][] methods to produce the unencrypted data. -The [`crypto.createDecipher()`][] or [`crypto.createDecipheriv()`][] methods are +The [`crypto.createDecipheriv()`][] method is used to create `Decipher` instances. `Decipher` objects are not to be created directly using the `new` keyword. @@ -2954,77 +2954,6 @@ added: v15.8.0 Checks the primality of the `candidate`. -### `crypto.createCipher(algorithm, password[, options])` - - - -> Stability: 0 - Deprecated: Use [`crypto.createCipheriv()`][] instead. - -* `algorithm` {string} -* `password` {string|ArrayBuffer|Buffer|TypedArray|DataView} -* `options` {Object} [`stream.transform` options][] -* Returns: {Cipher} - -Creates and returns a `Cipher` object that uses the given `algorithm` and -`password`. - -The `options` argument controls stream behavior and is optional except when a -cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) is used. In that case, the -`authTagLength` option is required and specifies the length of the -authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength` -option is not required but can be used to set the length of the authentication -tag that will be returned by `getAuthTag()` and defaults to 16 bytes. -For `chacha20-poly1305`, the `authTagLength` option defaults to 16 bytes. - -The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On -recent OpenSSL releases, `openssl list -cipher-algorithms` will -display the available cipher algorithms. - -The `password` is used to derive the cipher key and initialization vector (IV). -The value must be either a `'latin1'` encoded string, a [`Buffer`][], a -`TypedArray`, or a `DataView`. - -This function is semantically insecure for all -supported ciphers and fatally flawed for ciphers in counter mode (such as CTR, -GCM, or CCM). - -The implementation of `crypto.createCipher()` derives keys using the OpenSSL -function [`EVP_BytesToKey`][] with the digest algorithm set to MD5, one -iteration, and no salt. The lack of salt allows dictionary attacks as the same -password always creates the same key. The low iteration count and -non-cryptographically secure hash algorithm allow passwords to be tested very -rapidly. - -In line with OpenSSL's recommendation to use a more modern algorithm instead of -[`EVP_BytesToKey`][] it is recommended that developers derive a key and IV on -their own using [`crypto.scrypt()`][] and to use [`crypto.createCipheriv()`][] -to create the `Cipher` object. Users should not use ciphers with counter mode -(e.g. CTR, GCM, or CCM) in `crypto.createCipher()`. A warning is emitted when -they are used in order to avoid the risk of IV reuse that causes -vulnerabilities. For the case when IV is reused in GCM, see [Nonce-Disrespecting -Adversaries][] for details. - ### `crypto.createCipheriv(algorithm, key, iv[, options])` - -> Stability: 0 - Deprecated: Use [`crypto.createDecipheriv()`][] instead. - -* `algorithm` {string} -* `password` {string|ArrayBuffer|Buffer|TypedArray|DataView} -* `options` {Object} [`stream.transform` options][] -* Returns: {Decipher} - -Creates and returns a `Decipher` object that uses the given `algorithm` and -`password` (key). - -The `options` argument controls stream behavior and is optional except when a -cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) is used. In that case, the -`authTagLength` option is required and specifies the length of the -authentication tag in bytes, see [CCM mode][]. -For `chacha20-poly1305`, the `authTagLength` option defaults to 16 bytes. - -This function is semantically insecure for all -supported ciphers and fatally flawed for ciphers in counter mode (such as CTR, -GCM, or CCM). - -The implementation of `crypto.createDecipher()` derives keys using the OpenSSL -function [`EVP_BytesToKey`][] with the digest algorithm set to MD5, one -iteration, and no salt. The lack of salt allows dictionary attacks as the same -password always creates the same key. The low iteration count and -non-cryptographically secure hash algorithm allow passwords to be tested very -rapidly. - -In line with OpenSSL's recommendation to use a more modern algorithm instead of -[`EVP_BytesToKey`][] it is recommended that developers derive a key and IV on -their own using [`crypto.scrypt()`][] and to use [`crypto.createDecipheriv()`][] -to create the `Decipher` object. - ### `crypto.createDecipheriv(algorithm, key, iv[, options])` -Type: Runtime +Type: End-of-Life -Using [`crypto.createCipher()`][] and [`crypto.createDecipher()`][] must be -avoided as they use a weak key derivation function (MD5 with no salt) and static -initialization vectors. It is recommended to derive a key using +`crypto.createCipher()` and `crypto.createDecipher()` have been removed +as they use a weak key derivation function (MD5 with no salt) and static +initialization vectors. +It is recommended to derive a key using [`crypto.pbkdf2()`][] or [`crypto.scrypt()`][] with random salts and to use [`crypto.createCipheriv()`][] and [`crypto.createDecipheriv()`][] to obtain the [`Cipher`][] and [`Decipher`][] objects respectively. @@ -3557,9 +3561,7 @@ The [`util.types.isWebAssemblyCompiledModule`][] API is deprecated. Please use [`console.error()`]: console.md#consoleerrordata-args [`console.log()`]: console.md#consolelogdata-args [`crypto.Certificate()` constructor]: crypto.md#legacy-api -[`crypto.createCipher()`]: crypto.md#cryptocreatecipheralgorithm-password-options [`crypto.createCipheriv()`]: crypto.md#cryptocreatecipherivalgorithm-key-iv-options -[`crypto.createDecipher()`]: crypto.md#cryptocreatedecipheralgorithm-password-options [`crypto.createDecipheriv()`]: crypto.md#cryptocreatedecipherivalgorithm-key-iv-options [`crypto.fips`]: crypto.md#cryptofips [`crypto.pbkdf2()`]: crypto.md#cryptopbkdf2password-salt-iterations-keylen-digest-callback diff --git a/lib/crypto.js b/lib/crypto.js index 41adecc97c2527..ab9b9d99e11b8b 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -138,18 +138,10 @@ function createHash(algorithm, options) { return new Hash(algorithm, options); } -function createCipher(cipher, password, options) { - return new Cipher(cipher, password, options); -} - function createCipheriv(cipher, key, iv, options) { return new Cipheriv(cipher, key, iv, options); } -function createDecipher(cipher, password, options) { - return new Decipher(cipher, password, options); -} - function createDecipheriv(cipher, key, iv, options) { return new Decipheriv(cipher, key, iv, options); } @@ -336,18 +328,6 @@ function getRandomBytesAlias(key) { } ObjectDefineProperties(module.exports, { - createCipher: { - __proto__: null, - enumerable: false, - value: deprecate(createCipher, - 'crypto.createCipher is deprecated.', 'DEP0106'), - }, - createDecipher: { - __proto__: null, - enumerable: false, - value: deprecate(createDecipher, - 'crypto.createDecipher is deprecated.', 'DEP0106'), - }, // crypto.fips is deprecated. DEP0093. Use crypto.getFips()/crypto.setFips() fips: { __proto__: null, diff --git a/lib/internal/crypto/cipher.js b/lib/internal/crypto/cipher.js index a2b560d1382418..6f47b47f90ea4d 100644 --- a/lib/internal/crypto/cipher.js +++ b/lib/internal/crypto/cipher.js @@ -125,13 +125,6 @@ function createCipherBase(cipher, credential, options, decipher, iv) { ReflectApply(LazyTransform, this, [options]); } -function createCipher(cipher, password, options, decipher) { - validateString(cipher, 'cipher'); - password = getArrayBufferOrView(password, 'password'); - - ReflectApply(createCipherBase, this, [cipher, password, options, decipher]); -} - function createCipherWithIV(cipher, key, options, decipher, iv) { validateString(cipher, 'cipher'); const encoding = getStringOption(options, 'encoding'); @@ -148,8 +141,6 @@ function createCipherWithIV(cipher, key, options, decipher, iv) { function Cipher(cipher, password, options) { if (!(this instanceof Cipher)) return new Cipher(cipher, password, options); - - ReflectApply(createCipher, this, [cipher, password, options, true]); } ObjectSetPrototypeOf(Cipher.prototype, LazyTransform.prototype); @@ -269,8 +260,6 @@ addCipherPrototypeFunctions(Cipheriv); function Decipher(cipher, password, options) { if (!(this instanceof Decipher)) return new Decipher(cipher, password, options); - - ReflectApply(createCipher, this, [cipher, password, options, false]); } ObjectSetPrototypeOf(Decipher.prototype, LazyTransform.prototype); @@ -321,9 +310,7 @@ function getCipherInfo(nameOrNid, options) { } module.exports = { - Cipher, Cipheriv, - Decipher, Decipheriv, privateDecrypt, privateEncrypt, diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index 2e6e02d229b67b..2cc0714d950de1 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -404,15 +404,6 @@ void CipherBase::Init(const char* cipher_type, unsigned int auth_tag_len) { HandleScope scope(env()->isolate()); MarkPopErrorOnReturn mark_pop_error_on_return; -#if OPENSSL_VERSION_MAJOR >= 3 - if (EVP_default_properties_is_fips_enabled(nullptr)) { -#else - if (FIPS_mode()) { -#endif - return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(), - "crypto.createCipher() is not supported in FIPS mode."); - } - const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type); if (cipher == nullptr) return THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env()); diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 6178445adbc634..590eb4278fc13e 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -47,39 +47,6 @@ const errMessages = { const ciphers = crypto.getCiphers(); -const expectedWarnings = common.hasFipsCrypto ? - [] : [ - ['Use Cipheriv for counter mode of aes-192-gcm'], - ['Use Cipheriv for counter mode of aes-192-ccm'], - ['Use Cipheriv for counter mode of aes-192-ccm'], - ['Use Cipheriv for counter mode of aes-128-ccm'], - ['Use Cipheriv for counter mode of aes-128-ccm'], - ['Use Cipheriv for counter mode of aes-128-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-256-ccm'], - ['Use Cipheriv for counter mode of aes-128-ccm'], - ]; - -const expectedDeprecationWarnings = [ - ['crypto.createCipher is deprecated.', 'DEP0106'], -]; - -common.expectWarning({ - Warning: expectedWarnings, - DeprecationWarning: expectedDeprecationWarnings -}); - for (const test of TEST_CASES) { if (!ciphers.includes(test.algo)) { common.printSkipMessage(`unsupported ${test.algo} test`); @@ -157,45 +124,6 @@ for (const test of TEST_CASES) { } } - if (test.password) { - if (common.hasFipsCrypto) { - assert.throws(() => { crypto.createCipher(test.algo, test.password); }, - errMessages.FIPS); - } else { - const encrypt = crypto.createCipher(test.algo, test.password, options); - if (test.aad) - encrypt.setAAD(Buffer.from(test.aad, 'hex'), aadOptions); - let hex = encrypt.update(test.plain, 'ascii', 'hex'); - hex += encrypt.final('hex'); - const auth_tag = encrypt.getAuthTag(); - // Only test basic encryption run if output is marked as tampered. - if (!test.tampered) { - assert.strictEqual(hex, test.ct); - assert.strictEqual(auth_tag.toString('hex'), test.tag); - } - } - } - - if (test.password) { - if (common.hasFipsCrypto) { - assert.throws(() => { crypto.createDecipher(test.algo, test.password); }, - errMessages.FIPS); - } else { - const decrypt = crypto.createDecipher(test.algo, test.password, options); - decrypt.setAuthTag(Buffer.from(test.tag, 'hex')); - if (test.aad) - decrypt.setAAD(Buffer.from(test.aad, 'hex'), aadOptions); - let msg = decrypt.update(test.ct, 'hex', 'ascii'); - if (!test.tampered) { - msg += decrypt.final('ascii'); - assert.strictEqual(msg, test.plain); - } else { - // Assert that final throws if input data could not be verified! - assert.throws(function() { decrypt.final('ascii'); }, errMessages.auth); - } - } - } - { // Trying to get tag before inputting all data: const encrypt = crypto.createCipheriv(test.algo, @@ -344,26 +272,6 @@ for (const test of TEST_CASES) { message: "The property 'options.authTagLength' is invalid. " + `Received ${inspect(authTagLength)}` }); - - if (!common.hasFipsCrypto) { - assert.throws(() => { - crypto.createCipher('aes-256-ccm', 'bad password', { authTagLength }); - }, { - name: 'TypeError', - code: 'ERR_INVALID_ARG_VALUE', - message: "The property 'options.authTagLength' is invalid. " + - `Received ${inspect(authTagLength)}` - }); - - assert.throws(() => { - crypto.createDecipher('aes-256-ccm', 'bad password', { authTagLength }); - }, { - name: 'TypeError', - code: 'ERR_INVALID_ARG_VALUE', - message: "The property 'options.authTagLength' is invalid. " + - `Received ${inspect(authTagLength)}` - }); - } } // The following values will not be caught by the JS layer and thus will not @@ -387,14 +295,6 @@ for (const test of TEST_CASES) { authTagLength }); }, errMessages.authTagLength); - - assert.throws(() => { - crypto.createCipher('aes-256-ccm', 'bad password', { authTagLength }); - }, errMessages.authTagLength); - - assert.throws(() => { - crypto.createDecipher('aes-256-ccm', 'bad password', { authTagLength }); - }, errMessages.authTagLength); } } } @@ -420,18 +320,6 @@ for (const test of TEST_CASES) { }, { message: `authTagLength required for aes-256-${mode}` }); - - assert.throws(() => { - crypto.createCipher(`aes-256-${mode}`, 'very bad password'); - }, { - message: `authTagLength required for aes-256-${mode}` - }); - - assert.throws(() => { - crypto.createDecipher(`aes-256-${mode}`, 'very bad password'); - }, { - message: `authTagLength required for aes-256-${mode}` - }); } } } @@ -670,7 +558,6 @@ for (const test of TEST_CASES) { const opts = { authTagLength: 10 }; for (const cipher of [ - crypto.createCipher(algo, 'foo', opts), crypto.createCipheriv(algo, key, iv, opts), ]) { assert.throws(() => { diff --git a/test/parallel/test-crypto-cipher-decipher.js b/test/parallel/test-crypto-cipher-decipher.js deleted file mode 100644 index 35514afbea9256..00000000000000 --- a/test/parallel/test-crypto-cipher-decipher.js +++ /dev/null @@ -1,283 +0,0 @@ -'use strict'; -const common = require('../common'); - -if (!common.hasCrypto) - common.skip('missing crypto'); - -if (common.hasFipsCrypto) - common.skip('not supported in FIPS mode'); - -const crypto = require('crypto'); -const assert = require('assert'); - -common.expectWarning({ - Warning: [ - ['Use Cipheriv for counter mode of aes-256-gcm'], - ], - DeprecationWarning: [ - ['crypto.createCipher is deprecated.', 'DEP0106'], - ] -}); - -function testCipher1(key) { - // Test encryption and decryption - const plaintext = 'Keep this a secret? No! Tell everyone about node.js!'; - const cipher = crypto.createCipher('aes192', key); - - // Encrypt plaintext which is in utf8 format - // to a ciphertext which will be in hex - let ciph = cipher.update(plaintext, 'utf8', 'hex'); - // Only use binary or hex, not base64. - ciph += cipher.final('hex'); - - const decipher = crypto.createDecipher('aes192', key); - let txt = decipher.update(ciph, 'hex', 'utf8'); - txt += decipher.final('utf8'); - - assert.strictEqual(txt, plaintext); - - // Streaming cipher interface - // NB: In real life, it's not guaranteed that you can get all of it - // in a single read() like this. But in this case, we know it's - // quite small, so there's no harm. - const cStream = crypto.createCipher('aes192', key); - cStream.end(plaintext); - ciph = cStream.read(); - - const dStream = crypto.createDecipher('aes192', key); - dStream.end(ciph); - txt = dStream.read().toString('utf8'); - - assert.strictEqual(txt, plaintext); -} - - -function testCipher2(key) { - // Encryption and decryption with Base64. - // Reported in https://github.com/joyent/node/issues/738 - const plaintext = - '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' + - 'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' + - 'jAfaFg**'; - const cipher = crypto.createCipher('aes256', key); - - // Encrypt plaintext which is in utf8 format to a ciphertext which will be in - // Base64. - let ciph = cipher.update(plaintext, 'utf8', 'base64'); - ciph += cipher.final('base64'); - - const decipher = crypto.createDecipher('aes256', key); - let txt = decipher.update(ciph, 'base64', 'utf8'); - txt += decipher.final('utf8'); - - assert.strictEqual(txt, plaintext); -} - -testCipher1('MySecretKey123'); -testCipher1(Buffer.from('MySecretKey123')); - -testCipher2('0123456789abcdef'); -testCipher2(Buffer.from('0123456789abcdef')); - -{ - const Cipher = crypto.Cipher; - const instance = crypto.Cipher('aes-256-cbc', 'secret'); - assert(instance instanceof Cipher, 'Cipher is expected to return a new ' + - 'instance when called without `new`'); - - assert.throws( - () => crypto.createCipher(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "cipher" argument must be of type string. ' + - 'Received null' - }); - - assert.throws( - () => crypto.createCipher('aes-256-cbc', null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError' - }); - - assert.throws( - () => crypto.createCipher('aes-256-cbc', 'secret').update(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); - - assert.throws( - () => crypto.createCipher('aes-256-cbc', 'secret').setAAD(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); -} - -{ - const Decipher = crypto.Decipher; - const instance = crypto.Decipher('aes-256-cbc', 'secret'); - assert(instance instanceof Decipher, 'Decipher is expected to return a new ' + - 'instance when called without `new`'); - - assert.throws( - () => crypto.createDecipher(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - message: 'The "cipher" argument must be of type string. ' + - 'Received null' - }); - - assert.throws( - () => crypto.createDecipher('aes-256-cbc', 'secret').setAuthTag(null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); - - assert.throws( - () => crypto.createDecipher('aes-256-cbc', null), - { - code: 'ERR_INVALID_ARG_TYPE', - name: 'TypeError', - }); -} - -// Base64 padding regression test, see -// https://github.com/nodejs/node-v0.x-archive/issues/4837. -{ - const c = crypto.createCipher('aes-256-cbc', 'secret'); - const s = c.update('test', 'utf8', 'base64') + c.final('base64'); - assert.strictEqual(s, '375oxUQCIocvxmC5At+rvA=='); -} - -// Calling Cipher.final() or Decipher.final() twice should error but -// not assert. See https://github.com/nodejs/node-v0.x-archive/issues/4886. -{ - const c = crypto.createCipher('aes-256-cbc', 'secret'); - try { c.final('xxx'); } catch { /* Ignore. */ } - try { c.final('xxx'); } catch { /* Ignore. */ } - try { c.final('xxx'); } catch { /* Ignore. */ } - const d = crypto.createDecipher('aes-256-cbc', 'secret'); - try { d.final('xxx'); } catch { /* Ignore. */ } - try { d.final('xxx'); } catch { /* Ignore. */ } - try { d.final('xxx'); } catch { /* Ignore. */ } -} - -// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/5482: -// string to Cipher#update() should not assert. -{ - const c = crypto.createCipher('aes192', '0123456789abcdef'); - c.update('update'); - c.final(); -} - -// https://github.com/nodejs/node-v0.x-archive/issues/5655 regression tests, -// 'utf-8' and 'utf8' are identical. -{ - let c = crypto.createCipher('aes192', '0123456789abcdef'); - c.update('update', ''); // Defaults to "utf8". - c.final('utf-8'); // Should not throw. - - c = crypto.createCipher('aes192', '0123456789abcdef'); - c.update('update', 'utf8'); - c.final('utf-8'); // Should not throw. - - c = crypto.createCipher('aes192', '0123456789abcdef'); - c.update('update', 'utf-8'); - c.final('utf8'); // Should not throw. -} - -// Regression tests for https://github.com/nodejs/node/issues/8236. -{ - const key = '0123456789abcdef'; - const plaintext = 'Top secret!!!'; - const c = crypto.createCipher('aes192', key); - let ciph = c.update(plaintext, 'utf16le', 'base64'); - ciph += c.final('base64'); - - let decipher = crypto.createDecipher('aes192', key); - - let txt; - txt = decipher.update(ciph, 'base64', 'ucs2'); - txt += decipher.final('ucs2'); - assert.strictEqual(txt, plaintext); - - decipher = crypto.createDecipher('aes192', key); - txt = decipher.update(ciph, 'base64', 'ucs-2'); - txt += decipher.final('ucs-2'); - assert.strictEqual(txt, plaintext); - - decipher = crypto.createDecipher('aes192', key); - txt = decipher.update(ciph, 'base64', 'utf-16le'); - txt += decipher.final('utf-16le'); - assert.strictEqual(txt, plaintext); -} - -// setAutoPadding/setAuthTag/setAAD should return `this` -{ - const key = '0123456789'; - const tagbuf = Buffer.from('auth_tag'); - const aadbuf = Buffer.from('aadbuf'); - const decipher = crypto.createDecipher('aes-256-gcm', key); - assert.strictEqual(decipher.setAutoPadding(), decipher); - assert.strictEqual(decipher.setAuthTag(tagbuf), decipher); - assert.strictEqual(decipher.setAAD(aadbuf), decipher); -} - -// Error throwing in setAAD/setAuthTag/getAuthTag/setAutoPadding -{ - const key = '0123456789'; - const aadbuf = Buffer.from('aadbuf'); - const data = Buffer.from('test-crypto-cipher-decipher'); - - const cipher = crypto.createCipher('aes-256-gcm', key); - cipher.setAAD(aadbuf); - cipher.setAutoPadding(); - - assert.throws( - () => cipher.getAuthTag(), - { - code: 'ERR_CRYPTO_INVALID_STATE', - name: 'Error', - message: 'Invalid state for operation getAuthTag' - } - ); - - const encrypted = Buffer.concat([cipher.update(data), cipher.final()]); - - const decipher = crypto.createDecipher('aes-256-gcm', key); - decipher.setAAD(aadbuf); - decipher.setAuthTag(cipher.getAuthTag()); - decipher.setAutoPadding(); - decipher.update(encrypted); - decipher.final(); - - assert.throws( - () => decipher.setAAD(aadbuf), - { - code: 'ERR_CRYPTO_INVALID_STATE', - name: 'Error', - message: 'Invalid state for operation setAAD' - }); - - assert.throws( - () => decipher.setAuthTag(cipher.getAuthTag()), - { - code: 'ERR_CRYPTO_INVALID_STATE', - name: 'Error', - message: 'Invalid state for operation setAuthTag' - }); - - assert.throws( - () => decipher.setAutoPadding(), - { - code: 'ERR_CRYPTO_INVALID_STATE', - name: 'Error', - message: 'Invalid state for operation setAutoPadding' - } - ); -} diff --git a/test/parallel/test-crypto-classes.js b/test/parallel/test-crypto-classes.js index dd073274aef765..f736921476a1c5 100644 --- a/test/parallel/test-crypto-classes.js +++ b/test/parallel/test-crypto-classes.js @@ -22,8 +22,6 @@ const TEST_CASES = { }; if (!common.hasFipsCrypto) { - TEST_CASES.Cipher = ['aes192', 'secret']; - TEST_CASES.Decipher = ['aes192', 'secret']; TEST_CASES.DiffieHellman = [common.hasOpenSSL3 ? 1024 : 256]; } diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 8350401ba93707..4271121881379b 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -25,12 +25,6 @@ const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); -common.expectWarning({ - DeprecationWarning: [ - ['crypto.createCipher is deprecated.', 'DEP0106'], - ] -}); - const assert = require('assert'); const crypto = require('crypto'); const tls = require('tls'); @@ -184,24 +178,6 @@ const encodingError = { " Received 'hex'", }; -// Regression tests for https://github.com/nodejs/node-v0.x-archive/pull/5725: -// hex input that's not a power of two should throw, not assert in C++ land. -['createCipher', 'createDecipher'].forEach((funcName) => { - assert.throws( - () => crypto[funcName]('aes192', 'test').update('0', 'hex'), - (error) => { - assert.ok(!('opensslErrorStack' in error)); - if (common.hasFipsCrypto) { - return error instanceof Error && - error.name === 'Error' && - /^Error: not supported in FIPS mode$/.test(error); - } - assert.throws(() => { throw error; }, encodingError); - return true; - } - ); -}); - assert.throws( () => crypto.createHash('sha1').update('0', 'hex'), (error) => { diff --git a/test/parallel/test-process-emit-warning-from-native.js b/test/parallel/test-process-emit-warning-from-native.js deleted file mode 100644 index 80b1e71a08c58e..00000000000000 --- a/test/parallel/test-process-emit-warning-from-native.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; -const common = require('../common'); -const assert = require('assert'); - -if (!common.hasCrypto) - common.skip('missing crypto'); -if (common.hasFipsCrypto) - common.skip('crypto.createCipher() is not supported in FIPS mode'); - -const crypto = require('crypto'); -const key = '0123456789'; - -{ - common.expectWarning({ - DeprecationWarning: [ - ['crypto.createCipher is deprecated.', 'DEP0106'], - ], - Warning: [ - ['Use Cipheriv for counter mode of aes-256-gcm'], - ] - }); - - // Emits regular warning expected by expectWarning() - crypto.createCipher('aes-256-gcm', key); -} - -const realEmitWarning = process.emitWarning; - -{ - // It's a good idea to make this overridable from userland. - process.emitWarning = () => { throw new Error('foo'); }; - assert.throws(() => { - crypto.createCipher('aes-256-gcm', key); - }, /^Error: foo$/); -} - -{ - Object.defineProperty(process, 'emitWarning', { - get() { throw new Error('bar'); }, - configurable: true - }); - assert.throws(() => { - crypto.createCipher('aes-256-gcm', key); - }, /^Error: bar$/); -} - -// Reset back to default after the test. -Object.defineProperty(process, 'emitWarning', { - value: realEmitWarning, - configurable: true, - writable: true -});