From 09bc0c6a05cc0324c947e5563636743f6943f79a Mon Sep 17 00:00:00 2001 From: James M Snell Date: Sat, 26 Dec 2015 20:54:01 -0800 Subject: [PATCH] doc: improvements to crypto.markdown copy General improvements to crypto.markdown including new and revised examples. PR-URL: https://github.com/nodejs/node/pull/4435 Reviewed-By: Fedor Indutny Reviewed-By: Shigeki Ohtsu --- doc/api/crypto.markdown | 1237 ++++++++++++++++++++++++++------------- 1 file changed, 838 insertions(+), 399 deletions(-) diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index a731d979ac88da..fcec1b1abf013c 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -2,207 +2,373 @@ Stability: 2 - Stable +The `crypto` module provides cryptographic functionality that includes a set of +wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign and verify functions. + Use `require('crypto')` to access this module. -The crypto module offers a way of encapsulating secure credentials to be -used as part of a secure HTTPS net or http connection. + const crypto = require('crypto'); -It also offers a set of wrappers for OpenSSL's hash, hmac, cipher, -decipher, sign and verify methods. + const secret = 'abcdefg'; + const hash = crypto.createHmac('sha256', secret) + .update('I love cupcakes') + .digest('hex'); + console.log(hash); + // Prints: + // c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e ## Class: Certificate -The class used for working with signed public key & challenges. The most -common usage for this series of functions is when dealing with the `` -element. https://www.openssl.org/docs/apps/spkac.html +SPKAC is a Certificate Signing Request mechanism originally implemented by +Netscape and now specified formally as part of [HTML5's `keygen` element][]. + +The `crypto` module provides the `Certificate` class for working with SPKAC +data. The most common usage is handling output generated by the HTML5 +`` element. Node.js uses [OpenSSL's SPKAC implementation][] internally. + +### new crypto.Certificate() + +Instances of the `Certificate` class can be created using the `new` keyword +or by calling `crypto.Certificate()` as a function: + + const crypto = require('crypto'); + + const cert1 = new crypto.Certificate(); + const cert2 = crypto.Certificate(); -Returned by `crypto.Certificate`. +### certificate.exportChallenge(spkac) -### Certificate.exportChallenge(spkac) +The `spkac` data structure includes a public key and a challenge. The +`certificate.exportChallenge()` returns the challenge component in the +form of a Node.js [`Buffer`][]. The `spkac` argument can be either a string +or a [`Buffer`][]. -Exports the encoded challenge associated with the SPKAC. + const cert = require('crypto').Certificate(); + const spkac = getSpkacSomehow(); + const challenge = cert.exportChallenge(spkac); + console.log(challenge.toString('utf8')); + // Prints the challenge as a UTF8 string ### Certificate.exportPublicKey(spkac) -Exports the encoded public key from the supplied SPKAC. +The `spkac` data structure includes a public key and a challenge. The +`certificate.exportPublicKey()` returns the public key component in the +form of a Node.js [`Buffer`][]. The `spkac` argument can be either a string +or a [`Buffer`][]. + + const cert = require('crypto').Certificate(); + const spkac = getSpkacSomehow(); + const publicKey = cert.exportPublicKey(spkac); + console.log(publicKey); + // Prints the public key as ### Certificate.verifySpkac(spkac) -Returns true of false based on the validity of the SPKAC. +Returns `true` if the given `spkac` data structure is valid, `false` otherwise. +The `spkac` argument must be a Node.js [`Buffer`][]. + + const cert = require('crypto').Certificate(); + const spkac = getSpkacSomehow(); + console.log(cert.verifySpkac(new Buffer(spkac))); + // Prints true or false ## Class: Cipher -Class for encrypting data. +Instances of the `Cipher` class are used to encrypt data. The class can be +used in one of two ways: -Returned by `crypto.createCipher` and `crypto.createCipheriv`. +- As a [stream][] that is both readable and writable, where plain unencrypted + data is written to produce encrypted data on the readable side, or +- Using the `cipher.update()` and `cipher.final()` methods to produce the + encrypted data. -Cipher objects are [streams][] that are both readable and writable. -The written plain text data is used to produce the encrypted data on -the readable side. The legacy `update` and `final` methods are also -supported. +The `crypto.createCipher()` or `crypto.createCipheriv()` methods are used to +create `Cipher` instances. `Cipher` objects are not to be created directly +using the `new` keyword. -### cipher.final([output_encoding]) +Example: Using `Cipher` objects as streams: -Returns any remaining enciphered contents, with `output_encoding` -being one of: `'binary'`, `'base64'` or `'hex'`. If no encoding is -provided, then a buffer is returned. + const crypto = require('crypto'); + const cipher = crypto.createCipher('aes192', 'a password'); -Note: `cipher` object can not be used after `final()` method has been -called. + cipher.on('readable', () => { + var data = cipher.read(); + if (data) + console.log(data.toString('hex')); + // Prints: b919f20fc5ac2f9c1d2cce94cb1d9c2d + }); -### cipher.getAuthTag() + cipher.write('clear text data'); + cipher.end(); + +Example: Using `Cipher` and piped streams: + + const crypto = require('crypto'); + const fs = require('fs'); + const cipher = crypto.createCipher('aes192', 'a password'); + + const input = fs.createReadStream('test.js'); + const output = fs.createWriteStream('test.enc'); + + input.pipe(cipher).pipe(output); + +Example: Using the `cipher.update()` and `cipher.final()` methods: + + const crypto = require('crypto'); + const cipher = crypto.createCipher('aes192', 'a password'); -For authenticated encryption modes (currently supported: GCM), this -method returns a `Buffer` that represents the _authentication tag_ that -has been computed from the given data. Should be called after -encryption has been completed using the `final` method! + cipher.update('clear text data'); + console.log(cipher.final('hex')); + // Prints: b919f20fc5ac2f9c1d2cce94cb1d9c2d + +### cipher.final([output_encoding]) + +Returns any remaining enciphered contents. If `output_encoding` +parameter is one of `'binary'`, `'base64'` or `'hex'`, a string is returned. +If an `output_encoding` is not provided, a [`Buffer`][] is returned. + +Once the `cipher.final()` method has been called, the `Cipher` object can no +longer be used to encrypt data. Attempts to call `cipher.final()` more than +once will result in an error being thrown. ### cipher.setAAD(buffer) -For authenticated encryption modes (currently supported: GCM), this -method sets the value used for the additional authenticated data (AAD) input -parameter. +When using an authenticated encryption mode (only `GCM` is currently +supported), the `cipher.getAAD()` method sets the value used for the +_additional authenticated data_ (AAD) input parameter. + +### cipher.getAuthTag() + +When using an authenticated encryption mode (only `GCM` is currently +supported), the `cipher.getAuthTag()` method returns a [`Buffer`][] containing +the _authentication tag_ that has been computed from the given data. + +The `cipher.getAuthTag()` method should only be called after encryption has +been completed using the `cipher.final()` method. ### cipher.setAutoPadding(auto_padding=true) -You can disable automatic padding of the input data to block size. If -`auto_padding` is false, the length of the entire input data must be a -multiple of the cipher's block size or `final` will fail. Useful for -non-standard padding, e.g. using `0x0` instead of PKCS padding. You -must call this before `cipher.final`. +When using block encryption algorithms, the `Cipher` class will automatically +add padding to the input data to the appropriate block size. To disable the +default padding call `cipher.setAutoPadding(false)`. + +When `auto_padding` is `false`, the length of the entire input data must be a +multiple of the cipher's block size or `cipher.final()` will throw an Error. +Disabling automatic padding is useful for non-standard padding, for instance +using `0x0` instead of PKCS padding. + +The `cipher.setAutoPadding()` method must be called before `cipher.final()`. ### cipher.update(data[, input_encoding][, output_encoding]) -Updates the cipher with `data`, the encoding of which is given in -`input_encoding` and can be `'utf8'`, `'ascii'` or `'binary'`. If no -encoding is provided, then a buffer is expected. -If `data` is a `Buffer` then `input_encoding` is ignored. +Updates the cipher with `data`. If the `input_encoding` argument is given, +it's value must be one of `'utf8'`, `'ascii'`, or `'binary'` and the `data` +argument is a string using the specified encoding. If the `input_encoding` +argument is not given, `data` must be a [`Buffer`][]. If `data` is a +[`Buffer`][] then `input_encoding` is ignored. The `output_encoding` specifies the output format of the enciphered -data, and can be `'binary'`, `'base64'` or `'hex'`. If no encoding is -provided, then a buffer is returned. +data, and can be `'binary'`, `'base64'` or `'hex'`. If the `output_encoding` +is specified, a string using the specified encoding is returned. If no +`output_encoding` is provided, a [`Buffer`][] is returned. -Returns the enciphered contents, and can be called many times with new -data as it is streamed. +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 for decrypting data. +Instances of the `Decipher` 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 + data is written to produce unencrypted data on the readable side, or +- Using the `decipher.update()` and `decipher.final()` methods to produce the + unencrypted data. + +The `crypto.createDecipher()` or `crypto.createDecipheriv()` methods are used +to create `Decipher` instances. `Decipher` objects are not to be created +directly using the `new` keyword. + +Example: Using `Decipher` objects as streams: + + const crypto = require('crypto'); + const decipher = crypto.createDecipher('aes192', 'a password'); + + decipher.on('readable', () => { + var data = decipher.read(); + if (data) + console.log(data.toString()); + // Prints: clear text data + }); + + decipher.write('b919f20fc5ac2f9c1d2cce94cb1d9c2d', 'hex'); + decipher.end(); + +Example: Using `Decipher` and piped streams: + + const crypto = require('crypto'); + const fs = require('fs'); + const decipher = crypto.createDecipher('aes192', 'a password'); + + const input = fs.createReadStream('test.enc'); + const output = fs.createWriteStream('test.js'); + + input.pipe(decipher).pipe(output); + +Example: Using the `decipher.update()` and `decipher.final()` methods: -Returned by [`crypto.createDecipher`][] and [`crypto.createDecipheriv`][]. + const crypto = require('crypto'); + const decipher = crypto.createDecipher('aes192', 'a password'); -Decipher objects are [streams][] that are both readable and writable. -The written enciphered data is used to produce the plain-text data on -the the readable side. The legacy `update` and `final` methods are also -supported. + decipher.update('b919f20fc5ac2f9c1d2cce94cb1d9c2d', 'hex'); + console.log(decipher.final('utf8')); + // Prints: clear text data ### decipher.final([output_encoding]) -Returns any remaining plaintext which is deciphered, with -`output_encoding` being one of: `'binary'`, `'ascii'` or `'utf8'`. If -no encoding is provided, then a buffer is returned. +Returns any remaining deciphered contents. If `output_encoding` +parameter is one of `'binary'`, `'base64'` or `'hex'`, a string is returned. +If an `output_encoding` is not provided, a [`Buffer`][] is returned. -Note: `decipher` object can not be used after `final()` method has been -called. +Once the `decipher.final()` method has been called, the `Decipher` object can +no longer be used to decrypt data. Attempts to call `decipher.final()` more +than once will result in an error being thrown. ### decipher.setAAD(buffer) -For authenticated encryption modes (currently supported: GCM), this -method sets the value used for the additional authenticated data (AAD) input -parameter. +When using an authenticated encryption mode (only `GCM` is currently +supported), the `cipher.getAAD()` method sets the value used for the +_additional authenticated data_ (AAD) input parameter. ### decipher.setAuthTag(buffer) -For authenticated encryption modes (currently supported: GCM), this -method must be used to pass in the received _authentication tag_. -If no tag is provided or if the ciphertext has been tampered with, -`final` will throw, thus indicating that the ciphertext should -be discarded due to failed authentication. +When using an authenticated encryption mode (only `GCM` is currently +supported), the `decipher.setAuthTag()` method is used to pass in the +received _authentication tag_. If no tag is provided, or if the ciphertext +has been tampered with, `decipher.final()` with throw, indicating that the +ciphertext should be discarded due to failed authentication. ### decipher.setAutoPadding(auto_padding=true) -You can disable auto padding if the data has been encrypted without -standard block padding to prevent `decipher.final` from checking and -removing it. This will only work if the input data's length is a multiple of -the ciphers block size. You must call this before streaming data to -[`decipher.update`][]. +When data has been encrypted without standard block padding, calling +`decipher.setAuthPadding(false)` will disable automatic padding to prevent +`decipher.final()` from checking for and removing padding. + +Turning auto padding off will only work if the input data's length is a +multiple of the ciphers block size. + +The `decipher.setAutoPadding()` method must be called before +`decipher.update()`. ### decipher.update(data[, input_encoding][, output_encoding]) -Updates the decipher with `data`, which is encoded in `'binary'`, -`'base64'` or `'hex'`. If no encoding is provided, then a buffer is -expected. -If `data` is a `Buffer` then `input_encoding` is ignored. +Updates the decipher with `data`. If the `input_encoding` argument is given, +it's value must be one of `'binary'`, `'base64'`, or `'hex'` and the `data` +argument is a string using the specified encoding. If the `input_encoding` +argument is not given, `data` must be a [`Buffer`][]. If `data` is a +[`Buffer`][] then `input_encoding` is ignored. -The `output_decoding` specifies in what format to return the -deciphered plaintext: `'binary'`, `'ascii'` or `'utf8'`. If no -encoding is provided, then a buffer is returned. +The `output_encoding` specifies the output format of the enciphered +data, and can be `'binary'`, `'ascii'` or `'utf8'`. If the `output_encoding` +is specified, a string using the specified encoding is returned. If no +`output_encoding` is provided, a [`Buffer`][] is returned. + +The `decipher.update()` method can be called multiple times with new data until +`decipher.final()` is called. Calling `decipher.update()` after +`decipher.final()` will result in an error being thrown. ## Class: DiffieHellman -The class for creating Diffie-Hellman key exchanges. +The `DiffieHellman` class is a utility for creating Diffie-Hellman key +exchanges. + +Instances of the `DiffieHellman` class can be created using the +`crypto.createDiffieHellman()` function. + + const crypto = require('crypto'); + const assert = require('assert'); + + // Generate Alice's keys... + const alice = crypto.createDiffieHellman(11); + const alice_key = alice.generateKeys(); -Returned by `crypto.createDiffieHellman`. + // Generate Bob's keys... + const bob = crypto.createDiffieHellman(11); + const bob_key = bob.generateKeys(); + + // Exchange and generate the secret... + const alice_secret = alice.computeSecret(bob_key); + const bob_secret = bob.computeSecret(alice_key); + + assert(alice_secret, bob_secret); + // OK ### diffieHellman.computeSecret(other_public_key[, input_encoding][, output_encoding]) Computes the shared secret using `other_public_key` as the other -party's public key and returns the computed shared secret. Supplied -key is interpreted using specified `input_encoding`, and secret is +party's public key and returns the computed shared secret. The supplied +key is interpreted using the specified `input_encoding`, and secret is encoded using specified `output_encoding`. Encodings can be -`'binary'`, `'hex'`, or `'base64'`. If the input encoding is not -provided, then a buffer is expected. +`'binary'`, `'hex'`, or `'base64'`. If the `input_encoding` is not +provided, `other_public_key` is expected to be a [`Buffer`][]. -If no output encoding is given, then a buffer is returned. +If `output_encoding` is given a string is returned; otherwise, a +[`Buffer`][] is returned. ### diffieHellman.generateKeys([encoding]) Generates private and public Diffie-Hellman key values, and returns -the public key in the specified encoding. This key should be +the public key in the specified `encoding`. This key should be transferred to the other party. Encoding can be `'binary'`, `'hex'`, -or `'base64'`. If no encoding is provided, then a buffer is returned. +or `'base64'`. If `encoding` is provided a string is returned; otherwise a +[`Buffer`][] is returned. ### diffieHellman.getGenerator([encoding]) -Returns the Diffie-Hellman generator in the specified encoding, which can -be `'binary'`, `'hex'`, or `'base64'`. If no encoding is provided, -then a buffer is returned. +Returns the Diffie-Hellman generator in the specified `encoding`, which can +be `'binary'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrime([encoding]) -Returns the Diffie-Hellman prime in the specified encoding, which can -be `'binary'`, `'hex'`, or `'base64'`. If no encoding is provided, -then a buffer is returned. +Returns the Diffie-Hellman prime in the specified `encoding`, which can +be `'binary'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrivateKey([encoding]) -Returns the Diffie-Hellman private key in the specified encoding, -which can be `'binary'`, `'hex'`, or `'base64'`. If no encoding is -provided, then a buffer is returned. +Returns the Diffie-Hellman private key in the specified `encoding`, +which can be `'binary'`, `'hex'`, or `'base64'`. If `encoding` is provided a +string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPublicKey([encoding]) -Returns the Diffie-Hellman public key in the specified encoding, which -can be `'binary'`, `'hex'`, or `'base64'`. If no encoding is provided, -then a buffer is returned. +Returns the Diffie-Hellman public key in the specified `encoding`, which +can be `'binary'`, `'hex'`, or `'base64'`. If `encoding` is provided a +string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.setPrivateKey(private_key[, encoding]) -Sets the Diffie-Hellman private key. Key encoding can be `'binary'`, -`'hex'` or `'base64'`. If no encoding is provided, then a buffer is -expected. +Sets the Diffie-Hellman private key. If the `encoding` argument is provided +and is either `'binary'`, `'hex'`, or `'base64'`, `private_key` is expected +to be a string. If no `encoding` is provided, `private_key` is expected +to be a [`Buffer`][]. ### diffieHellman.setPublicKey(public_key[, encoding]) -Sets the Diffie-Hellman public key. Key encoding can be `'binary'`, -`'hex'` or `'base64'`. If no encoding is provided, then a buffer is -expected. +Sets the Diffie-Hellman public key. If the `encoding` argument is provided +and is either `'binary'`, `'hex'` or `'base64'`, `public_key` is expected +to be a string. If no `encoding` is provided, `public_key` is expected +to be a [`Buffer`][]. ### diffieHellman.verifyError -A bit field containing any warnings and/or errors as a result of a check performed -during initialization. The following values are valid for this property -(defined in `constants` module): +A bit field containing any warnings and/or errors resulting from a check +performed during initialization of the `DiffieHellman` object. + +The following values are valid for this property (as defined in `constants` +module): * `DH_CHECK_P_NOT_SAFE_PRIME` * `DH_CHECK_P_NOT_PRIME` @@ -211,72 +377,97 @@ during initialization. The following values are valid for this property ## Class: ECDH -The class for creating EC Diffie-Hellman key exchanges. +The `ECDH` class is a utility for creating Elliptic Curve Diffie-Hellman (ECDH) +key exchanges. + +Instances of the `ECDH` class can be created using the +`crypto.createECDH()` function. + + const crypto = require('crypto'); + const assert = require('assert'); -Returned by `crypto.createECDH`. + // Generate Alice's keys... + const alice = crypto.createECDH('secp521r1'); + const alice_key = alice.generateKeys(); + + // Generate Bob's keys... + const bob = crypto.createECDH('secp521r1'); + const bob_key = bob.generateKeys(); + + // Exchange and generate the secret... + const alice_secret = alice.computeSecret(bob_key); + const bob_secret = bob.computeSecret(alice_key); + + assert(alice_secret, bob_secret); + // OK ### ECDH.computeSecret(other_public_key[, input_encoding][, output_encoding]) Computes the shared secret using `other_public_key` as the other -party's public key and returns the computed shared secret. Supplied -key is interpreted using specified `input_encoding`, and secret is -encoded using specified `output_encoding`. Encodings can be -`'binary'`, `'hex'`, or `'base64'`. If the input encoding is not -provided, then a buffer is expected. +party's public key and returns the computed shared secret. The supplied +key is interpreted using specified `input_encoding`, and the returned secret +is encoded using the specified `output_encoding`. Encodings can be +`'binary'`, `'hex'`, or `'base64'`. If the `input_encoding` is not +provided, `other_public_key` is expected to be a [`Buffer`][]. -If no output encoding is given, then a buffer is returned. +If `output_encoding` is given a string will be returned; otherwise a +[`Buffer`][] is returned. ### ECDH.generateKeys([encoding[, format]]) Generates private and public EC Diffie-Hellman key values, and returns -the public key in the specified format and encoding. This key should be +the public key in the specified `format` and `encoding`. This key should be transferred to the other party. -Format specifies point encoding and can be `'compressed'`, `'uncompressed'`, or -`'hybrid'`. If no format is provided - the point will be returned in -`'uncompressed'` format. +The `format` arguments specifies point encoding and can be `'compressed'`, +`'uncompressed'`, or `'hybrid'`. If `format` is not specified, the point will +be returned in `'uncompressed'` format. -Encoding can be `'binary'`, `'hex'`, or `'base64'`. If no encoding is provided, -then a buffer is returned. +The `encoding` argument can be `'binary'`, `'hex'`, or `'base64'`. If +`encoding` is provided a string is returned; otherwise a [`Buffer`][] +is returned. ### ECDH.getPrivateKey([encoding]) -Returns the EC Diffie-Hellman private key in the specified encoding, -which can be `'binary'`, `'hex'`, or `'base64'`. If no encoding is -provided, then a buffer is returned. +Returns the EC Diffie-Hellman private key in the specified `encoding`, +which can be `'binary'`, `'hex'`, or `'base64'`. If `encoding` is provided +a string is returned; otherwise a [`Buffer`][] is returned. ### ECDH.getPublicKey([encoding[, format]]) -Returns the EC Diffie-Hellman public key in the specified encoding and format. +Returns the EC Diffie-Hellman public key in the specified `encoding` and +`format`. -Format specifies point encoding and can be `'compressed'`, `'uncompressed'`, or -`'hybrid'`. If no format is provided - the point will be returned in -`'uncompressed'` format. +The `format` argument specifies point encoding and can be `'compressed'`, +`'uncompressed'`, or `'hybrid'`. If `format` is not specified the point will be +returned in `'uncompressed'` format. -Encoding can be `'binary'`, `'hex'`, or `'base64'`. If no encoding is provided, -then a buffer is returned. +The `encoding` argument can be `'binary'`, `'hex'`, or `'base64'`. If +`encoding` is specified, a string is returned; otherwise a [`Buffer`][] is +returned. ### ECDH.setPrivateKey(private_key[, encoding]) -Sets the EC Diffie-Hellman private key. Key encoding can be `'binary'`, -`'hex'` or `'base64'`. If no encoding is provided, then a buffer is -expected. If `private_key` is not valid for the curve specified when -the ECDH object was created, then an error is thrown. Upon setting -the private key, the associated public point (key) is also generated -and set in the ECDH object. +Sets the EC Diffie-Hellman private key. The `encoding` can be `'binary'`, +`'hex'` or `'base64'`. If `encoding` is provided, `private_key` is expected +to be a string; otherwise `private_key` is expected to be a [`Buffer`][]. If +`private_key` is not valid for the curve specified when the `ECDH` object was +created, an error is thrown. Upon setting the private key, the associated +public point (key) is also generated and set in the ECDH object. ### ECDH.setPublicKey(public_key[, encoding]) Stability: 0 - Deprecated Sets the EC Diffie-Hellman public key. Key encoding can be `'binary'`, -`'hex'` or `'base64'`. If no encoding is provided, then a buffer is -expected. Note that there is not normally a reason to call this -method. This is because ECDH only needs your private key and the -other party's public key to compute the shared secret. Thus, usually -either `generateKeys` or `setPrivateKey` will be called. -Note that `setPrivateKey` attempts to generate the public point/key -associated with the private key being set. +`'hex'` or `'base64'`. If `encoding` is provided `public_key` is expected to +be a string; otherwise a [`Buffer`][] is expected. + +Note that there is not normally a reason to call this method because `ECDH` +only requires a private key and the other party's public key to compute the +shared secret. Typically either `ecdh.generateKeys()` or `ecdh.setPrivateKey()` +will be called. The `ecdh.setPrivateKey()` method attempts to generate the +public point/key associated with the private key being set. Example (obtaining a shared secret): @@ -291,8 +482,8 @@ Example (obtaining a shared secret): crypto.createHash('sha256').update('alice', 'utf8').digest() ); - // Bob uses a newly generated cryptographically strong pseudorandom key pair - bob.generateKeys(); + // Bob uses a newly generated cryptographically strong + // pseudorandom key pair bob.generateKeys(); const alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); @@ -302,289 +493,470 @@ Example (obtaining a shared secret): ## Class: Hash -The class for creating hash digests of data. +The `Hash` class is a utility for creating hash digests of data. It can be +used in one of two ways: + +- As a [stream][] that is both readable and writable, where data is written + to produce a computed hash digest on the readable side, or +- Using the `hash.update()` and `hash.final()` methods to produce the + computed hash. + +The `crypto.createHash()` method is used to create `Hash` instances. `Hash` +objects are not to be created directly using the `new` keyword. + +Example: Using `Hash` objects as streams: + + const crypto = require('crypto'); + const hash = crypto.createHash('sha256'); + + hash.on('readable', () => { + var data = hash.read(); + if (data) + console.log(data.toString('hex')); + // Prints: + // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50 + }); + + hash.write('some data to hash'); + hash.end(); + +Example: Using `Hash` and piped streams: + + const crypto = require('crypto'); + const fs = require('fs'); + const hash = crypto.createHash('sha256'); + + const input = fs.createReadStream('test.js'); + input.pipe(hash).pipe(process.stdout); -It is a [stream][] that is both readable and writable. The written data -is used to compute the hash. Once the writable side of the stream is ended, -use the `read()` method to get the computed hash digest. The legacy `update` -and `digest` methods are also supported. +Example: Using the `hash.update()` and `hash.digest()` methods: -Returned by `crypto.createHash`. + const crypto = require('crypto'); + const hash = crypto.createHash('sha256'); + + hash.update('some data to hash'); + console.log(hash.digest('hex')); + // Prints: + // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50 ### hash.digest([encoding]) -Calculates the digest of all of the passed data to be hashed. The -`encoding` can be `'hex'`, `'binary'` or `'base64'`. If no encoding -is provided, then a buffer is returned. +Calculates the digest of all of the data passed to be hashed (using the +`hash.update()` method). The `encoding` can be `'hex'`, `'binary'` or +`'base64'`. If `encoding` is provided a string will be returned; otherwise +a [`Buffer`][] is returned. -Note: `hash` object can not be used after `digest()` method has been -called. +The `Hash` object can not be used again after `hash.digest()` method has been +called. Multiple calls will cause an error to be thrown. ### hash.update(data[, input_encoding]) Updates the hash content with the given `data`, the encoding of which is given in `input_encoding` and can be `'utf8'`, `'ascii'` or -`'binary'`. If no encoding is provided, and the input is a string, an -encoding of `'binary'` is enforced. If `data` is a `Buffer` then +`'binary'`. If `encoding` is not provided, and the `data` is a string, an +encoding of `'binary'` is enforced. If `data` is a [`Buffer`][] then `input_encoding` is ignored. This can be called many times with new data as it is streamed. ## Class: Hmac -Class for creating cryptographic hmac content. +The `Hmac` Class is a utility for creating cryptographic HMAC digests. It can +be used in one of two ways: + +- As a [stream][] that is both readable and writable, where data is written + to produce a computed HMAC digest on the readable side, or +- Using the `hmac.update()` and `hmac.final()` methods to produce the + computed HMAC digest. + +The `crypto.createHmac()` method is used to create `Hmac` instances. `Hmac` +objects are not to be created directly using the `new` keyword. + +Example: Using `Hmac` objects as streams: + + const crypto = require('crypto'); + const hmac = crypto.createHmac('sha256', 'a secret'); + + hmac.on('readable', () => { + var data = hmac.read(); + if (data) + console.log(data.toString('hex')); + // Prints: + // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e + }); + + hmac.write('some data to hash'); + hmac.end(); + +Example: Using `Hmac` and piped streams: + + const crypto = require('crypto'); + const fs = require('fs'); + const hmac = crypto.createHmac('sha256', 'a secret'); + + const input = fs.createReadStream('test.js'); + input.pipe(hmac).pipe(process.stdout); -Returned by `crypto.createHmac`. +Example: Using the `hmac.update()` and `hmac.digest()` methods: + + const crypto = require('crypto'); + const hmac = crypto.createHmac('sha256', 'a secret'); + + hmac.update('some data to hash'); + console.log(hmac.digest('hex')); + // Prints: + // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e ### hmac.digest([encoding]) -Calculates the digest of all of the passed data to the hmac. The -`encoding` can be `'hex'`, `'binary'` or `'base64'`. If no encoding -is provided, then a buffer is returned. +Calculates the HMAC digest of all of the data passed using `hmac.update()`. The +`encoding` can be `'hex'`, `'binary'` or `'base64'`. If `encoding` is provided +a string is returned; otherwise a [`Buffer`][] is returned; -Note: `hmac` object can not be used after `digest()` method has been -called. +The `Hmac` object can not be used again after `hmac.digest()` has been +called. Multiple calls to `hmac.digest()` will result in an error being thrown. ### hmac.update(data) -Update the hmac content with the given `data`. This can be called +Update the `Hmac` content with the given `data`. This can be called many times with new data as it is streamed. ## Class: Sign -Class for generating signatures. +The `Sign` Class is a utility for generating signatures. It can be used in one +of two ways: -Returned by `crypto.createSign`. +- As a writable [stream][], where data to be signed is written and the + `sign.sign()` method is used to generate and return the signature, or +- Using the `sign.update()` and `sign.sign()` methods to produce the + signature. -Sign objects are writable [streams][]. The written data is used to -generate the signature. Once all of the data has been written, the -`sign` method will return the signature. The legacy `update` method -is also supported. +The `crypto.createSign()` method is used to create `Sign` instances. `Sign` +objects are not to be created directly using the `new` keyword. -### sign.sign(private_key[, output_format]) +Example: Using `Sign` objects as streams: -Calculates the signature on all the updated data passed through the -sign. + const crypto = require('crypto'); + const sign = crypto.createSign('rsa-sha256'); -`private_key` can be an object or a string. If `private_key` is a string, it is -treated as the key with no passphrase. + sign.write('some data to sign'); + sign.end(); -`private_key`: + const private_key = getPrivateKeySomehow(); + console.log(sign.sign(private_key, 'hex')); + // Prints the calculated signature + +Example: Using the `sign.update()` and `sign.sign()` methods: + + const crypto = require('crypto'); + const sign = crypto.createSign('rsa-sha256'); + + sign.update('some data to sign'); + + const private_key = getPrivateKeySomehow(); + console.log(sign.sign(private_key, 'hex')); + // Prints the calculated signature + +### sign.sign(private_key[, output_format]) + +Calculates the signature on all the data passed through using either +`sign.update()` or `sign.write()`. + +The `private_key` argument can be an object or a string. If `private_key` is a +string, it is treated as a raw key with no passphrase. If `private_key` is an +object, it is interpreted as a hash containing two properties: * `key` : A string holding the PEM encoded private key * `passphrase` : A string of passphrase for the private key -Returns the signature in `output_format` which can be `'binary'`, -`'hex'` or `'base64'`. If no encoding is provided, then a buffer is +The `output_format` can specify one of `'binary'`, `'hex'` or `'base64'`. If +`output_format` is provided a string is returned; otherwise a [`Buffer`][] is returned. -Note: `sign` object can not be used after `sign()` method has been -called. +The `Sign` object can not be again used after `sign.sign()` method has been +called. Multiple calls to `sign.sign()` will result in an error being thrown. ### sign.update(data) -Updates the sign object with data. This can be called many times +Updates the sign object with the given `data`. This can be called many times with new data as it is streamed. ## Class: Verify -Class for verifying signatures. +The `Verify` class is a utility for verifying signatures. It can be used in one +of two ways: -Returned by `crypto.createVerify`. +- As a writable [stream][] where written data is used to validate against the + supplied signature, or +- Using the `verify.update()` and `verify.verify()` methods to verify the + signature. -Verify objects are writable [streams][]. The written data is used to -validate against the supplied signature. Once all of the data has been -written, the `verify` method will return true if the supplied signature -is valid. The legacy `update` method is also supported. + The `crypto.createSign()` method is used to create `Sign` instances. `Sign` + objects are not to be created directly using the `new` keyword. + +Example: Using `Verify` objects as streams: + + const crypto = require('crypto'); + const verify = crypto.createVerify('rsa-sha256'); + + verify.write('some data to sign'); + verify.end(); + + const public_key = getPublicKeySomehow(); + const signature = getSignatureToVerify(); + console.log(sign.verify(public_key, signature)); + // Prints true or false + +Example: Using the `verify.update()` and `verify.verify()` methods: + + const crypto = require('crypto'); + const verify = crypto.createVerify('rsa-sha256'); + + verify.update('some data to sign'); + + const public_key = getPublicKeySomehow(); + const signature = getSignatureToVerify(); + console.log(verify.verify(public_key, signature)); + // Prints true or false ### verifier.update(data) -Updates the verifier object with data. This can be called many times -with new data as it is streamed. +Updates the verifier object with the given `data`. This can be called many +times with new data as it is streamed. ### verifier.verify(object, signature[, signature_format]) -Verifies the signed data by using the `object` and `signature`. -`object` is a string containing a PEM encoded object, which can be -one of RSA public key, DSA public key, or X.509 certificate. -`signature` is the previously calculated signature for the data, in +Verifies the provided data using the given `object` and `signature`. +The `object` argument is a string containing a PEM encoded object, which can be +one an RSA public key, a DSA public key, or an X.509 certificate. +The `signature` argument is the previously calculated signature for the data, in the `signature_format` which can be `'binary'`, `'hex'` or `'base64'`. -If no encoding is specified, then a buffer is expected. +If a `signature_format` is specified, the `signature` is expected to be a +string; otherwise `signature` is expected to be a [`Buffer`][]. -Returns true or false depending on the validity of the signature for +Returns `true` or `false` depending on the validity of the signature for the data and public key. -Note: `verifier` object can not be used after `verify()` method has been -called. +The `verifier` object can not be used again after `verify.verify()` has been +called. Multiple calls to `verify.verify()` will result in an error being +thrown. -## crypto.DEFAULT_ENCODING +## `crypto` module methods and properties + +### crypto.DEFAULT_ENCODING The default encoding to use for functions that can take either strings -or buffers. The default value is `'buffer'`, which makes it default -to using Buffer objects. This is here to make the crypto module more -easily compatible with legacy programs that expected `'binary'` to be -the default encoding. +or [buffers][]. The default value is `'buffer'`, which makes methods default +to [`Buffer`][] objects. + +The `crypto.DEFAULT_ENCODING` mechanism is provided for backwards compatibility +with legacy programs that expect `'binary'` to be the default encoding. -Note that new programs will probably expect buffers, so only use this -as a temporary measure. +New applications should expect the default to be `'buffer'`. This property may +become deprecated in a future Node.js release. -## crypto.createCipher(algorithm, password) +### crypto.createCipher(algorithm, password) -Creates and returns a cipher object, with the given algorithm and -password. +Creates and returns a `Cipher` object that uses the given `algorithm` and +`password`. -`algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On -recent releases, `openssl list-cipher-algorithms` will display the -available cipher algorithms. `password` is used to derive key and IV, -which must be a `'binary'` encoded string or a [buffer][]. +The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On +recent OpenSSL releases, `openssl list-cipher-algorithms` will display the +available cipher algorithms. -It is a [stream][] that is both readable and writable. The written data -is used to compute the hash. Once the writable side of the stream is ended, -use the `read()` method to get the enciphered contents. The legacy `update` -and `final` methods are also supported. +The `password` is used to derive the cipher key and initialization vector (IV). +The value must be either a `'binary'` encoded string or a [`Buffer`[]. -Note: `createCipher` derives keys with 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. +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 pbkdf2 instead of [`EVP_BytesToKey`][] it -is recommended you derive a key and iv yourself with [`crypto.pbkdf2`][] and to -then use [`createCipheriv()`][] to create the cipher stream. +In line with OpenSSL's recommendation to use pbkdf2 instead of +[`EVP_BytesToKey`][] it is recommended that developers derive a key and IV on +their own using [`crypto.pbkdf2`][] and to use [`crypto.createCipheriv()`][] +to create the `Cipher` object. -## crypto.createCipheriv(algorithm, key, iv) +### crypto.createCipheriv(algorithm, key, iv) -Creates and returns a cipher object, with the given algorithm, key and -iv. +Creates and returns a `Cipher` object, with the given `algorithm`, `key` and +initialization vector (`iv`). -`algorithm` is the same as the argument to `createCipher()`. `key` is -the raw key used by the algorithm. `iv` is an [initialization vector][]. +The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On +recent OpenSSL releases, `openssl list-cipher-algorithms` will display the +available cipher algorithms. -`key` and `iv` must be `'binary'` encoded strings or [buffers][]. +The `key` is the raw key used by the `algorithm` and `iv` is an +[initialization vector][]. Both arguments must be `'binary'` encoded strings or +[buffers][]. -## crypto.createCredentials(details) +### crypto.createCredentials(details) Stability: 0 - Deprecated: Use [`tls.createSecureContext`][] instead. -Creates a credentials object, with the optional details being a -dictionary with keys: +The `crypto.createCredentials()` method is a deprecated alias for creating +and returning a `tls.SecureContext` object. The `crypto.createCredentials()` +method should not be used. -* `pfx` : A string or buffer holding the PFX or PKCS12 encoded private +The optional `details` argument is a hash object with keys: + +* `pfx` : A string or [`Buffer`][] holding the PFX or PKCS12 encoded private key, certificate and CA certificates * `key` : A string holding the PEM encoded private key -* `passphrase` : A string of passphrase for the private key or pfx +* `passphrase` : The string passphrase for the private key or PFX * `cert` : A string holding the PEM encoded certificate -* `ca` : Either a string or list of strings of PEM encoded CA +* `ca` : Either a string or array of strings of PEM encoded CA certificates to trust. -* `crl` : Either a string or list of strings of PEM encoded CRLs +* `crl` : Either a string or array of strings of PEM encoded CRLs (Certificate Revocation List) -* `ciphers`: A string describing the ciphers to use or exclude. - Consult - - for details on the format. +* `ciphers`: A string using the [OpenSSL cipher list format][] describing the + cipher algorithms to use or exclude. + +If no 'ca' details are given, Node.js will use Mozilla's default +[publicly trusted list of CAs][]. + +### crypto.createDecipher(algorithm, password) -If no 'ca' details are given, then Node.js will use the default -publicly trusted list of CAs as given in -. +Creates and returns a `Decipher` object that uses the given `algorithm` and +`password` (key). -## crypto.createDecipher(algorithm, password) +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. -Creates and returns a decipher object, with the given algorithm and -key. This is the mirror of the [`createCipher()`][] above. +In line with OpenSSL's recommendation to use pbkdf2 instead of +[`EVP_BytesToKey`][] it is recommended that developers derive a key and IV on +their own using [`crypto.pbkdf2`][] and to use [`crypto.createDecipheriv()`][] +to create the `Decipher` object. -## crypto.createDecipheriv(algorithm, key, iv) +### crypto.createDecipheriv(algorithm, key, iv) -Creates and returns a decipher object, with the given algorithm, key -and iv. This is the mirror of the [`createCipheriv()`][] above. +Creates and returns a `Decipher` object that uses the given `algorithm`, `key` +and initialization vector (`iv`). + +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 `key` is the raw key used by the `algorithm` and `iv` is an +[initialization vector][]. Both arguments must be `'binary'` encoded strings or +[buffers][]. ## crypto.createDiffieHellman(prime[, prime_encoding][, generator][, generator_encoding]) -Creates a Diffie-Hellman key exchange object using the supplied `prime` and an +Creates a `DiffieHellman` key exchange object using the supplied `prime` and an optional specific `generator`. -`generator` can be a number, string, or Buffer. -If no `generator` is specified, then `2` is used. -`prime_encoding` and `generator_encoding` can be `'binary'`, `'hex'`, or `'base64'`. -If no `prime_encoding` is specified, then a Buffer is expected for `prime`. -If no `generator_encoding` is specified, then a Buffer is expected for `generator`. -## crypto.createDiffieHellman(prime_length[, generator]) +The `generator` argument can be a number, string, or [`Buffer`][]. If +`generator` is not specified, the value `2` is used. + +The `prime_encoding` and `generator_encoding` arguments can be `'binary'`, +`'hex'`, or `'base64'`. -Creates a Diffie-Hellman key exchange object and generates a prime of -`prime_length` bits and using an optional specific numeric `generator`. -If no `generator` is specified, then `2` is used. +If `prime_encoding` is specified, `prime` is expected to be a string; otherwise +a [`Buffer`][] is expected. -## crypto.createECDH(curve_name) +If `generator_encoding` is specified, `generator` is expected to be a string; +otherwise either a number or [`Buffer`][] is expected. -Creates an Elliptic Curve (EC) Diffie-Hellman key exchange object using a -predefined curve specified by the `curve_name` string. Use [`getCurves()`][] to -obtain a list of available curve names. On recent releases, -`openssl ecparam -list_curves` will also display the name and description of -each available elliptic curve. +### crypto.createDiffieHellman(prime_length[, generator]) -## crypto.createHash(algorithm) +Creates a `DiffieHellman` key exchange object and generates a prime of +`prime_length` bits using an optional specific numeric `generator`. +If `generator` is not specified, the value `2` is used. -Creates and returns a hash object, a cryptographic hash with the given -algorithm which can be used to generate hash digests. +### crypto.createECDH(curve_name) -`algorithm` is dependent on the available algorithms supported by the -version of OpenSSL on the platform. Examples are `'sha256'`, -`'sha512'`, etc. On recent releases, `openssl -list-message-digest-algorithms` will display the available digest -algorithms. +Creates an Elliptic Curve Diffie-Hellman (`ECDH`) key exchange object using a +predefined curve specified by the `curve_name` string. Use +[`crypto.getCurves()`][] to obtain a list of available curve names. On recent +OpenSSL releases, `openssl ecparam -list_curves` will also display the name +and description of each available elliptic curve. -Example: this program that takes the sha256 sum of a file +### crypto.createHash(algorithm) + +Creates and returns a `Hash` object that can be used to generate hash digests +using the given `algorithm`. + +The `algorithm` is dependent on the available algorithms supported by the +version of OpenSSL on the platform. Examples are `'sha256'`, `'sha512'`, etc. +On recent releases of OpenSSL, `openssl list-message-digest-algorithms` will +display the available digest algorithms. + +Example: generating the sha256 sum of a file const filename = process.argv[2]; const crypto = require('crypto'); const fs = require('fs'); - const shasum = crypto.createHash('sha256'); + const hash = crypto.createHash('sha256'); - const s = fs.ReadStream(filename); - s.on('data', (d) => { - shasum.update(d); + const input = fs.createReadStream(filename); + input.on('readable', () => { + var data = input.read(); + if (data) + hash.update(data); + else { + console.log(`${hash.digest('hex')} ${filename}`); + } }); - s.on('end', () => { - var d = shasum.digest('hex'); - console.log(`${d} ${filename}`); - }); +### crypto.createHmac(algorithm, key) + +Creates and returns an `Hmac` object that uses the given `algorithm` and `key`. -## crypto.createHmac(algorithm, key) +The `algorithm` is dependent on the available algorithms supported by the +version of OpenSSL on the platform. Examples are `'sha256'`, `'sha512'`, etc. +On recent releases of OpenSSL, `openssl list-message-digest-algorithms` will +display the available digest algorithms. -Creates and returns a hmac object, a cryptographic hmac with the given -algorithm and key. +The `key` is the HMAC key used to generate the cryptographic HMAC hash. -It is a [stream][] that is both readable and writable. The written -data is used to compute the hmac. Once the writable side of the -stream is ended, use the `read()` method to get the computed digest. -The legacy `update` and `digest` methods are also supported. +Example: generating the sha256 HMAC of a file -`algorithm` is dependent on the available algorithms supported by -OpenSSL - see createHash above. `key` is the hmac key to be used. + const filename = process.argv[2]; + const crypto = require('crypto'); + const fs = require('fs'); + + const hmac = crypto.createHmac('sha256', 'a secret'); + + const input = fs.createReadStream(filename); + input.on('readable', () => { + var data = input.read(); + if (data) + hmac.update(data); + else { + console.log(`${hmac.digest('hex')} ${filename}`); + } + }); -## crypto.createSign(algorithm) +### crypto.createSign(algorithm) -Creates and returns a signing object, with the given algorithm. On +Creates and returns a `Sign` object that uses the given `algorithm`. On recent OpenSSL releases, `openssl list-public-key-algorithms` will -display the available signing algorithms. Examples are `'RSA-SHA256'`. +display the available signing algorithms. One example is `'RSA-SHA256'`. -## crypto.createVerify(algorithm) +### crypto.createVerify(algorithm) -Creates and returns a verification object, with the given algorithm. -This is the mirror of the signing object above. +Creates and returns a `Verify` object that uses the given algorithm. On +recent OpenSSL releases, `openssl list-public-key-algorithms` will +display the available signing algorithms. One example is `'RSA-SHA256'`. -## crypto.getCiphers() +### crypto.getCiphers() -Returns an array with the names of the supported ciphers. +Returns an array with the names of the supported cipher algorithms. Example: const ciphers = crypto.getCiphers(); console.log(ciphers); // ['aes-128-cbc', 'aes-128-ccm', ...] -## crypto.getCurves() +### crypto.getCurves() Returns an array with the names of the supported elliptic curves. @@ -593,17 +965,17 @@ Example: const curves = crypto.getCurves(); console.log(curves); // ['secp256k1', 'secp384r1', ...] -## crypto.getDiffieHellman(group_name) +### crypto.getDiffieHellman(group_name) -Creates a predefined Diffie-Hellman key exchange object. The +Creates a predefined `DiffieHellman` key exchange object. The supported groups are: `'modp1'`, `'modp2'`, `'modp5'` (defined in [RFC 2412][], but see [Caveats][]) and `'modp14'`, `'modp15'`, -`'modp16'`, `'modp17'`, `'modp18'` (defined in [RFC 3526][]). The +`'modp16'`, `'modp17'`, `'modp18'` (defined in [RFC 3526][]). The returned object mimics the interface of objects created by [`crypto.createDiffieHellman()`][] above, but will not allow changing the keys (with [`diffieHellman.setPublicKey()`][] for example). The -advantage of using this routine is that the parties do not have to -generate nor exchange group modulus beforehand, saving both processor +advantage of using this method is that the parties do not have to +generate nor exchange a group modulus beforehand, saving both processor and communication time. Example (obtaining a shared secret): @@ -621,7 +993,7 @@ Example (obtaining a shared secret): /* alice_secret and bob_secret should be the same */ console.log(alice_secret == bob_secret); -## crypto.getHashes() +### crypto.getHashes() Returns an array with the names of the supported hash algorithms. @@ -630,42 +1002,91 @@ Example: const hashes = crypto.getHashes(); console.log(hashes); // ['sha', 'sha1', 'sha1WithRSAEncryption', ...] -## crypto.pbkdf2(password, salt, iterations, keylen[, digest], callback) +### crypto.pbkdf2(password, salt, iterations, keylen[, digest], callback) + +Provides an asynchronous Password-Based Key Derivation Function 2 (PBKDF2) +implementation. A selected HMAC digest algorithm specified by `digest` is +applied to derive a key of the requested byte length (`keylen`) from the +`password`, `salt` and `iterations`. If the `digest` algorithm is not specified, +a default of `'sha1'` is used. -Asynchronous PBKDF2 function. Applies the selected HMAC digest function -(default: SHA1) to derive a key of the requested byte length from the password, -salt and number of iterations. The callback gets two arguments: -`(err, derivedKey)`. +The supplied `callback` function is called with two arguments: `err` and +`derivedKey`. If an error occurs, `err` will be set; otherwise `err` will be +null. The successfully generated `derivedKey` will be passed as a [`Buffer`][]. -The number of iterations passed to pbkdf2 should be as high as possible, the -higher the number, the more secure it will be, but will take a longer amount of -time to complete. +The `iterations` argument must be a number set as high as possible. The +higher the number of iterations, the more secure the derived key will be, +but will take a longer amount of time to complete. -Chosen salts should also be unique. It is recommended that the salts are random -and their length is greater than 16 bytes. See [NIST SP 800-132] for details. +The `salt` should also be as unique as possible. It is recommended that the +salts are random and their lengths are greater than 16 bytes. See +[NIST SP 800-132][] for details. Example: - crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', function(err, key) { - if (err) - throw err; + const crypto = require('crypto'); + crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, key) => { + if (err) throw err; console.log(key.toString('hex')); // 'c5e478d...1469e50' }); -You can get a list of supported digest functions with [`crypto.getHashes()`][]. +An array of supported digest functions can be retrieved using +[`crypto.getHashes()`][]. -## crypto.pbkdf2Sync(password, salt, iterations, keylen[, digest]) +### crypto.pbkdf2Sync(password, salt, iterations, keylen[, digest]) -Synchronous PBKDF2 function. Returns derivedKey or throws error. +Provides a synchronous Password-Based Key Derivation Function 2 (PBKDF2) +implementation. A selected HMAC digest algorithm specified by `digest` is +applied to derive a key of the requested byte length (`keylen`) from the +`password`, `salt` and `iterations`. If the `digest` algorithm is not specified, +a default of `'sha1'` is used. -## crypto.privateDecrypt(private_key, buffer) +If an error occurs an Error will be thrown, otherwise the derived key will be +returned as a [`Buffer`][]. + +The `iterations` argument must be a number set as high as possible. The +higher the number of iterations, the more secure the derived key will be, +but will take a longer amount of time to complete. + +The `salt` should also be as unique as possible. It is recommended that the +salts are random and their lengths are greater than 16 bytes. See +[NIST SP 800-132][] for details. + +Example: + + const crypto = require('crypto'); + const key = crypto.pbkdf2sync('secret', 'salt', 100000, 512, 'sha512'); + console.log(key.toString('hex')); // 'c5e478d...1469e50' + +An array of supported digest functions can be retrieved using +[`crypto.getHashes()`][]. + +### crypto.privateDecrypt(private_key, buffer) Decrypts `buffer` with `private_key`. `private_key` can be an object or a string. If `private_key` is a string, it is treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`. +If `private_key` is an object, it is interpreted as a hash object with the +keys: -`private_key`: +* `key` : A string holding the PEM encoded private key +* `passphrase` : An optional string of passphrase for the private key +* `padding` : An optional padding value, one of the following: + * `constants.RSA_NO_PADDING` + * `constants.RSA_PKCS1_PADDING` + * `constants.RSA_PKCS1_OAEP_PADDING` + +All paddings are defined in the `constants` module. + +### crypto.privateEncrypt(private_key, buffer) + +Encrypts `buffer` with `private_key`. + +`private_key` can be an object or a string. If `private_key` is a string, it is +treated as the key with no passphrase and will use `RSA_PKCS1_PADDING`. +If `private_key` is an object, it is interpreted as a hash object with the +keys: * `key` : A string holding the PEM encoded private key * `passphrase` : An optional string of passphrase for the private key @@ -674,65 +1095,91 @@ treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`. * `constants.RSA_PKCS1_PADDING` * `constants.RSA_PKCS1_OAEP_PADDING` -NOTE: All paddings are defined in `constants` module. +All paddings are defined in the `constants` module. + +### crypto.publicDecrypt(public_key, buffer) -## crypto.privateEncrypt(private_key, buffer) +Decrypts `buffer` with `public_key`. -See above for details. Has the same API as `crypto.privateDecrypt`. -Default padding is `RSA_PKCS1_PADDING`. +`public_key` can be an object or a string. If `public_key` is a string, it is +treated as the key with no passphrase and will use `RSA_PKCS1_PADDING`. +If `public_key` is an object, it is interpreted as a hash object with the +keys: + +* `key` : A string holding the PEM encoded public key +* `passphrase` : An optional string of passphrase for the private key +* `padding` : An optional padding value, one of the following: + * `constants.RSA_NO_PADDING` + * `constants.RSA_PKCS1_PADDING` + * `constants.RSA_PKCS1_OAEP_PADDING` -## crypto.publicDecrypt(public_key, buffer) +Because RSA public keys can be derived from private keys, a private key may +be passed instead of a public key. -See above for details. Has the same API as `crypto.publicEncrypt`. Default -padding is `RSA_PKCS1_PADDING`. +All paddings are defined in the `constants` module. -## crypto.publicEncrypt(public_key, buffer) +### crypto.publicEncrypt(public_key, buffer) -Encrypts `buffer` with `public_key`. Only RSA is currently supported. +Encrypts `buffer` with `public_key`. `public_key` can be an object or a string. If `public_key` is a string, it is treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`. -Since RSA public keys may be derived from private keys you may pass a private -key to this method. - -`public_key`: +If `public_key` is an object, it is interpreted as a hash object with the +keys: -* `key` : A string holding the PEM encoded private key +* `key` : A string holding the PEM encoded public key * `passphrase` : An optional string of passphrase for the private key * `padding` : An optional padding value, one of the following: * `constants.RSA_NO_PADDING` * `constants.RSA_PKCS1_PADDING` * `constants.RSA_PKCS1_OAEP_PADDING` -NOTE: All paddings are defined in `constants` module. +Because RSA public keys can be derived from private keys, a private key may +be passed instead of a public key. + +All paddings are defined in the `constants` module. + +### crypto.randomBytes(size[, callback]) -## crypto.randomBytes(size[, callback]) +Generates cryptographically strong pseudo-random data. The `size` argument +is a number indicating the number of bytes to generate. -Generates cryptographically strong pseudo-random data. Usage: +If a `callback` function is provided, the bytes are generated asynchronously +and the `callback` function is invoked with two arguments: `err` and `buf`. +If an error occurs, `err` will be an Error object; otherwise it is null. The +`buf` argument is a [`Buffer`][] containing the generated bytes. - // async - crypto.randomBytes(256, (ex, buf) => { - if (ex) throw ex; - console.log('Have %d bytes of random data: %s', buf.length, buf); + // Asynchronous + const crypto = require('crypto'); + crypto.randomBytes(256, (err, buf) => { + if (err) throw err; + console.log( + `${buf.length}` bytes of random data: ${buf.toString('hex')}); }); - // sync +If the `callback` function is not provided, the random bytes are generated +synchronously and returned as a [`Buffer`][]. An error will be thrown if +there is a problem generating the bytes. + + // Synchronous const buf = crypto.randomBytes(256); - console.log('Have %d bytes of random data: %s', buf.length, buf); + console.log( + `${buf.length}` bytes of random data: ${buf.toString('hex')}); -NOTE: This will block if there is insufficient entropy, although it should -normally never take longer than a few milliseconds. The only time when this -may conceivably block is right after boot, when the whole system is still -low on entropy. +The `crypto.randomBytes()` method will block until there is sufficient entropy. +This should normally never take longer than a few milliseconds. The only time +when generating the random bytes may conceivably block for a longer period of +time is right after boot, when the whole system is still low on entropy. -## crypto.setEngine(engine[, flags]) +### crypto.setEngine(engine[, flags]) -Load and set engine for some/all OpenSSL functions (selected by flags). +Load and set the `engine` for some or all OpenSSL functions (selected by flags). `engine` could be either an id or a path to the engine's shared library. -`flags` is optional and has `ENGINE_METHOD_ALL` value by default. It could take -one of or mix of following flags (defined in `constants` module): +The optional `flags` argument uses `ENGINE_METHOD_ALL` by default. The `flags` +is a bit field taking one of or a mix of the following flags (defined in the +`constants` module): * `ENGINE_METHOD_RSA` * `ENGINE_METHOD_DSA` @@ -748,57 +1195,45 @@ one of or mix of following flags (defined in `constants` module): * `ENGINE_METHOD_ALL` * `ENGINE_METHOD_NONE` -## Recent API Changes +## Notes + +### Legacy Streams API (pre Node.js v0.10) The Crypto module was added to Node.js before there was the concept of a -unified Stream API, and before there were Buffer objects for handling -binary data. - -As such, the streaming classes don't have the typical methods found on -other Node.js classes, and many methods accepted and returned -Binary-encoded strings by default rather than Buffers. This was -changed to use Buffers by default instead. - -This is a breaking change for some use cases, but not all. - -For example, if you currently use the default arguments to the Sign -class, and then pass the results to the Verify class, without ever -inspecting the data, then it will continue to work as before. Where -you once got a binary string and then presented the binary string to -the Verify object, you'll now get a Buffer, and present the Buffer to -the Verify object. - -However, if you were doing things with the string data that will not -work properly on Buffers (such as, concatenating them, storing in -databases, etc.), or you are passing binary strings to the crypto -functions without an encoding argument, then you will need to start -providing encoding arguments to specify which encoding you'd like to -use. To switch to the previous style of using binary strings by -default, set the `crypto.DEFAULT_ENCODING` field to 'binary'. Note -that new programs will probably expect buffers, so only use this as a -temporary measure. +unified Stream API, and before there were [`Buffer`][] objects for handling +binary data. As such, the many of the `crypto` defined classes have methods not +typically found on other Node.js classes that implement the [streams][] +API (e.g. `update()`, `final()`, or `digest()`). Also, many methods accepted +and returned `'binary'` encoded strings by default rather than Buffers. This +default was changed after Node.js v0.8 to use [`Buffer`][] objects by default +instead. + +### Recent ECDH Changes Usage of `ECDH` with non-dynamically generated key pairs has been simplified. -Now, `setPrivateKey` can be called with a preselected private key and the +Now, `ecdh.setPrivateKey()` can be called with a preselected private key and the associated public point (key) will be computed and stored in the object. -This allows you to only store and provide the private part of the EC key pair. -`setPrivateKey` now also validates that the private key is valid for the curve. -`ECDH.setPublicKey` is now deprecated as its inclusion in the API is not -useful. Either a previously stored private key should be set, which -automatically generates the associated public key, or `generateKeys` should be -called. The main drawback of `ECDH.setPublicKey` is that it can be used to put -the ECDH key pair into an inconsistent state. +This allows code to only store and provide the private part of the EC key pair. +`ecdh.setPrivateKey()` now also validates that the private key is valid for the +selected curve. + +The `ecdh.setPublicKey()` method is now deprecated as its inclusion in the API +is not useful. Either a previously stored private key should be set, which +automatically generates the associated public key, or `ecdh.generateKeys()` +should be called. The main drawback of using `ecdh.setPublicKey()` is that it +can be used to put the ECDH key pair into an inconsistent state. -## Caveats +### Support for weak or compromised algorithms -The crypto module still supports some algorithms which are already -compromised. And the API also allows the use of ciphers and hashes -with a small key size that are considered to be too weak for safe use. +The `crypto` module still supports some algorithms which are already +compromised and are not currently recommended for use. The API also allows +the use of ciphers and hashes with a small key size that are considered to be +too weak for safe use. Users should take full responsibility for selecting the crypto algorithm and key size according to their security requirements. -Based on the recommendations of [NIST SP 800-131A]: +Based on the recommendations of [NIST SP 800-131A][]: - MD5 and SHA-1 are no longer acceptable where collision resistance is required such as digital signatures. @@ -810,6 +1245,8 @@ Based on the recommendations of [NIST SP 800-131A]: See the reference for other recommendations and details. +[HTML5's `keygen` element]: http://www.w3.org/TR/html5/forms.html#the-keygen-element +[OpenSSL's SPKAC implementation]: https://www.openssl.org/docs/apps/spkac.html [`createCipher()`]: #crypto_crypto_createcipher_algorithm_password [`createCipheriv()`]: #crypto_crypto_createcipheriv_algorithm_key_iv [`crypto.createDecipher`]: #crypto_crypto_createdecipher_algorithm_password @@ -822,13 +1259,15 @@ See the reference for other recommendations and details. [`EVP_BytesToKey`]: https://www.openssl.org/docs/crypto/EVP_BytesToKey.html [`getCurves()`]: #crypto_crypto_getcurves [`tls.createSecureContext`]: tls.html#tls_tls_createsecurecontext_details -[buffer]: buffer.html +[`Buffer`]: buffer.html [buffers]: buffer.html -[Caveats]: #crypto_caveats +[Caveats]: #crypto_support_for_weak_or_compromised_algorithms [initialization vector]: https://en.wikipedia.org/wiki/Initialization_vector -[NIST SP 800-131A]: http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf +[NIST SP 800-131A]: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf [NIST SP 800-132]: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf [RFC 2412]: https://www.rfc-editor.org/rfc/rfc2412.txt [RFC 3526]: https://www.rfc-editor.org/rfc/rfc3526.txt [stream]: stream.html [streams]: stream.html +[OpenSSL cipher list format]: https://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT +[publicly trusted list of CAs]: https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt