mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
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:
1 parent
7a2a4d07fe
commit
215f4d04b7
11 files changed
+10
-750
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
Reference in new issue
Block a user