crypto: move createCipher and createDecipher to eol

PR-URL: https://github.com/nodejs/node/pull/50973
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Marco Ippolito authored and GitHub committed 2023-12-15 14:00:52 +00:00
1 parent 7a2a4d07fe
commit 215f4d04b7
11 files changed
+10 -750

No files matched your search

-101
View File
@@ -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);
}
+2 -127
View File
@@ -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])`
<!-- YAML
added: v0.1.94
deprecated: v10.0.0
changes:
- version:
- v17.9.0
- v16.17.0
pr-url: https://github.com/nodejs/node/pull/42427
description: The `authTagLength` option is now optional when using the
`chacha20-poly1305` cipher and defaults to 16 bytes.
- version: v15.0.0
pr-url: https://github.com/nodejs/node/pull/35093
description: The password argument can be an ArrayBuffer and is limited to
a maximum of 2 ** 31 - 1 bytes.
- version: v10.10.0
pr-url: https://github.com/nodejs/node/pull/21447
description: Ciphers in OCB mode are now supported.
- version: v10.2.0
pr-url: https://github.com/nodejs/node/pull/20235
description: The `authTagLength` option can now be used to produce shorter
authentication tags in GCM mode and defaults to 16 bytes.
-->
> 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`.
<strong class="critical">This function is semantically insecure for all
supported ciphers and fatally flawed for ciphers in counter mode (such as CTR,
GCM, or CCM).</strong>
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])`
<!-- YAML
@@ -3099,55 +3028,6 @@ something has to be unpredictable and unique, but does not have to be secret;
remember that an attacker must not be able to predict ahead of time what a
given IV will be.
### `crypto.createDecipher(algorithm, password[, options])`
<!-- YAML
added: v0.1.94
deprecated: v10.0.0
changes:
- version:
- v17.9.0
- v16.17.0
pr-url: https://github.com/nodejs/node/pull/42427
description: The `authTagLength` option is now optional when using the
`chacha20-poly1305` cipher and defaults to 16 bytes.
- version: v10.10.0
pr-url: https://github.com/nodejs/node/pull/21447
description: Ciphers in OCB mode are now supported.
-->
> 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.
<strong class="critical">This function is semantically insecure for all
supported ciphers and fatally flawed for ciphers in counter mode (such as CTR,
GCM, or CCM).</strong>
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])`
<!-- YAML
@@ -6096,7 +5976,6 @@ See the [list of SSL OP Flags][] for details.
[NIST SP 800-131A]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf
[NIST SP 800-132]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[Nonce-Disrespecting Adversaries]: https://github.com/nonce-disrespect/nonce-disrespect
[OpenSSL's FIPS README file]: https://github.com/openssl/openssl/blob/openssl-3.0/README-FIPS.md
[OpenSSL's SPKAC implementation]: https://www.openssl.org/docs/man3.0/man1/openssl-spkac.html
[RFC 1421]: https://www.rfc-editor.org/rfc/rfc1421.txt
@@ -6113,7 +5992,6 @@ See the [list of SSL OP Flags][] for details.
[`Buffer`]: buffer.md
[`DH_generate_key()`]: https://www.openssl.org/docs/man3.0/man3/DH_generate_key.html
[`DiffieHellmanGroup`]: #class-diffiehellmangroup
[`EVP_BytesToKey`]: https://www.openssl.org/docs/man3.0/man3/EVP_BytesToKey.html
[`KeyObject`]: #class-keyobject
[`Sign`]: #class-sign
[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
@@ -6121,9 +5999,7 @@ See the [list of SSL OP Flags][] for details.
[`Verify`]: #class-verify
[`cipher.final()`]: #cipherfinaloutputencoding
[`cipher.update()`]: #cipherupdatedata-inputencoding-outputencoding
[`crypto.createCipher()`]: #cryptocreatecipheralgorithm-password-options
[`crypto.createCipheriv()`]: #cryptocreatecipherivalgorithm-key-iv-options
[`crypto.createDecipher()`]: #cryptocreatedecipheralgorithm-password-options
[`crypto.createDecipheriv()`]: #cryptocreatedecipherivalgorithm-key-iv-options
[`crypto.createDiffieHellman()`]: #cryptocreatediffiehellmanprime-primeencoding-generator-generatorencoding
[`crypto.createECDH()`]: #cryptocreateecdhcurvename
@@ -6144,7 +6020,6 @@ See the [list of SSL OP Flags][] for details.
[`crypto.publicEncrypt()`]: #cryptopublicencryptkey-buffer
[`crypto.randomBytes()`]: #cryptorandombytessize-callback
[`crypto.randomFill()`]: #cryptorandomfillbuffer-offset-size-callback
[`crypto.scrypt()`]: #cryptoscryptpassword-salt-keylen-options-callback
[`crypto.webcrypto.getRandomValues()`]: webcrypto.md#cryptogetrandomvaluestypedarray
[`crypto.webcrypto.subtle`]: webcrypto.md#class-subtlecrypto
[`decipher.final()`]: #decipherfinaloutputencoding
+8 -6
View File
@@ -2197,6 +2197,9 @@ Type: End-of-Life
<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/50973
description: End-of-Life.
- version: v11.0.0
pr-url: https://github.com/nodejs/node/pull/22089
description: Runtime deprecation.
@@ -2205,11 +2208,12 @@ changes:
description: Documentation-only deprecation.
-->
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.
@@ -3594,9 +3598,7 @@ Please use the [`crypto.createHash()`][] method to create Hash instances.
[`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.createHash()`]: crypto.md#cryptocreatehashalgorithm-options
[`crypto.fips`]: crypto.md#cryptofips
-20
View File
@@ -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,
-13
View File
@@ -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,
-9
View File
@@ -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());
-113
View File
@@ -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(() => {
@@ -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'
}
);
}
-2
View File
@@ -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];
}
-24
View File
@@ -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) => {
@@ -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
});