From 8c502f54cec557959861d0ec837ad30b020c1dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sun, 2 Sep 2018 17:00:01 +0200 Subject: [PATCH] crypto: add API for key pair generation This adds support for RSA, DSA and EC key pair generation with a variety of possible output formats etc. PR-URL: https://github.com/nodejs/node/pull/22660 Fixes: https://github.com/nodejs/node/issues/15116 Reviewed-By: Matteo Collina Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Ujjwal Sharma Reviewed-By: Ben Noordhuis --- doc/api/crypto.md | 110 +++ doc/api/errors.md | 5 + lib/crypto.js | 6 + lib/internal/crypto/keygen.js | 238 +++++++ lib/internal/errors.js | 2 + node.gyp | 1 + src/async_wrap.h | 1 + src/node_crypto.cc | 459 +++++++++++++ test/parallel/test-crypto-keygen.js | 634 ++++++++++++++++++ test/sequential/test-async-wrap-getasyncid.js | 1 + 10 files changed, 1457 insertions(+) create mode 100644 lib/internal/crypto/keygen.js create mode 100644 test/parallel/test-crypto-keygen.js diff --git a/doc/api/crypto.md b/doc/api/crypto.md index b7bf532d2f7..0af7bea90ed 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1673,6 +1673,116 @@ Use [`crypto.getHashes()`][] to obtain an array of names of the available signing algorithms. Optional `options` argument controls the `stream.Writable` behavior. +### crypto.generateKeyPair(type, options, callback) + +* `type`: {string} Must be `'rsa'`, `'dsa'` or `'ec'`. +* `options`: {Object} + - `modulusLength`: {number} Key size in bits (RSA, DSA). + - `publicExponent`: {number} Public exponent (RSA). **Default:** `0x10001`. + - `divisorLength`: {number} Size of `q` in bits (DSA). + - `namedCurve`: {string} Name of the curve to use (EC). + - `publicKeyEncoding`: {Object} + - `type`: {string} Must be one of `'pkcs1'` (RSA only) or `'spki'`. + - `format`: {string} Must be `'pem'` or `'der'`. + - `privateKeyEncoding`: {Object} + - `type`: {string} Must be one of `'pkcs1'` (RSA only), `'pkcs8'` or + `'sec1'` (EC only). + - `format`: {string} Must be `'pem'` or `'der'`. + - `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`. +* `callback`: {Function} + - `err`: {Error} + - `publicKey`: {string|Buffer} + - `privateKey`: {string|Buffer} + +Generates a new asymmetric key pair of the given `type`. Only RSA, DSA and EC +are currently supported. + +It is recommended to encode public keys as `'spki'` and private keys as +`'pkcs8'` with encryption: + +```js +const { generateKeyPair } = require('crypto'); +generateKeyPair('rsa', { + modulusLength: 4096, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem', + cipher: 'aes-256-cbc', + passphrase: 'top secret' + } +}, (err, publicKey, privateKey) => { + // Handle errors and use the generated key pair. +}); +``` + +On completion, `callback` will be called with `err` set to `undefined` and +`publicKey` / `privateKey` representing the generated key pair. When PEM +encoding was selected, the result will be a string, otherwise it will be a +buffer containing the data encoded as DER. Note that Node.js itself does not +accept DER, it is supported for interoperability with other libraries such as +WebCrypto only. + +### crypto.generateKeyPairSync(type, options) + +* `type`: {string} Must be `'rsa'`, `'dsa'` or `'ec'`. +* `options`: {Object} + - `modulusLength`: {number} Key size in bits (RSA, DSA). + - `publicExponent`: {number} Public exponent (RSA). **Default:** `0x10001`. + - `divisorLength`: {number} Size of `q` in bits (DSA). + - `namedCurve`: {string} Name of the curve to use (EC). + - `publicKeyEncoding`: {Object} + - `type`: {string} Must be one of `'pkcs1'` (RSA only) or `'spki'`. + - `format`: {string} Must be `'pem'` or `'der'`. + - `privateKeyEncoding`: {Object} + - `type`: {string} Must be one of `'pkcs1'` (RSA only), `'pkcs8'` or + `'sec1'` (EC only). + - `format`: {string} Must be `'pem'` or `'der'`. + - `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`. +* Returns: {Object} + - `publicKey`: {string|Buffer} + - `privateKey`: {string|Buffer} + +Generates a new asymmetric key pair of the given `type`. Only RSA, DSA and EC +are currently supported. + +It is recommended to encode public keys as `'spki'` and private keys as +`'pkcs8'` with encryption: + +```js +const { generateKeyPairSync } = require('crypto'); +const { publicKey, privateKey } = generateKeyPairSync('rsa', { + modulusLength: 4096, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem', + cipher: 'aes-256-cbc', + passphrase: 'top secret' + } +}); +``` + +The return value `{ publicKey, privateKey }` represents the generated key pair. +When PEM encoding was selected, the respective key will be a string, otherwise +it will be a buffer containing the data encoded as DER. + ### crypto.getCiphers()