summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2017-09-06 08:10:34 -0700
committerJames M Snell <jasnell@gmail.com>2017-09-18 08:10:59 -0700
commitc75f87cc4c8d3699e081d37bb5bf47a70d830fdb (patch)
tree9d79319f568ff43e36e05a8d2634130adfacfb74 /lib
parent8fa5fcc0ba74c23490c34da1a6c6e9a454280740 (diff)
downloadandroid-node-v8-c75f87cc4c8d3699e081d37bb5bf47a70d830fdb.tar.gz
android-node-v8-c75f87cc4c8d3699e081d37bb5bf47a70d830fdb.tar.bz2
android-node-v8-c75f87cc4c8d3699e081d37bb5bf47a70d830fdb.zip
crypto: refactor the crypto module
* Split single monolithic file into multiple * Make Certificate methods static * Allow randomFill(Sync) to use any ArrayBufferView * Use internal/errors throughout * Improve arg validation in Hash/Hmac * Doc updates PR-URL: https://github.com/nodejs/node/pull/15231 Reviewed-By: Michaƫl Zasso <targos@protonmail.com> Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto.js906
-rw-r--r--lib/internal/crypto/certificate.js40
-rw-r--r--lib/internal/crypto/cipher.js214
-rw-r--r--lib/internal/crypto/diffiehellman.js216
-rw-r--r--lib/internal/crypto/hash.js125
-rw-r--r--lib/internal/crypto/pbkdf2.js59
-rw-r--r--lib/internal/crypto/random.js98
-rw-r--r--lib/internal/crypto/sig.js131
-rw-r--r--lib/internal/crypto/util.js70
-rwxr-xr-xlib/internal/errors.js6
10 files changed, 1091 insertions, 774 deletions
diff --git a/lib/crypto.js b/lib/crypto.js
index 56795e23f2..1c8c6b36fb 100644
--- a/lib/crypto.js
+++ b/lib/crypto.js
@@ -24,786 +24,144 @@
'use strict';
-const internalUtil = require('internal/util');
-internalUtil.assertCrypto();
-
-exports.DEFAULT_ENCODING = 'buffer';
+const {
+ assertCrypto,
+ deprecate
+} = require('internal/util');
+assertCrypto();
const constants = process.binding('constants').crypto;
-const binding = process.binding('crypto');
-const randomBytes = binding.randomBytes;
-const getCiphers = binding.getCiphers;
-const getHashes = binding.getHashes;
-const getCurves = binding.getCurves;
-const getFipsCrypto = binding.getFipsCrypto;
-const setFipsCrypto = binding.setFipsCrypto;
-const timingSafeEqual = binding.timingSafeEqual;
-
-const Buffer = require('buffer').Buffer;
-const kBufferMaxLength = require('buffer').kMaxLength;
-const stream = require('stream');
-const util = require('util');
-const { isUint8Array } = process.binding('util');
-const LazyTransform = require('internal/streams/lazy_transform');
-
-const DH_GENERATOR = 2;
-
-Object.defineProperty(exports, 'constants', {
- configurable: false,
- enumerable: true,
- value: constants
-});
-
-// This is here because many functions accepted binary strings without
-// any explicit encoding in older versions of node, and we don't want
-// to break them unnecessarily.
-function toBuf(str, encoding) {
- if (typeof str === 'string') {
- if (encoding === 'buffer' || !encoding)
- encoding = 'utf8';
- return Buffer.from(str, encoding);
- }
- return str;
-}
-exports._toBuf = toBuf;
-
-
-const assert = require('assert');
-const StringDecoder = require('string_decoder').StringDecoder;
-
-
-exports.createHash = exports.Hash = Hash;
-function Hash(algorithm, options) {
- if (!(this instanceof Hash))
- return new Hash(algorithm, options);
- this._handle = new binding.Hash(algorithm);
- LazyTransform.call(this, options);
-}
-
-util.inherits(Hash, LazyTransform);
-
-Hash.prototype._transform = function _transform(chunk, encoding, callback) {
- this._handle.update(chunk, encoding);
- callback();
-};
-
-Hash.prototype._flush = function _flush(callback) {
- this.push(this._handle.digest());
- callback();
-};
-
-Hash.prototype.update = function update(data, encoding) {
- encoding = encoding || exports.DEFAULT_ENCODING;
- this._handle.update(data, encoding);
- return this;
-};
-
-
-Hash.prototype.digest = function digest(outputEncoding) {
- outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
- // Explicit conversion for backward compatibility.
- return this._handle.digest(`${outputEncoding}`);
-};
-
-
-exports.createHmac = exports.Hmac = Hmac;
-
-function Hmac(hmac, key, options) {
- if (!(this instanceof Hmac))
- return new Hmac(hmac, key, options);
- this._handle = new binding.Hmac();
- this._handle.init(hmac, toBuf(key));
- LazyTransform.call(this, options);
-}
-
-util.inherits(Hmac, LazyTransform);
-
-Hmac.prototype.update = Hash.prototype.update;
-Hmac.prototype.digest = Hash.prototype.digest;
-Hmac.prototype._flush = Hash.prototype._flush;
-Hmac.prototype._transform = Hash.prototype._transform;
-
-
-function getDecoder(decoder, encoding) {
- encoding = internalUtil.normalizeEncoding(encoding);
- decoder = decoder || new StringDecoder(encoding);
- assert(decoder.encoding === encoding, 'Cannot change encoding');
- return decoder;
-}
-
-
-exports.createCipher = exports.Cipher = Cipher;
-function Cipher(cipher, password, options) {
- if (!(this instanceof Cipher))
- return new Cipher(cipher, password, options);
- this._handle = new binding.CipherBase(true);
-
- this._handle.init(cipher, toBuf(password));
- this._decoder = null;
-
- LazyTransform.call(this, options);
-}
-
-util.inherits(Cipher, LazyTransform);
-
-Cipher.prototype._transform = function _transform(chunk, encoding, callback) {
- this.push(this._handle.update(chunk, encoding));
- callback();
-};
-
-Cipher.prototype._flush = function _flush(callback) {
- try {
- this.push(this._handle.final());
- } catch (e) {
- callback(e);
- return;
- }
- callback();
-};
-
-Cipher.prototype.update = function update(data, inputEncoding, outputEncoding) {
- inputEncoding = inputEncoding || exports.DEFAULT_ENCODING;
- outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
-
- var ret = this._handle.update(data, inputEncoding);
-
- if (outputEncoding && outputEncoding !== 'buffer') {
- this._decoder = getDecoder(this._decoder, outputEncoding);
- ret = this._decoder.write(ret);
- }
-
- return ret;
-};
-
-
-Cipher.prototype.final = function final(outputEncoding) {
- outputEncoding = outputEncoding || exports.DEFAULT_ENCODING;
- var ret = this._handle.final();
-
- if (outputEncoding && outputEncoding !== 'buffer') {
- this._decoder = getDecoder(this._decoder, outputEncoding);
- ret = this._decoder.end(ret);
- }
-
- return ret;
-};
-
-
-Cipher.prototype.setAutoPadding = function setAutoPadding(ap) {
- this._handle.setAutoPadding(ap);
- return this;
-};
-
-Cipher.prototype.getAuthTag = function getAuthTag() {
- return this._handle.getAuthTag();
-};
-
-
-Cipher.prototype.setAuthTag = function setAuthTag(tagbuf) {
- this._handle.setAuthTag(tagbuf);
- return this;
-};
-
-Cipher.prototype.setAAD = function setAAD(aadbuf) {
- this._handle.setAAD(aadbuf);
- return this;
-};
-
-exports.createCipheriv = exports.Cipheriv = Cipheriv;
-function Cipheriv(cipher, key, iv, options) {
- if (!(this instanceof Cipheriv))
- return new Cipheriv(cipher, key, iv, options);
- this._handle = new binding.CipherBase(true);
- this._handle.initiv(cipher, toBuf(key), toBuf(iv));
- this._decoder = null;
-
- LazyTransform.call(this, options);
-}
-
-util.inherits(Cipheriv, LazyTransform);
-
-Cipheriv.prototype._transform = Cipher.prototype._transform;
-Cipheriv.prototype._flush = Cipher.prototype._flush;
-Cipheriv.prototype.update = Cipher.prototype.update;
-Cipheriv.prototype.final = Cipher.prototype.final;
-Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
-Cipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
-Cipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
-Cipheriv.prototype.setAAD = Cipher.prototype.setAAD;
-
-exports.createDecipher = exports.Decipher = Decipher;
-function Decipher(cipher, password, options) {
- if (!(this instanceof Decipher))
- return new Decipher(cipher, password, options);
-
- this._handle = new binding.CipherBase(false);
- this._handle.init(cipher, toBuf(password));
- this._decoder = null;
-
- LazyTransform.call(this, options);
-}
-
-util.inherits(Decipher, LazyTransform);
-
-Decipher.prototype._transform = Cipher.prototype._transform;
-Decipher.prototype._flush = Cipher.prototype._flush;
-Decipher.prototype.update = Cipher.prototype.update;
-Decipher.prototype.final = Cipher.prototype.final;
-Decipher.prototype.finaltol = Cipher.prototype.final;
-Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
-Decipher.prototype.getAuthTag = Cipher.prototype.getAuthTag;
-Decipher.prototype.setAuthTag = Cipher.prototype.setAuthTag;
-Decipher.prototype.setAAD = Cipher.prototype.setAAD;
-
-
-exports.createDecipheriv = exports.Decipheriv = Decipheriv;
-function Decipheriv(cipher, key, iv, options) {
- if (!(this instanceof Decipheriv))
- return new Decipheriv(cipher, key, iv, options);
-
- this._handle = new binding.CipherBase(false);
- this._handle.initiv(cipher, toBuf(key), toBuf(iv));
- this._decoder = null;
-
- LazyTransform.call(this, options);
-}
-
-util.inherits(Decipheriv, LazyTransform);
-
-Decipheriv.prototype._transform = Cipher.prototype._transform;
-Decipheriv.prototype._flush = Cipher.prototype._flush;
-Decipheriv.prototype.update = Cipher.prototype.update;
-Decipheriv.prototype.final = Cipher.prototype.final;
-Decipheriv.prototype.finaltol = Cipher.prototype.final;
-Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
-Decipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
-Decipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
-Decipheriv.prototype.setAAD = Cipher.prototype.setAAD;
-
-
-exports.createSign = exports.Sign = Sign;
-function Sign(algorithm, options) {
- if (!(this instanceof Sign))
- return new Sign(algorithm, options);
- this._handle = new binding.Sign();
- this._handle.init(algorithm);
-
- stream.Writable.call(this, options);
-}
-
-util.inherits(Sign, stream.Writable);
-
-Sign.prototype._write = function _write(chunk, encoding, callback) {
- this._handle.update(chunk, encoding);
- callback();
-};
-
-Sign.prototype.update = Hash.prototype.update;
-
-Sign.prototype.sign = function sign(options, encoding) {
- if (!options)
- throw new Error('No key provided to sign');
-
- var key = options.key || options;
- var passphrase = options.passphrase || null;
-
- // Options specific to RSA
- var rsaPadding = constants.RSA_PKCS1_PADDING;
- if (options.hasOwnProperty('padding')) {
- if (options.padding === options.padding >> 0) {
- rsaPadding = options.padding;
- } else {
- throw new TypeError('padding must be an integer');
- }
- }
-
- var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO;
- if (options.hasOwnProperty('saltLength')) {
- if (options.saltLength === options.saltLength >> 0) {
- pssSaltLength = options.saltLength;
- } else {
- throw new TypeError('saltLength must be an integer');
- }
- }
-
- var ret = this._handle.sign(toBuf(key), passphrase, rsaPadding,
- pssSaltLength);
-
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- ret = ret.toString(encoding);
-
- return ret;
-};
-
-
-exports.createVerify = exports.Verify = Verify;
-function Verify(algorithm, options) {
- if (!(this instanceof Verify))
- return new Verify(algorithm, options);
-
- this._handle = new binding.Verify();
- this._handle.init(algorithm);
-
- stream.Writable.call(this, options);
-}
-
-util.inherits(Verify, stream.Writable);
-
-Verify.prototype._write = Sign.prototype._write;
-Verify.prototype.update = Sign.prototype.update;
-
-Verify.prototype.verify = function verify(options, signature, sigEncoding) {
- var key = options.key || options;
- sigEncoding = sigEncoding || exports.DEFAULT_ENCODING;
-
- // Options specific to RSA
- var rsaPadding = constants.RSA_PKCS1_PADDING;
- if (options.hasOwnProperty('padding')) {
- if (options.padding === options.padding >> 0) {
- rsaPadding = options.padding;
- } else {
- throw new TypeError('padding must be an integer');
- }
- }
-
- var pssSaltLength = constants.RSA_PSS_SALTLEN_AUTO;
- if (options.hasOwnProperty('saltLength')) {
- if (options.saltLength === options.saltLength >> 0) {
- pssSaltLength = options.saltLength;
- } else {
- throw new TypeError('saltLength must be an integer');
- }
- }
-
- return this._handle.verify(toBuf(key), toBuf(signature, sigEncoding),
- rsaPadding, pssSaltLength);
-};
-
-function rsaPublic(method, defaultPadding) {
- return function(options, buffer) {
- var key = options.key || options;
- var padding = options.padding || defaultPadding;
- var passphrase = options.passphrase || null;
- return method(toBuf(key), buffer, padding, passphrase);
- };
-}
-
-function rsaPrivate(method, defaultPadding) {
- return function(options, buffer) {
- var key = options.key || options;
- var passphrase = options.passphrase || null;
- var padding = options.padding || defaultPadding;
- return method(toBuf(key), buffer, padding, passphrase);
- };
+const {
+ getFipsCrypto,
+ setFipsCrypto,
+ timingSafeEqual
+} = process.binding('crypto');
+const {
+ randomBytes,
+ randomFill,
+ randomFillSync
+} = require('internal/crypto/random');
+const {
+ pbkdf2,
+ pbkdf2Sync
+} = require('internal/crypto/pbkdf2');
+const {
+ DiffieHellman,
+ DiffieHellmanGroup,
+ ECDH
+} = require('internal/crypto/diffiehellman');
+const {
+ Cipher,
+ Cipheriv,
+ Decipher,
+ Decipheriv,
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt
+} = require('internal/crypto/cipher');
+const {
+ Sign,
+ Verify
+} = require('internal/crypto/sig');
+const {
+ Hash,
+ Hmac
+} = require('internal/crypto/hash');
+const {
+ getCiphers,
+ getCurves,
+ getDefaultEncoding,
+ getHashes,
+ setDefaultEncoding,
+ setEngine,
+ toBuf
+} = require('internal/crypto/util');
+const Certificate = require('internal/crypto/certificate');
+
+function createECDH(curve) {
+ return new ECDH(curve);
}
-exports.publicEncrypt = rsaPublic(binding.publicEncrypt,
- constants.RSA_PKCS1_OAEP_PADDING);
-exports.publicDecrypt = rsaPublic(binding.publicDecrypt,
- constants.RSA_PKCS1_PADDING);
-exports.privateEncrypt = rsaPrivate(binding.privateEncrypt,
- constants.RSA_PKCS1_PADDING);
-exports.privateDecrypt = rsaPrivate(binding.privateDecrypt,
- constants.RSA_PKCS1_OAEP_PADDING);
-
-
-exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
-
-function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
- if (!(this instanceof DiffieHellman))
- return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
-
- if (typeof sizeOrKey !== 'number' &&
- typeof sizeOrKey !== 'string' &&
- !ArrayBuffer.isView(sizeOrKey)) {
- throw new TypeError('First argument should be number, string, ' +
- 'Buffer, TypedArray, or DataView');
- }
-
- if (keyEncoding) {
- if (typeof keyEncoding !== 'string' ||
- (!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
- genEncoding = generator;
- generator = keyEncoding;
- keyEncoding = false;
- }
- }
-
- keyEncoding = keyEncoding || exports.DEFAULT_ENCODING;
- genEncoding = genEncoding || exports.DEFAULT_ENCODING;
-
- if (typeof sizeOrKey !== 'number')
- sizeOrKey = toBuf(sizeOrKey, keyEncoding);
-
- if (!generator)
- generator = DH_GENERATOR;
- else if (typeof generator !== 'number')
- generator = toBuf(generator, genEncoding);
-
- this._handle = new binding.DiffieHellman(sizeOrKey, generator);
- Object.defineProperty(this, 'verifyError', {
+module.exports = exports = {
+ // Methods
+ _toBuf: toBuf,
+ createCipher: Cipher,
+ createCipheriv: Cipheriv,
+ createDecipher: Decipher,
+ createDecipheriv: Decipheriv,
+ createDiffieHellman: DiffieHellman,
+ createDiffieHellmanGroup: DiffieHellmanGroup,
+ createECDH,
+ createHash: Hash,
+ createHmac: Hmac,
+ createSign: Sign,
+ createVerify: Verify,
+ getCiphers,
+ getCurves,
+ getDiffieHellman: DiffieHellmanGroup,
+ getHashes,
+ pbkdf2,
+ pbkdf2Sync,
+ privateDecrypt,
+ privateEncrypt,
+ prng: randomBytes,
+ pseudoRandomBytes: randomBytes,
+ publicDecrypt,
+ publicEncrypt,
+ randomBytes,
+ randomFill,
+ randomFillSync,
+ rng: randomBytes,
+ setEngine,
+ timingSafeEqual,
+
+ // Classes
+ Certificate,
+ Cipher,
+ Cipheriv,
+ Decipher,
+ Decipheriv,
+ DiffieHellman,
+ DiffieHellmanGroup,
+ Hash,
+ Hmac,
+ Sign,
+ Verify
+};
+
+Object.defineProperties(exports, {
+ fips: {
+ get: getFipsCrypto,
+ set: setFipsCrypto
+ },
+ DEFAULT_ENCODING: {
enumerable: true,
- value: this._handle.verifyError,
- writable: false
- });
-}
-
-
-exports.DiffieHellmanGroup =
- exports.createDiffieHellmanGroup =
- exports.getDiffieHellman = DiffieHellmanGroup;
-
-function DiffieHellmanGroup(name) {
- if (!(this instanceof DiffieHellmanGroup))
- return new DiffieHellmanGroup(name);
- this._handle = new binding.DiffieHellmanGroup(name);
- Object.defineProperty(this, 'verifyError', {
+ configurable: true,
+ get: getDefaultEncoding,
+ set: setDefaultEncoding
+ },
+ constants: {
+ configurable: false,
enumerable: true,
- value: this._handle.verifyError,
- writable: false
- });
-}
-
-
-DiffieHellmanGroup.prototype.generateKeys =
- DiffieHellman.prototype.generateKeys =
- dhGenerateKeys;
-
-function dhGenerateKeys(encoding) {
- var keys = this._handle.generateKeys();
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- keys = keys.toString(encoding);
- return keys;
-}
-
-
-DiffieHellmanGroup.prototype.computeSecret =
- DiffieHellman.prototype.computeSecret =
- dhComputeSecret;
-
-function dhComputeSecret(key, inEnc, outEnc) {
- inEnc = inEnc || exports.DEFAULT_ENCODING;
- outEnc = outEnc || exports.DEFAULT_ENCODING;
- var ret = this._handle.computeSecret(toBuf(key, inEnc));
- if (outEnc && outEnc !== 'buffer')
- ret = ret.toString(outEnc);
- return ret;
-}
-
-
-DiffieHellmanGroup.prototype.getPrime =
- DiffieHellman.prototype.getPrime =
- dhGetPrime;
-
-function dhGetPrime(encoding) {
- var prime = this._handle.getPrime();
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- prime = prime.toString(encoding);
- return prime;
-}
-
-
-DiffieHellmanGroup.prototype.getGenerator =
- DiffieHellman.prototype.getGenerator =
- dhGetGenerator;
-
-function dhGetGenerator(encoding) {
- var generator = this._handle.getGenerator();
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- generator = generator.toString(encoding);
- return generator;
-}
-
-
-DiffieHellmanGroup.prototype.getPublicKey =
- DiffieHellman.prototype.getPublicKey =
- dhGetPublicKey;
-
-function dhGetPublicKey(encoding) {
- var key = this._handle.getPublicKey();
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- key = key.toString(encoding);
- return key;
-}
-
-
-DiffieHellmanGroup.prototype.getPrivateKey =
- DiffieHellman.prototype.getPrivateKey =
- dhGetPrivateKey;
-
-function dhGetPrivateKey(encoding) {
- var key = this._handle.getPrivateKey();
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- key = key.toString(encoding);
- return key;
-}
+ value: constants
+ },
-
-DiffieHellman.prototype.setPublicKey = function setPublicKey(key, encoding) {
- encoding = encoding || exports.DEFAULT_ENCODING;
- this._handle.setPublicKey(toBuf(key, encoding));
- return this;
-};
-
-
-DiffieHellman.prototype.setPrivateKey = function setPrivateKey(key, encoding) {
- encoding = encoding || exports.DEFAULT_ENCODING;
- this._handle.setPrivateKey(toBuf(key, encoding));
- return this;
-};
-
-
-function ECDH(curve) {
- if (typeof curve !== 'string')
- throw new TypeError('"curve" argument should be a string');
-
- this._handle = new binding.ECDH(curve);
-}
-
-exports.createECDH = function createECDH(curve) {
- return new ECDH(curve);
-};
-
-ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret;
-ECDH.prototype.setPrivateKey = DiffieHellman.prototype.setPrivateKey;
-ECDH.prototype.setPublicKey = DiffieHellman.prototype.setPublicKey;
-ECDH.prototype.getPrivateKey = DiffieHellman.prototype.getPrivateKey;
-
-ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
- this._handle.generateKeys();
-
- return this.getPublicKey(encoding, format);
-};
-
-ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
- var f;
- if (format) {
- if (typeof format === 'number')
- f = format;
- if (format === 'compressed')
- f = constants.POINT_CONVERSION_COMPRESSED;
- else if (format === 'hybrid')
- f = constants.POINT_CONVERSION_HYBRID;
- // Default
- else if (format === 'uncompressed')
- f = constants.POINT_CONVERSION_UNCOMPRESSED;
- else
- throw new TypeError('Bad format: ' + format);
- } else {
- f = constants.POINT_CONVERSION_UNCOMPRESSED;
- }
- var key = this._handle.getPublicKey(f);
- encoding = encoding || exports.DEFAULT_ENCODING;
- if (encoding && encoding !== 'buffer')
- key = key.toString(encoding);
- return key;
-};
-
-
-exports.pbkdf2 = function(password,
- salt,
- iterations,
- keylen,
- digest,
- callback) {
- if (typeof digest === 'function') {
- callback = digest;
- digest = undefined;
- }
-
- if (typeof callback !== 'function')
- throw new Error('No callback provided to pbkdf2');
-
- return pbkdf2(password, salt, iterations, keylen, digest, callback);
-};
-
-
-exports.pbkdf2Sync = function(password, salt, iterations, keylen, digest) {
- return pbkdf2(password, salt, iterations, keylen, digest);
-};
-
-
-function pbkdf2(password, salt, iterations, keylen, digest, callback) {
-
- if (digest === undefined) {
- throw new TypeError(
- 'The "digest" argument is required and must not be undefined');
- }
-
- password = toBuf(password);
- salt = toBuf(salt);
-
- if (exports.DEFAULT_ENCODING === 'buffer')
- return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);
-
- // at this point, we need to handle encodings.
- var encoding = exports.DEFAULT_ENCODING;
- if (callback) {
- function next(er, ret) {
- if (ret)
- ret = ret.toString(encoding);
- callback(er, ret);
- }
- binding.PBKDF2(password, salt, iterations, keylen, digest, next);
- } else {
- var ret = binding.PBKDF2(password, salt, iterations, keylen, digest);
- return ret.toString(encoding);
- }
-}
-
-
-exports.Certificate = Certificate;
-
-function Certificate() {
- if (!(this instanceof Certificate))
- return new Certificate();
-}
-
-
-Certificate.prototype.verifySpkac = function verifySpkac(object) {
- return binding.certVerifySpkac(object);
-};
-
-
-Certificate.prototype.exportPublicKey =
- function exportPublicKey(object, encoding) {
- return binding.certExportPublicKey(toBuf(object, encoding));
- };
-
-
-Certificate.prototype.exportChallenge =
- function exportChallenge(object, encoding) {
- return binding.certExportChallenge(toBuf(object, encoding));
- };
-
-
-exports.setEngine = function setEngine(id, flags) {
- if (typeof id !== 'string')
- throw new TypeError('"id" argument should be a string');
-
- if (flags && typeof flags !== 'number')
- throw new TypeError('"flags" argument should be a number, if present');
- flags = flags >>> 0;
-
- // Use provided engine for everything by default
- if (flags === 0)
- flags = constants.ENGINE_METHOD_ALL;
-
- return binding.setEngine(id, flags);
-};
-
-const kMaxUint32 = Math.pow(2, 32) - 1;
-
-function randomFillSync(buf, offset = 0, size) {
- if (!isUint8Array(buf)) {
- throw new TypeError('"buf" argument must be a Buffer or Uint8Array');
- }
-
- assertOffset(offset, buf.length);
-
- if (size === undefined) size = buf.length - offset;
-
- assertSize(size, offset, buf.length);
-
- return binding.randomFill(buf, offset, size);
-}
-exports.randomFillSync = randomFillSync;
-
-function randomFill(buf, offset, size, cb) {
- if (!isUint8Array(buf)) {
- throw new TypeError('"buf" argument must be a Buffer or Uint8Array');
- }
-
- if (typeof offset === 'function') {
- cb = offset;
- offset = 0;
- size = buf.length;
- } else if (typeof size === 'function') {
- cb = size;
- size = buf.length - offset;
- } else if (typeof cb !== 'function') {
- throw new TypeError('"cb" argument must be a function');
- }
-
- assertOffset(offset, buf.length);
- assertSize(size, offset, buf.length);
-
- return binding.randomFill(buf, offset, size, cb);
-}
-exports.randomFill = randomFill;
-
-function assertOffset(offset, length) {
- if (typeof offset !== 'number' || offset !== offset) {
- throw new TypeError('offset must be a number');
- }
-
- if (offset > kMaxUint32 || offset < 0) {
- throw new TypeError('offset must be a uint32');
- }
-
- if (offset > kBufferMaxLength || offset > length) {
- throw new RangeError('offset out of range');
- }
-}
-
-function assertSize(size, offset, length) {
- if (typeof size !== 'number' || size !== size) {
- throw new TypeError('size must be a number');
- }
-
- if (size > kMaxUint32 || size < 0) {
- throw new TypeError('size must be a uint32');
- }
-
- if (size + offset > length || size > kBufferMaxLength) {
- throw new RangeError('buffer too small');
+ // Legacy API
+ createCredentials: {
+ configurable: true,
+ enumerable: true,
+ get: deprecate(() => {
+ return require('tls').createSecureContext;
+ }, 'crypto.createCredentials is deprecated. ' +
+ 'Use tls.createSecureContext instead.', 'DEP0010')
+ },
+ Credentials: {
+ configurable: true,
+ enumerable: true,
+ get: deprecate(function() {
+ return require('tls').SecureContext;
+ }, 'crypto.Credentials is deprecated. ' +
+ 'Use tls.SecureContext instead.', 'DEP0011')
}
-}
-
-exports.randomBytes = exports.pseudoRandomBytes = randomBytes;
-
-exports.rng = exports.prng = randomBytes;
-
-exports.getCiphers = internalUtil.cachedResult(
- () => internalUtil.filterDuplicateStrings(getCiphers())
-);
-
-exports.getHashes = internalUtil.cachedResult(
- () => internalUtil.filterDuplicateStrings(getHashes())
-);
-
-exports.getCurves = internalUtil.cachedResult(
- () => internalUtil.filterDuplicateStrings(getCurves())
-);
-
-Object.defineProperty(exports, 'fips', {
- get: getFipsCrypto,
- set: setFipsCrypto
-});
-
-exports.timingSafeEqual = timingSafeEqual;
-
-// Legacy API
-Object.defineProperty(exports, 'createCredentials', {
- configurable: true,
- enumerable: true,
- get: internalUtil.deprecate(function() {
- return require('tls').createSecureContext;
- }, 'crypto.createCredentials is deprecated. ' +
- 'Use tls.createSecureContext instead.', 'DEP0010')
-});
-
-Object.defineProperty(exports, 'Credentials', {
- configurable: true,
- enumerable: true,
- get: internalUtil.deprecate(function() {
- return require('tls').SecureContext;
- }, 'crypto.Credentials is deprecated. ' +
- 'Use tls.SecureContext instead.', 'DEP0011')
});
diff --git a/lib/internal/crypto/certificate.js b/lib/internal/crypto/certificate.js
new file mode 100644
index 0000000000..e37bedd2f9
--- /dev/null
+++ b/lib/internal/crypto/certificate.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const {
+ certExportChallenge,
+ certExportPublicKey,
+ certVerifySpkac
+} = process.binding('crypto');
+
+const {
+ toBuf
+} = require('internal/crypto/util');
+
+function verifySpkac(object) {
+ return certVerifySpkac(object);
+}
+
+function exportPublicKey(object, encoding) {
+ return certExportPublicKey(toBuf(object, encoding));
+}
+
+function exportChallenge(object, encoding) {
+ return certExportChallenge(toBuf(object, encoding));
+}
+
+// For backwards compatibility reasons, this cannot be converted into a
+// ES6 Class.
+function Certificate() {
+ if (!(this instanceof Certificate))
+ return new Certificate();
+}
+
+Certificate.prototype.verifySpkac = verifySpkac;
+Certificate.prototype.exportPublicKey = exportPublicKey;
+Certificate.prototype.exportChallenge = exportChallenge;
+
+Certificate.exportChallenge = exportChallenge;
+Certificate.exportPublicKey = exportPublicKey;
+Certificate.verifySpkac = verifySpkac;
+
+module.exports = Certificate;
diff --git a/lib/internal/crypto/cipher.js b/lib/internal/crypto/cipher.js
new file mode 100644
index 0000000000..d9b31674c1
--- /dev/null
+++ b/lib/internal/crypto/cipher.js
@@ -0,0 +1,214 @@
+'use strict';
+
+const {
+ RSA_PKCS1_OAEP_PADDING,
+ RSA_PKCS1_PADDING
+} = process.binding('constants').crypto;
+
+const {
+ getDefaultEncoding,
+ toBuf
+} = require('internal/crypto/util');
+
+const {
+ CipherBase,
+ privateDecrypt: _privateDecrypt,
+ privateEncrypt: _privateEncrypt,
+ publicDecrypt: _publicDecrypt,
+ publicEncrypt: _publicEncrypt
+} = process.binding('crypto');
+
+const assert = require('assert');
+const LazyTransform = require('internal/streams/lazy_transform');
+const { StringDecoder } = require('string_decoder');
+
+const { inherits } = require('util');
+const { normalizeEncoding } = require('internal/util');
+
+function rsaPublic(method, defaultPadding) {
+ return function(options, buffer) {
+ const key = options.key || options;
+ const padding = options.padding || defaultPadding;
+ const passphrase = options.passphrase || null;
+ return method(toBuf(key), buffer, padding, passphrase);
+ };
+}
+
+function rsaPrivate(method, defaultPadding) {
+ return function(options, buffer) {
+ const key = options.key || options;
+ const passphrase = options.passphrase || null;
+ const padding = options.padding || defaultPadding;
+ return method(toBuf(key), buffer, padding, passphrase);
+ };
+}
+
+const publicEncrypt = rsaPublic(_publicEncrypt, RSA_PKCS1_OAEP_PADDING);
+const publicDecrypt = rsaPublic(_publicDecrypt, RSA_PKCS1_PADDING);
+const privateEncrypt = rsaPrivate(_privateEncrypt, RSA_PKCS1_PADDING);
+const privateDecrypt = rsaPrivate(_privateDecrypt, RSA_PKCS1_OAEP_PADDING);
+
+function getDecoder(decoder, encoding) {
+ encoding = normalizeEncoding(encoding);
+ decoder = decoder || new StringDecoder(encoding);
+ assert(decoder.encoding === encoding, 'Cannot change encoding');
+ return decoder;
+}
+
+function Cipher(cipher, password, options) {
+ if (!(this instanceof Cipher))
+ return new Cipher(cipher, password, options);
+ this._handle = new CipherBase(true);
+
+ this._handle.init(cipher, toBuf(password));
+ this._decoder = null;
+
+ LazyTransform.call(this, options);
+}
+
+inherits(Cipher, LazyTransform);
+
+Cipher.prototype._transform = function _transform(chunk, encoding, callback) {
+ this.push(this._handle.update(chunk, encoding));
+ callback();
+};
+
+Cipher.prototype._flush = function _flush(callback) {
+ try {
+ this.push(this._handle.final());
+ } catch (e) {
+ callback(e);
+ return;
+ }
+ callback();
+};
+
+Cipher.prototype.update = function update(data, inputEncoding, outputEncoding) {
+ const encoding = getDefaultEncoding();
+ inputEncoding = inputEncoding || encoding;
+ outputEncoding = outputEncoding || encoding;
+
+ var ret = this._handle.update(data, inputEncoding);
+
+ if (outputEncoding && outputEncoding !== 'buffer') {
+ this._decoder = getDecoder(this._decoder, outputEncoding);
+ ret = this._decoder.write(ret);
+ }
+
+ return ret;
+};
+
+
+Cipher.prototype.final = function final(outputEncoding) {
+ outputEncoding = outputEncoding || getDefaultEncoding();
+ var ret = this._handle.final();
+
+ if (outputEncoding && outputEncoding !== 'buffer') {
+ this._decoder = getDecoder(this._decoder, outputEncoding);
+ ret = this._decoder.end(ret);
+ }
+
+ return ret;
+};
+
+
+Cipher.prototype.setAutoPadding = function setAutoPadding(ap) {
+ this._handle.setAutoPadding(ap);
+ return this;
+};
+
+Cipher.prototype.getAuthTag = function getAuthTag() {
+ return this._handle.getAuthTag();
+};
+
+
+Cipher.prototype.setAuthTag = function setAuthTag(tagbuf) {
+ this._handle.setAuthTag(tagbuf);
+ return this;
+};
+
+Cipher.prototype.setAAD = function setAAD(aadbuf) {
+ this._handle.setAAD(aadbuf);
+ return this;
+};
+
+function Cipheriv(cipher, key, iv, options) {
+ if (!(this instanceof Cipheriv))
+ return new Cipheriv(cipher, key, iv, options);
+ this._handle = new CipherBase(true);
+ this._handle.initiv(cipher, toBuf(key), toBuf(iv));
+ this._decoder = null;
+
+ LazyTransform.call(this, options);
+}
+
+inherits(Cipheriv, LazyTransform);
+
+Cipheriv.prototype._transform = Cipher.prototype._transform;
+Cipheriv.prototype._flush = Cipher.prototype._flush;
+Cipheriv.prototype.update = Cipher.prototype.update;
+Cipheriv.prototype.final = Cipher.prototype.final;
+Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
+Cipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
+Cipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
+Cipheriv.prototype.setAAD = Cipher.prototype.setAAD;
+
+
+function Decipher(cipher, password, options) {
+ if (!(this instanceof Decipher))
+ return new Decipher(cipher, password, options);
+
+ this._handle = new CipherBase(false);
+ this._handle.init(cipher, toBuf(password));
+ this._decoder = null;
+
+ LazyTransform.call(this, options);
+}
+
+inherits(Decipher, LazyTransform);
+
+Decipher.prototype._transform = Cipher.prototype._transform;
+Decipher.prototype._flush = Cipher.prototype._flush;
+Decipher.prototype.update = Cipher.prototype.update;
+Decipher.prototype.final = Cipher.prototype.final;
+Decipher.prototype.finaltol = Cipher.prototype.final;
+Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
+Decipher.prototype.getAuthTag = Cipher.prototype.getAuthTag;
+Decipher.prototype.setAuthTag = Cipher.prototype.setAuthTag;
+Decipher.prototype.setAAD = Cipher.prototype.setAAD;
+
+
+function Decipheriv(cipher, key, iv, options) {
+ if (!(this instanceof Decipheriv))
+ return new Decipheriv(cipher, key, iv, options);
+
+ this._handle = new CipherBase(false);
+ this._handle.initiv(cipher, toBuf(key), toBuf(iv));
+ this._decoder = null;
+
+ LazyTransform.call(this, options);
+}
+
+inherits(Decipheriv, LazyTransform);
+
+Decipheriv.prototype._transform = Cipher.prototype._transform;
+Decipheriv.prototype._flush = Cipher.prototype._flush;
+Decipheriv.prototype.update = Cipher.prototype.update;
+Decipheriv.prototype.final = Cipher.prototype.final;
+Decipheriv.prototype.finaltol = Cipher.prototype.final;
+Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
+Decipheriv.prototype.getAuthTag = Cipher.prototype.getAuthTag;
+Decipheriv.prototype.setAuthTag = Cipher.prototype.setAuthTag;
+Decipheriv.prototype.setAAD = Cipher.prototype.setAAD;
+
+
+module.exports = {
+ Cipher,
+ Cipheriv,
+ Decipher,
+ Decipheriv,
+ privateDecrypt,
+ privateEncrypt,
+ publicDecrypt,
+ publicEncrypt,
+};
diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js
new file mode 100644
index 0000000000..b891a0b354
--- /dev/null
+++ b/lib/internal/crypto/diffiehellman.js
@@ -0,0 +1,216 @@
+'use strict';
+
+const { Buffer } = require('buffer');
+const errors = require('internal/errors');
+const {
+ getDefaultEncoding,
+ toBuf
+} = require('internal/crypto/util');
+const {
+ DiffieHellman: _DiffieHellman,
+ DiffieHellmanGroup: _DiffieHellmanGroup,
+ ECDH: _ECDH
+} = process.binding('crypto');
+const {
+ POINT_CONVERSION_COMPRESSED,
+ POINT_CONVERSION_HYBRID,
+ POINT_CONVERSION_UNCOMPRESSED
+} = process.binding('constants').crypto;
+
+const DH_GENERATOR = 2;
+
+function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) {
+ if (!(this instanceof DiffieHellman))
+ return new DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding);
+
+ if (typeof sizeOrKey !== 'number' &&
+ typeof sizeOrKey !== 'string' &&
+ !ArrayBuffer.isView(sizeOrKey)) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'sizeOrKey',
+ ['number', 'string', 'Buffer', 'TypedArray',
+ 'DataView']);
+ }
+
+ if (keyEncoding) {
+ if (typeof keyEncoding !== 'string' ||
+ (!Buffer.isEncoding(keyEncoding) && keyEncoding !== 'buffer')) {
+ genEncoding = generator;
+ generator = keyEncoding;
+ keyEncoding = false;
+ }
+ }
+
+ const encoding = getDefaultEncoding();
+ keyEncoding = keyEncoding || encoding;
+ genEncoding = genEncoding || encoding;
+
+ if (typeof sizeOrKey !== 'number')
+ sizeOrKey = toBuf(sizeOrKey, keyEncoding);
+
+ if (!generator)
+ generator = DH_GENERATOR;
+ else if (typeof generator !== 'number')
+ generator = toBuf(generator, genEncoding);
+
+ this._handle = new _DiffieHellman(sizeOrKey, generator);
+ Object.defineProperty(this, 'verifyError', {
+ enumerable: true,
+ value: this._handle.verifyError,
+ writable: false
+ });
+}
+
+
+function DiffieHellmanGroup(name) {
+ if (!(this instanceof DiffieHellmanGroup))
+ return new DiffieHellmanGroup(name);
+ this._handle = new _DiffieHellmanGroup(name);
+ Object.defineProperty(this, 'verifyError', {
+ enumerable: true,
+ value: this._handle.verifyError,
+ writable: false
+ });
+}
+
+
+DiffieHellmanGroup.prototype.generateKeys =
+ DiffieHellman.prototype.generateKeys =
+ dhGenerateKeys;
+
+function dhGenerateKeys(encoding) {
+ var keys = this._handle.generateKeys();
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ keys = keys.toString(encoding);
+ return keys;
+}
+
+
+DiffieHellmanGroup.prototype.computeSecret =
+ DiffieHellman.prototype.computeSecret =
+ dhComputeSecret;
+
+function dhComputeSecret(key, inEnc, outEnc) {
+ const encoding = getDefaultEncoding();
+ inEnc = inEnc || encoding;
+ outEnc = outEnc || encoding;
+ var ret = this._handle.computeSecret(toBuf(key, inEnc));
+ if (outEnc && outEnc !== 'buffer')
+ ret = ret.toString(outEnc);
+ return ret;
+}
+
+
+DiffieHellmanGroup.prototype.getPrime =
+ DiffieHellman.prototype.getPrime =
+ dhGetPrime;
+
+function dhGetPrime(encoding) {
+ var prime = this._handle.getPrime();
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ prime = prime.toString(encoding);
+ return prime;
+}
+
+
+DiffieHellmanGroup.prototype.getGenerator =
+ DiffieHellman.prototype.getGenerator =
+ dhGetGenerator;
+
+function dhGetGenerator(encoding) {
+ var generator = this._handle.getGenerator();
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ generator = generator.toString(encoding);
+ return generator;
+}
+
+
+DiffieHellmanGroup.prototype.getPublicKey =
+ DiffieHellman.prototype.getPublicKey =
+ dhGetPublicKey;
+
+function dhGetPublicKey(encoding) {
+ var key = this._handle.getPublicKey();
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ key = key.toString(encoding);
+ return key;
+}
+
+
+DiffieHellmanGroup.prototype.getPrivateKey =
+ DiffieHellman.prototype.getPrivateKey =
+ dhGetPrivateKey;
+
+function dhGetPrivateKey(encoding) {
+ var key = this._handle.getPrivateKey();
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ key = key.toString(encoding);
+ return key;
+}
+
+
+DiffieHellman.prototype.setPublicKey = function setPublicKey(key, encoding) {
+ encoding = encoding || getDefaultEncoding();
+ this._handle.setPublicKey(toBuf(key, encoding));
+ return this;
+};
+
+
+DiffieHellman.prototype.setPrivateKey = function setPrivateKey(key, encoding) {
+ encoding = encoding || getDefaultEncoding();
+ this._handle.setPrivateKey(toBuf(key, encoding));
+ return this;
+};
+
+
+function ECDH(curve) {
+ if (typeof curve !== 'string')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'curve', 'string');
+
+ this._handle = new _ECDH(curve);
+}
+
+ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret;
+ECDH.prototype.setPrivateKey = DiffieHellman.prototype.setPrivateKey;
+ECDH.prototype.setPublicKey = DiffieHellman.prototype.setPublicKey;
+ECDH.prototype.getPrivateKey = DiffieHellman.prototype.getPrivateKey;
+
+ECDH.prototype.generateKeys = function generateKeys(encoding, format) {
+ this._handle.generateKeys();
+
+ return this.getPublicKey(encoding, format);
+};
+
+ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) {
+ var f;
+ if (format) {
+ if (typeof format === 'number')
+ f = format;
+ if (format === 'compressed')
+ f = POINT_CONVERSION_COMPRESSED;
+ else if (format === 'hybrid')
+ f = POINT_CONVERSION_HYBRID;
+ // Default
+ else if (format === 'uncompressed')
+ f = POINT_CONVERSION_UNCOMPRESSED;
+ else
+ throw new errors.TypeError('ERR_CRYPTO_ECDH_INVALID_FORMAT', format);
+ } else {
+ f = POINT_CONVERSION_UNCOMPRESSED;
+ }
+ var key = this._handle.getPublicKey(f);
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ key = key.toString(encoding);
+ return key;
+};
+
+module.exports = {
+ DiffieHellman,
+ DiffieHellmanGroup,
+ ECDH
+};
diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js
new file mode 100644
index 0000000000..12b3e1e78e
--- /dev/null
+++ b/lib/internal/crypto/hash.js
@@ -0,0 +1,125 @@
+'use strict';
+
+const {
+ Hash: _Hash,
+ Hmac: _Hmac
+} = process.binding('crypto');
+
+const {
+ getDefaultEncoding,
+ toBuf
+} = require('internal/crypto/util');
+
+const {
+ isArrayBufferView
+} = process.binding('util');
+
+const { Buffer } = require('buffer');
+
+const errors = require('internal/errors');
+const { inherits } = require('util');
+const { normalizeEncoding } = require('internal/util');
+const LazyTransform = require('internal/streams/lazy_transform');
+const kState = Symbol('state');
+const kFinalized = Symbol('finalized');
+
+function Hash(algorithm, options) {
+ if (!(this instanceof Hash))
+ return new Hash(algorithm, options);
+ if (typeof algorithm !== 'string')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'algorithm', 'string');
+ this._handle = new _Hash(algorithm);
+ this[kState] = {
+ [kFinalized]: false
+ };
+ LazyTransform.call(this, options);
+}
+
+inherits(Hash, LazyTransform);
+
+Hash.prototype._transform = function _transform(chunk, encoding, callback) {
+ this._handle.update(chunk, encoding);
+ callback();
+};
+
+Hash.prototype._flush = function _flush(callback) {
+ this.push(this._handle.digest());
+ callback();
+};
+
+Hash.prototype.update = function update(data, encoding) {
+ const state = this[kState];
+ if (state[kFinalized])
+ throw new errors.Error('ERR_CRYPTO_HASH_FINALIZED');
+
+ if (typeof data !== 'string' && !isArrayBufferView(data)) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'data',
+ ['string', 'TypedArray', 'DataView']);
+ }
+
+ if (!this._handle.update(data, encoding || getDefaultEncoding()))
+ throw new errors.Error('ERR_CRYPTO_HASH_UPDATE_FAILED');
+ return this;
+};
+
+
+Hash.prototype.digest = function digest(outputEncoding) {
+ const state = this[kState];
+ if (state[kFinalized])
+ throw new errors.Error('ERR_CRYPTO_HASH_FINALIZED');
+ outputEncoding = outputEncoding || getDefaultEncoding();
+ if (normalizeEncoding(outputEncoding) === 'utf16le')
+ throw new errors.Error('ERR_CRYPTO_HASH_DIGEST_NO_UTF16');
+
+ // Explicit conversion for backward compatibility.
+ const ret = this._handle.digest(`${outputEncoding}`);
+ state[kFinalized] = true;
+ return ret;
+};
+
+
+function Hmac(hmac, key, options) {
+ if (!(this instanceof Hmac))
+ return new Hmac(hmac, key, options);
+ if (typeof hmac !== 'string')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'hmac', 'string');
+ if (typeof key !== 'string' && !isArrayBufferView(key)) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'key',
+ ['string', 'TypedArray', 'DataView']);
+ }
+ this._handle = new _Hmac();
+ this._handle.init(hmac, toBuf(key));
+ this[kState] = {
+ [kFinalized]: false
+ };
+ LazyTransform.call(this, options);
+}
+
+inherits(Hmac, LazyTransform);
+
+Hmac.prototype.update = Hash.prototype.update;
+
+Hmac.prototype.digest = function digest(outputEncoding) {
+ const state = this[kState];
+ outputEncoding = outputEncoding || getDefaultEncoding();
+ if (normalizeEncoding(outputEncoding) === 'utf16le')
+ throw new errors.Error('ERR_CRYPTO_HASH_DIGEST_NO_UTF16');
+
+ if (state[kFinalized]) {
+ const buf = Buffer.from('');
+ return outputEncoding === 'buffer' ? buf : buf.toString(outputEncoding);
+ }
+
+ // Explicit conversion for backward compatibility.
+ const ret = this._handle.digest(`${outputEncoding}`);
+ state[kFinalized] = true;
+ return ret;
+};
+
+Hmac.prototype._flush = Hash.prototype._flush;
+Hmac.prototype._transform = Hash.prototype._transform;
+
+module.exports = {
+ Hash,
+ Hmac
+};
diff --git a/lib/internal/crypto/pbkdf2.js b/lib/internal/crypto/pbkdf2.js
new file mode 100644
index 0000000000..5398321ece
--- /dev/null
+++ b/lib/internal/crypto/pbkdf2.js
@@ -0,0 +1,59 @@
+'use strict';
+
+const errors = require('internal/errors');
+const {
+ getDefaultEncoding,
+ toBuf
+} = require('internal/crypto/util');
+const {
+ PBKDF2
+} = process.binding('crypto');
+
+function pbkdf2(password, salt, iterations, keylen, digest, callback) {
+ if (typeof digest === 'function') {
+ callback = digest;
+ digest = undefined;
+ }
+
+ if (typeof callback !== 'function')
+ throw new errors.TypeError('ERR_INVALID_CALLBACK');
+
+ return _pbkdf2(password, salt, iterations, keylen, digest, callback);
+}
+
+function pbkdf2Sync(password, salt, iterations, keylen, digest) {
+ return _pbkdf2(password, salt, iterations, keylen, digest);
+}
+
+function _pbkdf2(password, salt, iterations, keylen, digest, callback) {
+
+ if (digest !== null && typeof digest !== 'string')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'digest',
+ ['string', 'null']);
+
+ password = toBuf(password);
+ salt = toBuf(salt);
+
+ const encoding = getDefaultEncoding();
+
+ if (encoding === 'buffer')
+ return PBKDF2(password, salt, iterations, keylen, digest, callback);
+
+ // at this point, we need to handle encodings.
+ if (callback) {
+ function next(er, ret) {
+ if (ret)
+ ret = ret.toString(encoding);
+ callback(er, ret);
+ }
+ PBKDF2(password, salt, iterations, keylen, digest, next);
+ } else {
+ var ret = PBKDF2(password, salt, iterations, keylen, digest);
+ return ret.toString(encoding);
+ }
+}
+
+module.exports = {
+ pbkdf2,
+ pbkdf2Sync
+};
diff --git a/lib/internal/crypto/random.js b/lib/internal/crypto/random.js
new file mode 100644
index 0000000000..81025289d5
--- /dev/null
+++ b/lib/internal/crypto/random.js
@@ -0,0 +1,98 @@
+'use strict';
+
+const errors = require('internal/errors');
+const { isArrayBufferView } = process.binding('util');
+const {
+ randomBytes,
+ randomFill: _randomFill
+} = process.binding('crypto');
+
+const { kMaxLength } = require('buffer');
+const kMaxUint32 = Math.pow(2, 32) - 1;
+
+function assertOffset(offset, length) {
+ if (typeof offset !== 'number' || offset !== offset) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'offset', 'number');
+ }
+
+ if (offset > kMaxUint32 || offset < 0) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'offset', 'uint32');
+ }
+
+ if (offset > kMaxLength || offset > length) {
+ throw new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');
+ }
+}
+
+function assertSize(size, offset, length) {
+ if (typeof size !== 'number' || size !== size) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'size', 'number');
+ }
+
+ if (size > kMaxUint32 || size < 0) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'size', 'uint32');
+ }
+
+ if (size + offset > length || size > kMaxLength) {
+ throw new errors.RangeError('ERR_OUT_OF_RANGE', 'size');
+ }
+}
+
+function randomFillSync(buf, offset = 0, size) {
+ if (!isArrayBufferView(buf)) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'buf', 'ArrayBufferView');
+ }
+
+ const elementSize = buf.BYTES_PER_ELEMENT || 1;
+
+ offset *= elementSize;
+ assertOffset(offset, buf.byteLength);
+
+ if (size === undefined) {
+ size = buf.byteLength - offset;
+ } else {
+ size *= elementSize;
+ }
+
+ assertSize(size, offset, buf.byteLength);
+
+ return _randomFill(buf, offset, size);
+}
+
+function randomFill(buf, offset, size, cb) {
+ if (!isArrayBufferView(buf)) {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'buf', 'ArrayBufferView');
+ }
+
+ const elementSize = buf.BYTES_PER_ELEMENT || 1;
+
+ if (typeof offset === 'function') {
+ cb = offset;
+ offset = 0;
+ size = buf.bytesLength;
+ } else if (typeof size === 'function') {
+ cb = size;
+ offset *= elementSize;
+ size = buf.byteLength - offset;
+ } else if (typeof cb !== 'function') {
+ throw new errors.TypeError('ERR_INVALID_CALLBACK');
+ }
+ if (size === undefined) {
+ size = buf.byteLength - offset;
+ } else {
+ size *= elementSize;
+ }
+
+ assertOffset(offset, buf.byteLength);
+ assertSize(size, offset, buf.byteLength);
+
+ return _randomFill(buf, offset, size, cb);
+}
+
+module.exports = {
+ randomBytes,
+ randomFill,
+ randomFillSync
+};
diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js
new file mode 100644
index 0000000000..52827c9c4b
--- /dev/null
+++ b/lib/internal/crypto/sig.js
@@ -0,0 +1,131 @@
+'use strict';
+
+const errors = require('internal/errors');
+const {
+ Sign: _Sign,
+ Verify: _Verify
+} = process.binding('crypto');
+const {
+ RSA_PSS_SALTLEN_AUTO,
+ RSA_PKCS1_PADDING
+} = process.binding('constants').crypto;
+const {
+ getDefaultEncoding,
+ toBuf
+} = require('internal/crypto/util');
+const { Writable } = require('stream');
+const { inherits } = require('util');
+
+function Sign(algorithm, options) {
+ if (!(this instanceof Sign))
+ return new Sign(algorithm, options);
+ this._handle = new _Sign();
+ this._handle.init(algorithm);
+
+ Writable.call(this, options);
+}
+
+inherits(Sign, Writable);
+
+Sign.prototype._write = function _write(chunk, encoding, callback) {
+ this._handle.update(chunk, encoding);
+ callback();
+};
+
+Sign.prototype.update = function update(data, encoding) {
+ encoding = encoding || getDefaultEncoding();
+ this._handle.update(data, encoding);
+ return this;
+};
+
+Sign.prototype.sign = function sign(options, encoding) {
+ if (!options)
+ throw new errors.Error('ERR_CRYPTO_SIGN_KEY_REQUIRED');
+
+ var key = options.key || options;
+ var passphrase = options.passphrase || null;
+
+ // Options specific to RSA
+ var rsaPadding = RSA_PKCS1_PADDING;
+ if (options.hasOwnProperty('padding')) {
+ if (options.padding === options.padding >> 0) {
+ rsaPadding = options.padding;
+ } else {
+ throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
+ 'padding',
+ options.padding);
+ }
+ }
+
+ var pssSaltLength = RSA_PSS_SALTLEN_AUTO;
+ if (options.hasOwnProperty('saltLength')) {
+ if (options.saltLength === options.saltLength >> 0) {
+ pssSaltLength = options.saltLength;
+ } else {
+ throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
+ 'saltLength',
+ options.saltLength);
+ }
+ }
+
+ var ret = this._handle.sign(toBuf(key), passphrase, rsaPadding,
+ pssSaltLength);
+
+ encoding = encoding || getDefaultEncoding();
+ if (encoding && encoding !== 'buffer')
+ ret = ret.toString(encoding);
+
+ return ret;
+};
+
+
+function Verify(algorithm, options) {
+ if (!(this instanceof Verify))
+ return new Verify(algorithm, options);
+
+ this._handle = new _Verify();
+ this._handle.init(algorithm);
+
+ Writable.call(this, options);
+}
+
+inherits(Verify, Writable);
+
+Verify.prototype._write = Sign.prototype._write;
+Verify.prototype.update = Sign.prototype.update;
+
+Verify.prototype.verify = function verify(options, signature, sigEncoding) {
+ var key = options.key || options;
+ sigEncoding = sigEncoding || getDefaultEncoding();
+
+ // Options specific to RSA
+ var rsaPadding = RSA_PKCS1_PADDING;
+ if (options.hasOwnProperty('padding')) {
+ if (options.padding === options.padding >> 0) {
+ rsaPadding = options.padding;
+ } else {
+ throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
+ 'padding',
+ options.padding);
+ }
+ }
+
+ var pssSaltLength = RSA_PSS_SALTLEN_AUTO;
+ if (options.hasOwnProperty('saltLength')) {
+ if (options.saltLength === options.saltLength >> 0) {
+ pssSaltLength = options.saltLength;
+ } else {
+ throw new errors.TypeError('ERR_INVALID_OPT_VALUE',
+ 'saltLength',
+ options.saltLength);
+ }
+ }
+
+ return this._handle.verify(toBuf(key), toBuf(signature, sigEncoding),
+ rsaPadding, pssSaltLength);
+};
+
+module.exports = {
+ Sign,
+ Verify
+};
diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js
new file mode 100644
index 0000000000..9e242dc917
--- /dev/null
+++ b/lib/internal/crypto/util.js
@@ -0,0 +1,70 @@
+'use strict';
+
+const {
+ getCiphers: _getCiphers,
+ getCurves: _getCurves,
+ getHashes: _getHashes,
+ setEngine: _setEngine
+} = process.binding('crypto');
+
+const {
+ ENGINE_METHOD_ALL
+} = process.binding('constants').crypto;
+
+const errors = require('internal/errors');
+const { Buffer } = require('buffer');
+const {
+ cachedResult,
+ filterDuplicateStrings
+} = require('internal/util');
+
+var defaultEncoding = 'buffer';
+
+function setDefaultEncoding(val) {
+ defaultEncoding = val;
+}
+
+function getDefaultEncoding() {
+ return defaultEncoding;
+}
+
+// This is here because many functions accepted binary strings without
+// any explicit encoding in older versions of node, and we don't want
+// to break them unnecessarily.
+function toBuf(str, encoding) {
+ if (typeof str === 'string') {
+ if (encoding === 'buffer' || !encoding)
+ encoding = 'utf8';
+ return Buffer.from(str, encoding);
+ }
+ return str;
+}
+
+const getCiphers = cachedResult(() => filterDuplicateStrings(_getCiphers()));
+const getHashes = cachedResult(() => filterDuplicateStrings(_getHashes()));
+const getCurves = cachedResult(() => filterDuplicateStrings(_getCurves()));
+
+function setEngine(id, flags) {
+ if (typeof id !== 'string')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'id', 'string');
+
+ if (flags && typeof flags !== 'number')
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'flags', 'number');
+ flags = flags >>> 0;
+
+ // Use provided engine for everything by default
+ if (flags === 0)
+ flags = ENGINE_METHOD_ALL;
+
+ return _setEngine(id, flags);
+}
+
+module.exports = {
+ getCiphers,
+ getCurves,
+ getDefaultEncoding,
+ getHashes,
+ setDefaultEncoding,
+ setEngine,
+ toBuf
+};
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 7f72e7a0e5..261378e2b1 100755
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -125,6 +125,11 @@ E('ERR_CHILD_CLOSED_BEFORE_REPLY', 'Child closed before reply received');
E('ERR_CONSOLE_WRITABLE_STREAM',
'Console expects a writable stream instance for %s');
E('ERR_CPU_USAGE', 'Unable to obtain cpu usage %s');
+E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s');
+E('ERR_CRYPTO_HASH_DIGEST_NO_UTF16', 'hash.digest() does not support UTF-16');
+E('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called');
+E('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed');
+E('ERR_CRYPTO_SIGN_KEY_REQUIRED', 'No key provided to sign');
E('ERR_DNS_SET_SERVERS_FAILED', (err, servers) =>
`c-ares failed to set servers: "${err}" [${servers}]`);
E('ERR_ENCODING_INVALID_ENCODED_DATA',
@@ -253,6 +258,7 @@ E('ERR_NAPI_CONS_PROTOTYPE_OBJECT', 'Constructor.prototype must be an object');
E('ERR_NO_CRYPTO', 'Node.js is not compiled with OpenSSL crypto support');
E('ERR_NO_ICU', '%s is not supported on Node.js compiled without ICU');
E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported');
+E('ERR_OUT_OF_RANGE', 'The "%s" argument is out of range');
E('ERR_OUTOFMEMORY', 'Out of memory');
E('ERR_PARSE_HISTORY_DATA', 'Could not parse history data in %s');
E('ERR_REQUIRE_ESM', 'Must use import to load ES Module: %s');