Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: runtime deprecate calling Cipheriv(...) and Decipheriv(...) without new #57268

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,15 @@ console.log(cert.verifySpkac(Buffer.from(spkac)));
// Prints: true or false
```

## Class: `Cipher`
## Class: `Cipheriv`

<!-- YAML
added: v0.1.94
-->

* Extends: {stream.Transform}

Instances of the `Cipher` class are used to encrypt data. The class can be
Instances of the `Cipheriv` class are used to encrypt data. The class can be
used in one of two ways:

* As a [stream][] that is both readable and writable, where plain unencrypted
Expand All @@ -320,10 +320,10 @@ used in one of two ways:
the encrypted data.

The [`crypto.createCipheriv()`][] method is
used to create `Cipher` instances. `Cipher` objects are not to be created
used to create `Cipheriv` instances. `Cipheriv` objects are not to be created
directly using the `new` keyword.

Example: Using `Cipher` objects as streams:
Example: Using `Cipheriv` objects as streams:

```mjs
const {
Expand Down Expand Up @@ -391,7 +391,7 @@ scrypt(password, 'salt', 24, (err, key) => {
});
```

Example: Using `Cipher` and piped streams:
Example: Using `Cipheriv` and piped streams:

```mjs
import {
Expand Down Expand Up @@ -538,7 +538,7 @@ added: v0.1.94
If `outputEncoding` is specified, a string is
returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned.

Once the `cipher.final()` method has been called, the `Cipher` object can no
Once the `cipher.final()` method has been called, the `Cipheriv` object can no
longer be used to encrypt data. Attempts to call `cipher.final()` more than
once will result in an error being thrown.

Expand Down Expand Up @@ -570,7 +570,7 @@ added: v1.0.0
* `options` {Object} [`stream.transform` options][]
* `plaintextLength` {number}
* `encoding` {string} The string encoding to use when `buffer` is a string.
* Returns: {Cipher} The same `Cipher` instance for method chaining.
* Returns: {Cipher} The same `Cipheriv` instance for method chaining.

When using an authenticated encryption mode (`GCM`, `CCM`, `OCB`, and
`chacha20-poly1305` are
Expand All @@ -590,9 +590,9 @@ added: v0.7.1
-->

* `autoPadding` {boolean} **Default:** `true`
* Returns: {Cipher} The same `Cipher` instance for method chaining.
* Returns: {Cipher} The same `Cipheriv` instance for method chaining.

When using block encryption algorithms, the `Cipher` class will automatically
When using block encryption algorithms, the `Cipheriv` class will automatically
add padding to the input data to the appropriate block size. To disable the
default padding call `cipher.setAutoPadding(false)`.

Expand Down Expand Up @@ -635,15 +635,15 @@ The `cipher.update()` method can be called multiple times with new data until
[`cipher.final()`][] is called. Calling `cipher.update()` after
[`cipher.final()`][] will result in an error being thrown.

## Class: `Decipher`
## Class: `Decipheriv`

<!-- YAML
added: v0.1.94
-->

* Extends: {stream.Transform}

Instances of the `Decipher` class are used to decrypt data. The class can be
Instances of the `Decipheriv` class are used to decrypt data. The class can be
used in one of two ways:

* As a [stream][] that is both readable and writable, where plain encrypted
Expand All @@ -652,10 +652,10 @@ used in one of two ways:
produce the unencrypted data.

The [`crypto.createDecipheriv()`][] method is
used to create `Decipher` instances. `Decipher` objects are not to be created
used to create `Decipheriv` instances. `Decipheriv` objects are not to be created
directly using the `new` keyword.

Example: Using `Decipher` objects as streams:
Example: Using `Decipheriv` objects as streams:

```mjs
import { Buffer } from 'node:buffer';
Expand Down Expand Up @@ -731,7 +731,7 @@ decipher.write(encrypted, 'hex');
decipher.end();
```

Example: Using `Decipher` and piped streams:
Example: Using `Decipheriv` and piped streams:

```mjs
import {
Expand Down Expand Up @@ -848,7 +848,7 @@ added: v0.1.94
If `outputEncoding` is specified, a string is
returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned.

Once the `decipher.final()` method has been called, the `Decipher` object can
Once the `decipher.final()` method has been called, the `Decipheriv` object can
no longer be used to decrypt data. Attempts to call `decipher.final()` more
than once will result in an error being thrown.

Expand Down Expand Up @@ -3038,7 +3038,7 @@ changes:
* `options` {Object} [`stream.transform` options][]
* Returns: {Cipher}

Creates and returns a `Cipher` object, with the given `algorithm`, `key` and
Creates and returns a `Cipheriv` object, with the given `algorithm`, `key` and
initialization vector (`iv`).

The `options` argument controls stream behavior and is optional except when a
Expand Down Expand Up @@ -3108,7 +3108,7 @@ changes:
* `options` {Object} [`stream.transform` options][]
* Returns: {Decipher}

Creates and returns a `Decipher` object that uses the given `algorithm`, `key`
Creates and returns a `Decipheriv` object that uses the given `algorithm`, `key`
and initialization vector (`iv`).

The `options` argument controls stream behavior and is optional except when a
Expand Down
20 changes: 17 additions & 3 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2276,7 +2276,7 @@
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.
[`Cipheriv`][] and [`Decipheriv`][] objects respectively.

### DEP0107: `tls.convertNPNProtocols()`

Expand Down Expand Up @@ -3840,6 +3840,20 @@
`process.features.tls_alpn`, `process.features.tls_ocsp`, and `process.features.tls_sni` are
deprecated, as their values are guaranteed to be identical to that of `process.features.tls`.

### DEP0190: Instantiating `node:crypto` `Cipheriv` and `Decipheriv` classes without `new`

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/00000

Check warning on line 3848 in doc/api/deprecations.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: Runtime deprecation.
-->

Type: Runtime

Instantiating the [`Cipheriv`][] and [`Decipheriv`][] classes exported by the `node:crypto`
module is deprecated.

[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
[RFC 8247 Section 2.4]: https://www.rfc-editor.org/rfc/rfc8247#section-2.4
Expand All @@ -3854,8 +3868,8 @@
[`Buffer.from(array)`]: buffer.md#static-method-bufferfromarray
[`Buffer.from(buffer)`]: buffer.md#static-method-bufferfrombuffer
[`Buffer.isBuffer()`]: buffer.md#static-method-bufferisbufferobj
[`Cipher`]: crypto.md#class-cipher
[`Decipher`]: crypto.md#class-decipher
[`Cipheriv`]: crypto.md#class-cipheriv
[`Decipheriv`]: crypto.md#class-decipheriv
[`REPLServer.clearBufferedCommand()`]: repl.md#replserverclearbufferedcommand
[`ReadStream.open()`]: fs.md#class-fsreadstream
[`Server.getConnections()`]: net.md#servergetconnectionscallback
Expand Down
4 changes: 0 additions & 4 deletions lib/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ const {
diffieHellman,
} = require('internal/crypto/diffiehellman');
const {
Cipher,
Cipheriv,
Decipher,
Decipheriv,
privateDecrypt,
privateEncrypt,
Expand Down Expand Up @@ -224,9 +222,7 @@ module.exports = {

// Classes
Certificate,
Cipher,
Cipheriv,
Decipher,
Decipheriv,
DiffieHellman,
DiffieHellmanGroup,
Expand Down
69 changes: 24 additions & 45 deletions lib/internal/crypto/cipher.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ const assert = require('internal/assert');

const LazyTransform = require('internal/streams/lazy_transform');

const { normalizeEncoding } = require('internal/util');
const {
normalizeEncoding,
deprecateInstantiation,
} = require('internal/util');

const { StringDecoder } = require('string_decoder');

Expand Down Expand Up @@ -138,20 +141,12 @@ function createCipherWithIV(cipher, key, options, decipher, iv) {
// the Cipher class is defined using the legacy function syntax rather than
// ES6 classes.

function Cipher(cipher, password, options) {
if (!(this instanceof Cipher))
return new Cipher(cipher, password, options);
}

ObjectSetPrototypeOf(Cipher.prototype, LazyTransform.prototype);
ObjectSetPrototypeOf(Cipher, LazyTransform);

Cipher.prototype._transform = function _transform(chunk, encoding, callback) {
function _transform(chunk, encoding, callback) {
this.push(this[kHandle].update(chunk, encoding));
callback();
};

Cipher.prototype._flush = function _flush(callback) {
function _flush(callback) {
try {
this.push(this[kHandle].final());
} catch (e) {
Expand All @@ -161,7 +156,7 @@ Cipher.prototype._flush = function _flush(callback) {
callback();
};

Cipher.prototype.update = function update(data, inputEncoding, outputEncoding) {
function update(data, inputEncoding, outputEncoding) {
if (typeof data === 'string') {
validateEncoding(data, inputEncoding);
} else if (!isArrayBufferView(data)) {
Expand All @@ -179,8 +174,7 @@ Cipher.prototype.update = function update(data, inputEncoding, outputEncoding) {
return ret;
};


Cipher.prototype.final = function final(outputEncoding) {
function final(outputEncoding) {
const ret = this[kHandle].final();

if (outputEncoding && outputEncoding !== 'buffer') {
Expand All @@ -191,29 +185,27 @@ Cipher.prototype.final = function final(outputEncoding) {
return ret;
};


Cipher.prototype.setAutoPadding = function setAutoPadding(ap) {
function setAutoPadding(ap) {
if (!this[kHandle].setAutoPadding(!!ap))
throw new ERR_CRYPTO_INVALID_STATE('setAutoPadding');
return this;
};

Cipher.prototype.getAuthTag = function getAuthTag() {
function getAuthTag() {
const ret = this[kHandle].getAuthTag();
if (ret === undefined)
throw new ERR_CRYPTO_INVALID_STATE('getAuthTag');
return ret;
};


function setAuthTag(tagbuf, encoding) {
tagbuf = getArrayBufferOrView(tagbuf, 'buffer', encoding);
if (!this[kHandle].setAuthTag(tagbuf))
throw new ERR_CRYPTO_INVALID_STATE('setAuthTag');
return this;
}

Cipher.prototype.setAAD = function setAAD(aadbuf, options) {
function setAAD(aadbuf, options) {
const encoding = getStringOption(options, 'encoding');
const plaintextLength = getUIntOption(options, 'plaintextLength');
aadbuf = getArrayBufferOrView(aadbuf, 'aadbuf', encoding);
Expand All @@ -228,52 +220,39 @@ Cipher.prototype.setAAD = function setAAD(aadbuf, options) {
// ES6 classes.

function Cipheriv(cipher, key, iv, options) {
if (!(this instanceof Cipheriv))
return new Cipheriv(cipher, key, iv, options);
if (!(this instanceof Cipheriv)) {
return deprecateInstantiation(Cipheriv, 'DEP0190', cipher, key, iv, options);
}

ReflectApply(createCipherWithIV, this, [cipher, key, options, true, iv]);
}

function addCipherPrototypeFunctions(constructor) {
constructor.prototype._transform = Cipher.prototype._transform;
constructor.prototype._flush = Cipher.prototype._flush;
constructor.prototype.update = Cipher.prototype.update;
constructor.prototype.final = Cipher.prototype.final;
constructor.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
constructor.prototype._transform = _transform;
constructor.prototype._flush = _flush;
constructor.prototype.update = update;
constructor.prototype.final = final;
constructor.prototype.setAutoPadding = setAutoPadding;
if (constructor === Cipheriv) {
constructor.prototype.getAuthTag = Cipher.prototype.getAuthTag;
constructor.prototype.getAuthTag = getAuthTag;
} else {
constructor.prototype.setAuthTag = setAuthTag;
}
constructor.prototype.setAAD = Cipher.prototype.setAAD;
constructor.prototype.setAAD = setAAD;
}

ObjectSetPrototypeOf(Cipheriv.prototype, LazyTransform.prototype);
ObjectSetPrototypeOf(Cipheriv, LazyTransform);
addCipherPrototypeFunctions(Cipheriv);

// The Decipher class is part of the legacy Node.js crypto API. It exposes
// a stream-based encryption/decryption model. For backwards compatibility
// the Decipher class is defined using the legacy function syntax rather than
// ES6 classes.

function Decipher(cipher, password, options) {
if (!(this instanceof Decipher))
return new Decipher(cipher, password, options);
}

ObjectSetPrototypeOf(Decipher.prototype, LazyTransform.prototype);
ObjectSetPrototypeOf(Decipher, LazyTransform);
addCipherPrototypeFunctions(Decipher);

// The Decipheriv class is part of the legacy Node.js crypto API. It exposes
// a stream-based encryption/decryption model. For backwards compatibility
// the Decipheriv class is defined using the legacy function syntax rather than
// ES6 classes.

function Decipheriv(cipher, key, iv, options) {
if (!(this instanceof Decipheriv))
return new Decipheriv(cipher, key, iv, options);
if (!(this instanceof Decipheriv)) {
return deprecateInstantiation(Decipheriv, 'DEP0190', cipher, key, iv, options);
}

ReflectApply(createCipherWithIV, this, [cipher, key, options, false, iv]);
}
Expand Down
4 changes: 2 additions & 2 deletions tools/doc/type-parser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ const customTypesMap = {

'cluster.Worker': 'cluster.html#class-worker',

'Cipher': 'crypto.html#class-cipher',
'Decipher': 'crypto.html#class-decipher',
'Cipheriv': 'crypto.html#class-cipheriv',
'Decipheriv': 'crypto.html#class-decipheriv',
'DiffieHellman': 'crypto.html#class-diffiehellman',
'DiffieHellmanGroup': 'crypto.html#class-diffiehellmangroup',
'ECDH': 'crypto.html#class-ecdh',
Expand Down
Loading