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

crypto: add key object API #24234

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 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
210 changes: 185 additions & 25 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,78 @@ encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or

This can be called many times with new data as it is streamed.

## Class: KeyObject
tniessen marked this conversation as resolved.
Show resolved Hide resolved
<!-- YAML
added: REPLACEME
-->

Node.js uses an internal `KeyObject` class which should not be accessed
directly. Instead, factory functions exist to create instances of this class
in a secure manner, see [`crypto.createSecretKey()`][],
[`crypto.createPublicKey()`][] and [`crypto.createPrivateKey()`][]. A
`KeyObject` can represent a symmetric or asymmetric key, and each kind of key
exposes different functions.

Most applications should consider using the new `KeyObject` API instead of
passing keys as strings or `Buffer`s due to improved security features.

### keyObject.asymmetricKeyType
<!-- YAML
added: REPLACEME
-->
* {string}

For asymmetric keys, this property represents the type of the embedded key
(`'rsa'`, `'dsa'` or `'ec'`). This property is `undefined` for symmetric keys.

### keyObject.export([options])
<!-- YAML
added: REPLACEME
-->
* `options`: {Object}
* Returns: {string | Buffer}

For symmetric keys, this function allocates a `Buffer` containing the key
material and ignores any options.

For asymmetric keys, the `options` parameter is used to determine the export
format.

For public keys, the following encoding options can be used:

* `type`: {string} Must be one of `'pkcs1'` (RSA only) or `'spki'`.
* `format`: {string} Must be `'pem'` or `'der'`.

For private keys, the following encoding options can be used:

* `type`: {string} Must be one of `'pkcs1'` (RSA only), `'pkcs8'` or
`'sec1'` (EC only).
* `format`: {string} Must be `'pem'` or `'der'`.
sam-github marked this conversation as resolved.
Show resolved Hide resolved
* `cipher`: {string} If specified, the private key will be encrypted with
the given `cipher` and `passphrase` using PKCS#5 v2.0 password based
encryption.
* `passphrase`: {string | Buffer} The passphrase to use for encryption, see
tniessen marked this conversation as resolved.
Show resolved Hide resolved
`cipher`.

### keyObject.symmetricSize
<!-- YAML
added: REPLACEME
-->
* {number}

For secret keys, this property represents the size of the key in bytes. This
property is `undefined` for asymmetric keys.

### keyObject.type
<!-- YAML
added: REPLACEME
-->
* {string}

Depending on the type of this `KeyObject`, this property is either
`'secret'` for secret (symmetric) keys, `'public'` for public (asymmetric) keys
or `'private'` for private (asymmetric) keys.

## Class: Sign
<!-- YAML
added: v0.1.92
Expand Down Expand Up @@ -1169,13 +1241,16 @@ console.log(sign.sign(privateKey, 'hex'));
<!-- YAML
added: v0.1.92
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
- version: v8.0.0
pr-url: https://github.com/nodejs/node/pull/11705
description: Support for RSASSA-PSS and additional options was added.
-->
* `privateKey` {string | Object}
- `key` {string}
- `passphrase` {string}
* `privateKey` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A private key.
- `passphrase` {string | Buffer} An optional passphrase for the private key.
tniessen marked this conversation as resolved.
Show resolved Hide resolved
- `padding` {integer}
- `saltLength` {integer}
* `outputEncoding` {string} The [encoding][] of the return value.
Expand Down Expand Up @@ -1299,7 +1374,10 @@ changes:
pr-url: https://github.com/nodejs/node/pull/11705
description: Support for RSASSA-PSS and additional options was added.
-->
* `object` {string | Object}
* `object` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A public key.
tniessen marked this conversation as resolved.
Show resolved Hide resolved
- `padding` {integer}
- `saltLength` {integer}
* `signature` {string | Buffer | TypedArray | DataView}
* `signatureEncoding` {string} The [encoding][] of the `signature` string.
* Returns: {boolean} `true` or `false` depending on the validity of the
Expand All @@ -1310,7 +1388,7 @@ The `object` argument can be either a string containing a PEM encoded object,
which can be an RSA public key, a DSA public key, or an X.509 certificate,
or an object with one or more of the following properties:

* `key`: {string} - PEM encoded public key (required)
* `key`: {string | KeyObject} - The public key (required)
* `padding`: {integer} - Optional padding value for RSA, one of the following:
* `crypto.constants.RSA_PKCS1_PADDING` (default)
* `crypto.constants.RSA_PKCS1_PSS_PADDING`
Expand Down Expand Up @@ -1436,6 +1514,9 @@ Adversaries][] for details.
<!-- YAML
added: v0.1.94
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: The `key` argument can now be a `KeyObject`.
- version: v11.2.0
pr-url: https://github.com/nodejs/node/pull/24081
description: The cipher `chacha20-poly1305` is now supported.
Expand All @@ -1452,7 +1533,7 @@ changes:
need an initialization vector.
-->
* `algorithm` {string}
* `key` {string | Buffer | TypedArray | DataView}
* `key` {string | Buffer | TypedArray | DataView | KeyObject}
tniessen marked this conversation as resolved.
Show resolved Hide resolved
* `iv` {string | Buffer | TypedArray | DataView}
* `options` {Object} [`stream.transform` options][]
* Returns: {Cipher}
Expand Down Expand Up @@ -1525,6 +1606,9 @@ to create the `Decipher` object.
<!-- YAML
added: v0.1.94
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: The `key` argument can now be a `KeyObject`.
- version: v11.2.0
pr-url: https://github.com/nodejs/node/pull/24081
description: The cipher `chacha20-poly1305` is now supported.
Expand Down Expand Up @@ -1674,9 +1758,13 @@ input.on('readable', () => {
### crypto.createHmac(algorithm, key[, options])
<!-- YAML
added: v0.1.94
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: The `key` argument can now be a `KeyObject`.
-->
* `algorithm` {string}
* `key` {string | Buffer | TypedArray | DataView}
* `key` {string | Buffer | TypedArray | DataView | KeyObject}
tniessen marked this conversation as resolved.
Show resolved Hide resolved
* `options` {Object} [`stream.transform` options][]
* Returns: {Hmac}

Expand Down Expand Up @@ -1711,6 +1799,47 @@ input.on('readable', () => {
});
```

### crypto.createPrivateKey(key)
<!-- YAML
added: REPLACEME
-->
* `key` {Object | string | Buffer}
- `key`: {string | Buffer} The key material, either in PEM or DER format.
- `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`.
- `type`: {string} Must be `'pkcs1'`, `'pkcs8'` or `'sec1'`. This option is
required only if the `format` is `'der'` and ignored if it is `'pem'`.
- `passphrase`: {string | Buffer} The passphrase to use for decryption.
* Returns: {KeyObject}

Creates and returns a new key object containing a private key. If `key` is a
string or `Buffer`, it is parsed as a PEM-encoded private key; otherwise, `key`
tniessen marked this conversation as resolved.
Show resolved Hide resolved
must be an object with the properties described above.

### crypto.createPublicKey(key)
<!-- YAML
added: REPLACEME
-->
* `key` {Object | string | Buffer}
- `key`: {string | Buffer}
- `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`.
- `type`: {string} Must be `'pkcs1'` or `'spki'`. This option is required
only if the `format` is `'der'`.
* Returns: {KeyObject}

Creates and returns a new key object containing a public key. If `key` is a
string or `Buffer`, it is parsed as a PEM-encoded public key; otherwise, `key`
must be an object with the properties described above.

### crypto.createSecretKey(key)
<!-- YAML
added: REPLACEME
-->
* `key` {Buffer}
* Returns: {KeyObject}

Creates and returns a new key object containing a secret key for symmetric
encryption or `Hmac`.

### crypto.createSign(algorithm[, options])
<!-- YAML
added: v0.1.92
Expand Down Expand Up @@ -1740,6 +1869,11 @@ signing algorithms. Optional `options` argument controls the
### crypto.generateKeyPair(type, options, callback)
<!-- YAML
added: v10.12.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: The `generateKeyPair` and `generateKeyPairSync` functions now
produce key objects if no encoding was specified.
sam-github marked this conversation as resolved.
Show resolved Hide resolved
-->
* `type`: {string} Must be `'rsa'`, `'dsa'` or `'ec'`.
* `options`: {Object}
Expand All @@ -1757,11 +1891,12 @@ added: v10.12.0
- `cipher`: {string} If specified, the private key will be encrypted with
the given `cipher` and `passphrase` using PKCS#5 v2.0 password based
encryption.
- `passphrase`: {string} The passphrase to use for encryption, see `cipher`.
- `passphrase`: {string | Buffer} The passphrase to use for encryption, see
`cipher`.
* `callback`: {Function}
- `err`: {Error}
- `publicKey`: {string|Buffer}
- `privateKey`: {string|Buffer}
- `publicKey`: {string | Buffer | KeyObject}
- `privateKey`: {string | Buffer | KeyObject}

Generates a new asymmetric key pair of the given `type`. Only RSA, DSA and EC
are currently supported.
Expand Down Expand Up @@ -1801,6 +1936,11 @@ a `Promise` for an `Object` with `publicKey` and `privateKey` properties.
### crypto.generateKeyPairSync(type, options)
<!-- YAML
added: v10.12.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: The `generateKeyPair` and `generateKeyPairSync` functions now
produce key objects if no encoding was specified.
-->
* `type`: {string} Must be `'rsa'`, `'dsa'` or `'ec'`.
* `options`: {Object}
Expand All @@ -1818,10 +1958,11 @@ added: v10.12.0
- `cipher`: {string} If specified, the private key will be encrypted with
the given `cipher` and `passphrase` using PKCS#5 v2.0 password based
encryption.
- `passphrase`: {string} The passphrase to use for encryption, see `cipher`.
- `passphrase`: {string | Buffer} The passphrase to use for encryption, see
`cipher`.
* Returns: {Object}
- `publicKey`: {string|Buffer}
- `privateKey`: {string|Buffer}
- `publicKey`: {string | Buffer | KeyObject}
- `privateKey`: {string | Buffer | KeyObject}

Generates a new asymmetric key pair of the given `type`. Only RSA, DSA and EC
are currently supported.
Expand Down Expand Up @@ -2062,10 +2203,14 @@ An array of supported digest functions can be retrieved using
### crypto.privateDecrypt(privateKey, buffer)
<!-- YAML
added: v0.11.14
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
-->
* `privateKey` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
* `privateKey` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A PEM encoded private key.
- `passphrase` {string | Buffer} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING`,
`crypto.constants.RSA_PKCS1_PADDING`, or
Expand All @@ -2082,10 +2227,14 @@ treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`.
### crypto.privateEncrypt(privateKey, buffer)
<!-- YAML
added: v1.1.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
-->
* `privateKey` {Object | string}
- `key` {string} A PEM encoded private key.
- `passphrase` {string} An optional passphrase for the private key.
* `privateKey` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A PEM encoded private key.
- `passphrase` {string | Buffer} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING` or
`crypto.constants.RSA_PKCS1_PADDING`.
Expand All @@ -2101,10 +2250,14 @@ treated as the key with no passphrase and will use `RSA_PKCS1_PADDING`.
### crypto.publicDecrypt(key, buffer)
<!-- YAML
added: v1.1.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
-->
* `key` {Object | string}
- `key` {string} A PEM encoded public or private key.
- `passphrase` {string} An optional passphrase for the private key.
* `key` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A PEM encoded public or private key.
- `passphrase` {string | Buffer} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING` or
`crypto.constants.RSA_PKCS1_PADDING`.
Expand All @@ -2123,10 +2276,14 @@ be passed instead of a public key.
### crypto.publicEncrypt(key, buffer)
<!-- YAML
added: v0.11.14
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24234
description: This function now supports key objects.
-->
* `key` {Object | string}
- `key` {string} A PEM encoded public or private key.
- `passphrase` {string} An optional passphrase for the private key.
* `key` {Object | string | Buffer | KeyObject}
- `key` {string | Buffer | KeyObject} A PEM encoded public or private key.
- `passphrase` {string | Buffer} An optional passphrase for the private key.
- `padding` {crypto.constants} An optional padding value defined in
`crypto.constants`, which may be: `crypto.constants.RSA_NO_PADDING`,
`crypto.constants.RSA_PKCS1_PADDING`, or
Expand Down Expand Up @@ -2928,6 +3085,9 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
[`crypto.createECDH()`]: #crypto_crypto_createecdh_curvename
[`crypto.createHash()`]: #crypto_crypto_createhash_algorithm_options
[`crypto.createHmac()`]: #crypto_crypto_createhmac_algorithm_key_options
[`crypto.createPrivateKey()`]: #crypto_crypto_createprivatekey_key
[`crypto.createPublicKey()`]: #crypto_crypto_createpublickey_key
[`crypto.createSecretKey()`]: #crypto_crypto_createsecretkey_key
[`crypto.createSign()`]: #crypto_crypto_createsign_algorithm_options
[`crypto.createVerify()`]: #crypto_crypto_createverify_algorithm_options
[`crypto.getCurves()`]: #crypto_crypto_getcurves
Expand Down
5 changes: 5 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,11 @@ The selected public or private key encoding is incompatible with other options.

An invalid [crypto digest algorithm][] was specified.

<a id="ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE"></a>
### ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE

The given crypto key object has an invalid type.
tniessen marked this conversation as resolved.
Show resolved Hide resolved

<a id="ERR_CRYPTO_INVALID_STATE"></a>
### ERR_CRYPTO_INVALID_STATE

Expand Down
8 changes: 8 additions & 0 deletions lib/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ const {
generateKeyPair,
generateKeyPairSync
} = require('internal/crypto/keygen');
const {
createSecretKey,
createPublicKey,
createPrivateKey
} = require('internal/crypto/keys');
const {
DiffieHellman,
DiffieHellmanGroup,
Expand Down Expand Up @@ -149,6 +154,9 @@ module.exports = exports = {
createECDH,
createHash,
createHmac,
createPrivateKey,
createPublicKey,
createSecretKey,
createSign,
createVerify,
getCiphers,
Expand Down
Loading