mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
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>
This commit is contained in:
parent
8fa5fcc0ba
commit
c75f87cc4c
@ -48,7 +48,60 @@ The `crypto` module provides the `Certificate` class for working with SPKAC
|
||||
data. The most common usage is handling output generated by the HTML5
|
||||
`<keygen>` element. Node.js uses [OpenSSL's SPKAC implementation][] internally.
|
||||
|
||||
### new crypto.Certificate()
|
||||
### Certificate.exportChallenge(spkac)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
- `spkac` {string | Buffer | TypedArray | DataView}
|
||||
- Returns {Buffer} The challenge component of the `spkac` data structure, which
|
||||
includes a public key and a challenge.
|
||||
|
||||
```js
|
||||
const { Certificate } = require('crypto');
|
||||
const spkac = getSpkacSomehow();
|
||||
const challenge = Certificate.exportChallenge(spkac);
|
||||
console.log(challenge.toString('utf8'));
|
||||
// Prints: the challenge as a UTF8 string
|
||||
```
|
||||
|
||||
### Certificate.exportPublicKey(spkac)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
- `spkac` {string | Buffer | TypedArray | DataView}
|
||||
- Returns {Buffer} The public key component of the `spkac` data structure,
|
||||
which includes a public key and a challenge.
|
||||
|
||||
```js
|
||||
const { Certificate } = require('crypto');
|
||||
const spkac = getSpkacSomehow();
|
||||
const publicKey = Certificate.exportPublicKey(spkac);
|
||||
console.log(publicKey);
|
||||
// Prints: the public key as <Buffer ...>
|
||||
```
|
||||
|
||||
### Certificate.verifySpkac(spkac)
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
- `spkac` {Buffer | TypedArray | DataView}
|
||||
- Returns {boolean} `true` if the given `spkac` data structure is valid, `false`
|
||||
otherwise.
|
||||
|
||||
```js
|
||||
const { Certificate } = require('crypto');
|
||||
const spkac = getSpkacSomehow();
|
||||
console.log(Certificate.verifySpkac(Buffer.from(spkac)));
|
||||
// Prints: true or false
|
||||
```
|
||||
|
||||
### Legacy API
|
||||
|
||||
As a still supported legacy interface, it is possible (but not recommended) to
|
||||
create new instances of the `crypto.Certificate` class as illustrated in the
|
||||
examples below.
|
||||
|
||||
#### new crypto.Certificate()
|
||||
|
||||
Instances of the `Certificate` class can be created using the `new` keyword
|
||||
or by calling `crypto.Certificate()` as a function:
|
||||
@ -60,7 +113,7 @@ const cert1 = new crypto.Certificate();
|
||||
const cert2 = crypto.Certificate();
|
||||
```
|
||||
|
||||
### certificate.exportChallenge(spkac)
|
||||
#### certificate.exportChallenge(spkac)
|
||||
<!-- YAML
|
||||
added: v0.11.8
|
||||
-->
|
||||
@ -76,7 +129,7 @@ console.log(challenge.toString('utf8'));
|
||||
// Prints: the challenge as a UTF8 string
|
||||
```
|
||||
|
||||
### certificate.exportPublicKey(spkac)
|
||||
#### certificate.exportPublicKey(spkac)
|
||||
<!-- YAML
|
||||
added: v0.11.8
|
||||
-->
|
||||
@ -92,7 +145,7 @@ console.log(publicKey);
|
||||
// Prints: the public key as <Buffer ...>
|
||||
```
|
||||
|
||||
### certificate.verifySpkac(spkac)
|
||||
#### certificate.verifySpkac(spkac)
|
||||
<!-- YAML
|
||||
added: v0.11.8
|
||||
-->
|
||||
@ -1747,9 +1800,13 @@ negative performance implications for some applications, see the
|
||||
### crypto.randomFillSync(buffer[, offset][, size])
|
||||
<!-- YAML
|
||||
added: v7.10.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/15231
|
||||
description: The `buffer` argument may be any ArrayBufferView
|
||||
-->
|
||||
|
||||
* `buffer` {Buffer|Uint8Array} Must be supplied.
|
||||
* `buffer` {Buffer|Uint8Array|ArrayBufferView} Must be supplied.
|
||||
* `offset` {number} Defaults to `0`.
|
||||
* `size` {number} Defaults to `buffer.length - offset`.
|
||||
|
||||
@ -1769,12 +1826,29 @@ crypto.randomFillSync(buf, 5, 5);
|
||||
console.log(buf.toString('hex'));
|
||||
```
|
||||
|
||||
Any `TypedArray` or `DataView` instance may be passed as `buffer`.
|
||||
|
||||
```js
|
||||
const a = new Uint32Array(10);
|
||||
console.log(crypto.randomFillSync(a).toString('hex'));
|
||||
|
||||
const b = new Float64Array(10);
|
||||
console.log(crypto.randomFillSync(a).toString('hex'));
|
||||
|
||||
const c = new DataView(new ArrayBuffer(10));
|
||||
console.log(crypto.randomFillSync(a).toString('hex'));
|
||||
```
|
||||
|
||||
### crypto.randomFill(buffer[, offset][, size], callback)
|
||||
<!-- YAML
|
||||
added: v7.10.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/15231
|
||||
description: The `buffer` argument may be any ArrayBufferView
|
||||
-->
|
||||
|
||||
* `buffer` {Buffer|Uint8Array} Must be supplied.
|
||||
* `buffer` {Buffer|Uint8Array|ArrayBufferView} Must be supplied.
|
||||
* `offset` {number} Defaults to `0`.
|
||||
* `size` {number} Defaults to `buffer.length - offset`.
|
||||
* `callback` {Function} `function(err, buf) {}`.
|
||||
@ -1804,6 +1878,28 @@ crypto.randomFill(buf, 5, 5, (err, buf) => {
|
||||
});
|
||||
```
|
||||
|
||||
Any `TypedArray` or `DataView` instance may be passed as `buffer`.
|
||||
|
||||
```js
|
||||
const a = new Uint32Array(10);
|
||||
crypto.randomFill(a, (err, buf) => {
|
||||
if (err) throw err;
|
||||
console.log(buf.toString('hex'));
|
||||
});
|
||||
|
||||
const b = new Float64Array(10);
|
||||
crypto.randomFill(b, (err, buf) => {
|
||||
if (err) throw err;
|
||||
console.log(buf.toString('hex'));
|
||||
});
|
||||
|
||||
const c = new DataView(new ArrayBuffer(10));
|
||||
crypto.randomFill(c, (err, buf) => {
|
||||
if (err) throw err;
|
||||
console.log(buf.toString('hex'));
|
||||
});
|
||||
```
|
||||
|
||||
Note that this API uses libuv's threadpool, which can have surprising and
|
||||
negative performance implications for some applications, see the
|
||||
[`UV_THREADPOOL_SIZE`][] documentation for more information.
|
||||
|
@ -621,6 +621,12 @@ Used when `Console` is instantiated without `stdout` stream or when `stdout` or
|
||||
|
||||
Used when the native call from `process.cpuUsage` cannot be processed properly.
|
||||
|
||||
<a id="ERR_CRYPTO_ECDH_INVALID_FORMAT"></a>
|
||||
### ERR_CRYPTO_ECDH_INVALID_FORMAT
|
||||
|
||||
Used when an invalid value for the `format` argument has been passed to the
|
||||
`crypto.ECDH()` class `getPublicKey()` method.
|
||||
|
||||
<a id="ERR_DNS_SET_SERVERS_FAILED"></a>
|
||||
### ERR_DNS_SET_SERVERS_FAILED
|
||||
|
||||
|
902
lib/crypto.js
902
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);
|
||||
};
|
||||
}
|
||||
|
||||
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', {
|
||||
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', {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
exports.Certificate = Certificate;
|
||||
|
||||
function Certificate() {
|
||||
if (!(this instanceof Certificate))
|
||||
return new Certificate();
|
||||
}
|
||||
|
||||
|
||||
Certificate.prototype.verifySpkac = function verifySpkac(object) {
|
||||
return binding.certVerifySpkac(object);
|
||||
// Classes
|
||||
Certificate,
|
||||
Cipher,
|
||||
Cipheriv,
|
||||
Decipher,
|
||||
Decipheriv,
|
||||
DiffieHellman,
|
||||
DiffieHellmanGroup,
|
||||
Hash,
|
||||
Hmac,
|
||||
Sign,
|
||||
Verify
|
||||
};
|
||||
|
||||
Object.defineProperties(exports, {
|
||||
fips: {
|
||||
get: getFipsCrypto,
|
||||
set: setFipsCrypto
|
||||
},
|
||||
DEFAULT_ENCODING: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: getDefaultEncoding,
|
||||
set: setDefaultEncoding
|
||||
},
|
||||
constants: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: constants
|
||||
},
|
||||
|
||||
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');
|
||||
// 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')
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
});
|
||||
|
40
lib/internal/crypto/certificate.js
Normal file
40
lib/internal/crypto/certificate.js
Normal file
@ -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;
|
214
lib/internal/crypto/cipher.js
Normal file
214
lib/internal/crypto/cipher.js
Normal file
@ -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,
|
||||
};
|
216
lib/internal/crypto/diffiehellman.js
Normal file
216
lib/internal/crypto/diffiehellman.js
Normal file
@ -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
|
||||
};
|
125
lib/internal/crypto/hash.js
Normal file
125
lib/internal/crypto/hash.js
Normal file
@ -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
|
||||
};
|
59
lib/internal/crypto/pbkdf2.js
Normal file
59
lib/internal/crypto/pbkdf2.js
Normal file
@ -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
|
||||
};
|
98
lib/internal/crypto/random.js
Normal file
98
lib/internal/crypto/random.js
Normal file
@ -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
|
||||
};
|
131
lib/internal/crypto/sig.js
Normal file
131
lib/internal/crypto/sig.js
Normal file
@ -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
|
||||
};
|
70
lib/internal/crypto/util.js
Normal file
70
lib/internal/crypto/util.js
Normal file
@ -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
|
||||
};
|
@ -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');
|
||||
|
8
node.gyp
8
node.gyp
@ -84,6 +84,14 @@
|
||||
'lib/internal/cluster/shared_handle.js',
|
||||
'lib/internal/cluster/utils.js',
|
||||
'lib/internal/cluster/worker.js',
|
||||
'lib/internal/crypto/certificate.js',
|
||||
'lib/internal/crypto/cipher.js',
|
||||
'lib/internal/crypto/diffiehellman.js',
|
||||
'lib/internal/crypto/hash.js',
|
||||
'lib/internal/crypto/pbkdf2.js',
|
||||
'lib/internal/crypto/random.js',
|
||||
'lib/internal/crypto/sig.js',
|
||||
'lib/internal/crypto/util.js',
|
||||
'lib/internal/encoding.js',
|
||||
'lib/internal/errors.js',
|
||||
'lib/internal/freelist.js',
|
||||
|
@ -3699,7 +3699,6 @@ void Hmac::New(const FunctionCallbackInfo<Value>& args) {
|
||||
void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) {
|
||||
HandleScope scope(env()->isolate());
|
||||
|
||||
CHECK_EQ(initialised_, false);
|
||||
const EVP_MD* md = EVP_get_digestbyname(hash_type);
|
||||
if (md == nullptr) {
|
||||
return env()->ThrowError("Unknown message digest");
|
||||
@ -3720,13 +3719,6 @@ void Hmac::HmacInit(const FunctionCallbackInfo<Value>& args) {
|
||||
ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
|
||||
Environment* env = hmac->env();
|
||||
|
||||
if (args.Length() < 2) {
|
||||
return env->ThrowError("Hash type and key arguments are mandatory");
|
||||
}
|
||||
|
||||
THROW_AND_RETURN_IF_NOT_STRING(args[0], "Hash type");
|
||||
THROW_AND_RETURN_IF_NOT_BUFFER(args[1], "Key");
|
||||
|
||||
const node::Utf8Value hash_type(env->isolate(), args[0]);
|
||||
const char* buffer_data = Buffer::Data(args[1]);
|
||||
size_t buffer_length = Buffer::Length(args[1]);
|
||||
@ -3748,24 +3740,22 @@ void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
|
||||
Hmac* hmac;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&hmac, args.Holder());
|
||||
|
||||
THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(args[0], "Data");
|
||||
|
||||
// Only copy the data if we have to, because it's a string
|
||||
bool r;
|
||||
bool r = true;
|
||||
if (args[0]->IsString()) {
|
||||
StringBytes::InlineDecoder decoder;
|
||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8))
|
||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)) {
|
||||
args.GetReturnValue().Set(false);
|
||||
return;
|
||||
}
|
||||
r = hmac->HmacUpdate(decoder.out(), decoder.size());
|
||||
} else {
|
||||
} else if (args[0]->IsArrayBufferView()) {
|
||||
char* buf = Buffer::Data(args[0]);
|
||||
size_t buflen = Buffer::Length(args[0]);
|
||||
r = hmac->HmacUpdate(buf, buflen);
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
return env->ThrowTypeError("HmacUpdate fail");
|
||||
}
|
||||
args.GetReturnValue().Set(r);
|
||||
}
|
||||
|
||||
|
||||
@ -3777,13 +3767,9 @@ void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
enum encoding encoding = BUFFER;
|
||||
if (args.Length() >= 1) {
|
||||
CHECK(args[0]->IsString());
|
||||
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
|
||||
}
|
||||
|
||||
if (encoding == UCS2) {
|
||||
return env->ThrowError("hmac.digest() does not support UTF-16");
|
||||
}
|
||||
CHECK_NE(encoding, UCS2); // Digest does not support UTF-16
|
||||
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len = 0;
|
||||
@ -3825,10 +3811,6 @@ void Hash::Initialize(Environment* env, v8::Local<v8::Object> target) {
|
||||
void Hash::New(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (args.Length() == 0 || !args[0]->IsString()) {
|
||||
return env->ThrowError("Must give hashtype string as argument");
|
||||
}
|
||||
|
||||
const node::Utf8Value hash_type(env->isolate(), args[0]);
|
||||
|
||||
Hash* hash = new Hash(env, args.This());
|
||||
@ -3840,7 +3822,6 @@ void Hash::New(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
|
||||
bool Hash::HashInit(const char* hash_type) {
|
||||
CHECK_EQ(initialised_, false);
|
||||
const EVP_MD* md = EVP_get_digestbyname(hash_type);
|
||||
if (md == nullptr)
|
||||
return false;
|
||||
@ -3868,31 +3849,22 @@ void Hash::HashUpdate(const FunctionCallbackInfo<Value>& args) {
|
||||
Hash* hash;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&hash, args.Holder());
|
||||
|
||||
THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(args[0], "Data");
|
||||
|
||||
if (!hash->initialised_) {
|
||||
return env->ThrowError("Not initialized");
|
||||
}
|
||||
if (hash->finalized_) {
|
||||
return env->ThrowError("Digest already called");
|
||||
}
|
||||
|
||||
// Only copy the data if we have to, because it's a string
|
||||
bool r;
|
||||
bool r = true;
|
||||
if (args[0]->IsString()) {
|
||||
StringBytes::InlineDecoder decoder;
|
||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8))
|
||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)) {
|
||||
args.GetReturnValue().Set(false);
|
||||
return;
|
||||
}
|
||||
r = hash->HashUpdate(decoder.out(), decoder.size());
|
||||
} else {
|
||||
} else if (args[0]->IsArrayBufferView()) {
|
||||
char* buf = Buffer::Data(args[0]);
|
||||
size_t buflen = Buffer::Length(args[0]);
|
||||
r = hash->HashUpdate(buf, buflen);
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
return env->ThrowTypeError("HashUpdate fail");
|
||||
}
|
||||
args.GetReturnValue().Set(r);
|
||||
}
|
||||
|
||||
|
||||
@ -3902,23 +3874,11 @@ void Hash::HashDigest(const FunctionCallbackInfo<Value>& args) {
|
||||
Hash* hash;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&hash, args.Holder());
|
||||
|
||||
if (!hash->initialised_) {
|
||||
return env->ThrowError("Not initialized");
|
||||
}
|
||||
if (hash->finalized_) {
|
||||
return env->ThrowError("Digest already called");
|
||||
}
|
||||
|
||||
enum encoding encoding = BUFFER;
|
||||
if (args.Length() >= 1) {
|
||||
CHECK(args[0]->IsString());
|
||||
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
|
||||
}
|
||||
|
||||
if (encoding == UCS2) {
|
||||
return env->ThrowError("hash.digest() does not support UTF-16");
|
||||
}
|
||||
|
||||
unsigned char md_value[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len;
|
||||
|
||||
@ -5562,13 +5522,14 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> (*argv)[2]) {
|
||||
req->object()->Get(req->env()->context(),
|
||||
req->env()->buffer_string()).ToLocalChecked();
|
||||
|
||||
if (buffer->IsUint8Array()) {
|
||||
if (buffer->IsArrayBufferView()) {
|
||||
CHECK_LE(req->size(), Buffer::Length(buffer));
|
||||
char* buf = Buffer::Data(buffer);
|
||||
memcpy(buf, data, req->size());
|
||||
(*argv)[1] = buffer;
|
||||
} else {
|
||||
(*argv)[1] = Buffer::New(req->env(), data, size).ToLocalChecked();
|
||||
(*argv)[1] = Buffer::New(req->env(), data, size)
|
||||
.ToLocalChecked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5649,7 +5610,7 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
|
||||
void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
CHECK(args[0]->IsUint8Array());
|
||||
CHECK(args[0]->IsArrayBufferView());
|
||||
CHECK(args[1]->IsUint32());
|
||||
CHECK(args[2]->IsUint32());
|
||||
|
||||
|
@ -19,6 +19,7 @@ using v8::Value;
|
||||
|
||||
#define VALUE_METHOD_MAP(V) \
|
||||
V(isArrayBuffer, IsArrayBuffer) \
|
||||
V(isArrayBufferView, IsArrayBufferView) \
|
||||
V(isAsyncFunction, IsAsyncFunction) \
|
||||
V(isDataView, IsDataView) \
|
||||
V(isDate, IsDate) \
|
||||
|
@ -568,9 +568,12 @@ testCipher4(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678'));
|
||||
|
||||
|
||||
// update() should only take buffers / strings
|
||||
assert.throws(function() {
|
||||
crypto.createHash('sha1').update({ foo: 'bar' });
|
||||
}, /^TypeError: Data must be a string or a buffer$/);
|
||||
common.expectsError(
|
||||
() => crypto.createHash('sha1').update({ foo: 'bar' }),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
});
|
||||
|
||||
|
||||
// Test Diffie-Hellman with two parties sharing a secret,
|
||||
|
@ -26,6 +26,7 @@ if (!common.hasCrypto)
|
||||
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
const { Certificate } = crypto;
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
crypto.DEFAULT_ENCODING = 'buffer';
|
||||
@ -35,26 +36,47 @@ const spkacValid = fixtures.readSync('spkac.valid');
|
||||
const spkacFail = fixtures.readSync('spkac.fail');
|
||||
const spkacPem = fixtures.readSync('spkac.pem');
|
||||
|
||||
const certificate = new crypto.Certificate();
|
||||
{
|
||||
// Test instance methods
|
||||
const certificate = new Certificate();
|
||||
|
||||
assert.strictEqual(certificate.verifySpkac(spkacValid), true);
|
||||
assert.strictEqual(certificate.verifySpkac(spkacFail), false);
|
||||
assert.strictEqual(certificate.verifySpkac(spkacValid), true);
|
||||
assert.strictEqual(certificate.verifySpkac(spkacFail), false);
|
||||
|
||||
assert.strictEqual(
|
||||
stripLineEndings(certificate.exportPublicKey(spkacValid).toString('utf8')),
|
||||
stripLineEndings(spkacPem.toString('utf8'))
|
||||
);
|
||||
assert.strictEqual(certificate.exportPublicKey(spkacFail), '');
|
||||
assert.strictEqual(
|
||||
stripLineEndings(certificate.exportPublicKey(spkacValid).toString('utf8')),
|
||||
stripLineEndings(spkacPem.toString('utf8'))
|
||||
);
|
||||
assert.strictEqual(certificate.exportPublicKey(spkacFail), '');
|
||||
|
||||
assert.strictEqual(
|
||||
certificate.exportChallenge(spkacValid).toString('utf8'),
|
||||
'fb9ab814-6677-42a4-a60c-f905d1a6924d'
|
||||
);
|
||||
assert.strictEqual(certificate.exportChallenge(spkacFail), '');
|
||||
assert.strictEqual(
|
||||
certificate.exportChallenge(spkacValid).toString('utf8'),
|
||||
'fb9ab814-6677-42a4-a60c-f905d1a6924d'
|
||||
);
|
||||
assert.strictEqual(certificate.exportChallenge(spkacFail), '');
|
||||
}
|
||||
|
||||
{
|
||||
// Test static methods
|
||||
assert.strictEqual(Certificate.verifySpkac(spkacValid), true);
|
||||
assert.strictEqual(Certificate.verifySpkac(spkacFail), false);
|
||||
|
||||
assert.strictEqual(
|
||||
stripLineEndings(Certificate.exportPublicKey(spkacValid).toString('utf8')),
|
||||
stripLineEndings(spkacPem.toString('utf8'))
|
||||
);
|
||||
assert.strictEqual(Certificate.exportPublicKey(spkacFail), '');
|
||||
|
||||
assert.strictEqual(
|
||||
Certificate.exportChallenge(spkacValid).toString('utf8'),
|
||||
'fb9ab814-6677-42a4-a60c-f905d1a6924d'
|
||||
);
|
||||
assert.strictEqual(Certificate.exportChallenge(spkacFail), '');
|
||||
}
|
||||
|
||||
function stripLineEndings(obj) {
|
||||
return obj.replace(/\n/g, '');
|
||||
}
|
||||
|
||||
// direct call Certificate() should return instance
|
||||
assert(crypto.Certificate() instanceof crypto.Certificate);
|
||||
assert(Certificate() instanceof Certificate);
|
||||
|
@ -22,24 +22,22 @@ assert.strictEqual(secret2.toString('base64'), secret1);
|
||||
assert.strictEqual(dh1.verifyError, 0);
|
||||
assert.strictEqual(dh2.verifyError, 0);
|
||||
|
||||
const argumentsError =
|
||||
/^TypeError: First argument should be number, string, Buffer, TypedArray, or DataView$/;
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.createDiffieHellman([0x1, 0x2]);
|
||||
}, argumentsError);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.createDiffieHellman(() => { });
|
||||
}, argumentsError);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.createDiffieHellman(/abc/);
|
||||
}, argumentsError);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.createDiffieHellman({});
|
||||
}, argumentsError);
|
||||
[
|
||||
[0x1, 0x2],
|
||||
() => { },
|
||||
/abc/,
|
||||
{}
|
||||
].forEach((i) => {
|
||||
common.expectsError(
|
||||
() => crypto.createDiffieHellman(i),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "sizeOrKey" argument must be one of type number, string, ' +
|
||||
'Buffer, TypedArray, or DataView'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Create "another dh1" using generated keys from dh1,
|
||||
// and compute secret again
|
||||
@ -198,9 +196,14 @@ if (availableCurves.has('prime256v1') && availableCurves.has('secp256k1')) {
|
||||
firstByte = ecdh1.getPublicKey('buffer', 'hybrid')[0];
|
||||
assert(firstByte === 6 || firstByte === 7);
|
||||
// format value should be string
|
||||
assert.throws(() => {
|
||||
ecdh1.getPublicKey('buffer', 10);
|
||||
}, /^TypeError: Bad format: 10$/);
|
||||
|
||||
common.expectsError(
|
||||
() => ecdh1.getPublicKey('buffer', 10),
|
||||
{
|
||||
code: 'ERR_CRYPTO_ECDH_INVALID_FORMAT',
|
||||
type: TypeError,
|
||||
message: 'Invalid ECDH format: 10'
|
||||
});
|
||||
|
||||
// ECDH should check that point is on curve
|
||||
const ecdh3 = crypto.createECDH('secp256k1');
|
||||
@ -331,6 +334,10 @@ if (availableCurves.has('prime256v1') && availableHashes.has('sha256')) {
|
||||
}
|
||||
|
||||
// invalid test: curve argument is undefined
|
||||
assert.throws(() => {
|
||||
crypto.createECDH();
|
||||
}, /^TypeError: "curve" argument should be a string$/);
|
||||
common.expectsError(
|
||||
() => crypto.createECDH(),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "curve" argument must be of type string'
|
||||
});
|
||||
|
@ -4,13 +4,20 @@ const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
|
||||
assert.throws(function() {
|
||||
crypto.setEngine(true);
|
||||
}, /^TypeError: "id" argument should be a string$/);
|
||||
common.expectsError(
|
||||
() => crypto.setEngine(true),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "id" argument must be of type string'
|
||||
});
|
||||
|
||||
assert.throws(function() {
|
||||
crypto.setEngine('/path/to/engine', 'notANumber');
|
||||
}, /^TypeError: "flags" argument should be a number, if present$/);
|
||||
common.expectsError(
|
||||
() => crypto.setEngine('/path/to/engine', 'notANumber'),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "flags" argument must be of type number'
|
||||
});
|
||||
|
@ -105,14 +105,34 @@ assert.notStrictEqual(
|
||||
|
||||
const h3 = crypto.createHash('sha256');
|
||||
h3.digest();
|
||||
assert.throws(function() {
|
||||
h3.digest();
|
||||
}, /Digest already called/);
|
||||
|
||||
assert.throws(function() {
|
||||
h3.update('foo');
|
||||
}, /Digest already called/);
|
||||
common.expectsError(
|
||||
() => h3.digest(),
|
||||
{
|
||||
code: 'ERR_CRYPTO_HASH_FINALIZED',
|
||||
type: Error
|
||||
});
|
||||
|
||||
assert.throws(function() {
|
||||
crypto.createHash('sha256').digest('ucs2');
|
||||
}, /^Error: hash\.digest\(\) does not support UTF-16$/);
|
||||
common.expectsError(
|
||||
() => h3.update('foo'),
|
||||
{
|
||||
code: 'ERR_CRYPTO_HASH_FINALIZED',
|
||||
type: Error
|
||||
});
|
||||
|
||||
common.expectsError(
|
||||
() => crypto.createHash('sha256').digest('ucs2'),
|
||||
{
|
||||
code: 'ERR_CRYPTO_HASH_DIGEST_NO_UTF16',
|
||||
type: Error
|
||||
}
|
||||
);
|
||||
|
||||
common.expectsError(
|
||||
() => crypto.createHash(),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "algorithm" argument must be of type string'
|
||||
}
|
||||
);
|
||||
|
@ -6,19 +6,11 @@ if (!common.hasCrypto)
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
|
||||
// Test for binding layer robustness
|
||||
{
|
||||
const binding = process.binding('crypto');
|
||||
const h = new binding.Hmac();
|
||||
// Fail to init the Hmac with an algorithm.
|
||||
assert.throws(() => h.update('hello'), /^TypeError: HmacUpdate fail$/);
|
||||
}
|
||||
|
||||
// Test HMAC
|
||||
const h1 = crypto.createHmac('sha1', 'Node')
|
||||
.update('some data')
|
||||
.update('to hmac')
|
||||
.digest('hex');
|
||||
.update('some data')
|
||||
.update('to hmac')
|
||||
.digest('hex');
|
||||
assert.strictEqual(h1, '19fd6e1ba73d9ed2224dd5094a71babe85d9a892', 'test HMAC');
|
||||
|
||||
// Test HMAC (Wikipedia Test Cases)
|
||||
@ -376,9 +368,12 @@ for (let i = 0, l = rfc2202_sha1.length; i < l; i++) {
|
||||
);
|
||||
}
|
||||
|
||||
assert.throws(function() {
|
||||
crypto.createHmac('sha256', 'w00t').digest('ucs2');
|
||||
}, /^Error: hmac\.digest\(\) does not support UTF-16$/);
|
||||
common.expectsError(
|
||||
() => crypto.createHmac('sha256', 'w00t').digest('ucs2'),
|
||||
{
|
||||
code: 'ERR_CRYPTO_HASH_DIGEST_NO_UTF16',
|
||||
type: Error
|
||||
});
|
||||
|
||||
// Check initialized -> uninitialized state transition after calling digest().
|
||||
{
|
||||
|
@ -55,9 +55,13 @@ function ondone(err, key) {
|
||||
}
|
||||
|
||||
// Error path should not leak memory (check with valgrind).
|
||||
assert.throws(function() {
|
||||
crypto.pbkdf2('password', 'salt', 1, 20, null);
|
||||
}, /^Error: No callback provided to pbkdf2$/);
|
||||
common.expectsError(
|
||||
() => crypto.pbkdf2('password', 'salt', 1, 20, null),
|
||||
{
|
||||
code: 'ERR_INVALID_CALLBACK',
|
||||
type: TypeError
|
||||
}
|
||||
);
|
||||
|
||||
// Should not work with Infinity key length
|
||||
assert.throws(function() {
|
||||
@ -95,10 +99,18 @@ assert.doesNotThrow(() => {
|
||||
}));
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall());
|
||||
}, /^TypeError: The "digest" argument is required and must not be undefined$/);
|
||||
common.expectsError(
|
||||
() => crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "digest" argument must be one of type string or null'
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.pbkdf2Sync('password', 'salt', 8, 8);
|
||||
}, /^TypeError: The "digest" argument is required and must not be undefined$/);
|
||||
common.expectsError(
|
||||
() => crypto.pbkdf2Sync('password', 'salt', 8, 8),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "digest" argument must be one of type string or null'
|
||||
});
|
||||
|
@ -33,15 +33,6 @@ crypto.DEFAULT_ENCODING = 'buffer';
|
||||
// bump, we register a lot of exit listeners
|
||||
process.setMaxListeners(256);
|
||||
|
||||
const errMessages = {
|
||||
offsetNotNumber: /^TypeError: offset must be a number$/,
|
||||
offsetOutOfRange: /^RangeError: offset out of range$/,
|
||||
offsetNotUInt32: /^TypeError: offset must be a uint32$/,
|
||||
sizeNotNumber: /^TypeError: size must be a number$/,
|
||||
sizeNotUInt32: /^TypeError: size must be a uint32$/,
|
||||
bufferTooSmall: /^RangeError: buffer too small$/,
|
||||
};
|
||||
|
||||
const expectedErrorRegexp = /^TypeError: size must be a number >= 0$/;
|
||||
[crypto.randomBytes, crypto.pseudoRandomBytes].forEach(function(f) {
|
||||
[-1, undefined, null, false, true, {}, []].forEach(function(value) {
|
||||
@ -74,6 +65,46 @@ const expectedErrorRegexp = /^TypeError: size must be a number >= 0$/;
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Uint16Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFillSync(buf);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Uint32Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFillSync(buf);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Float32Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFillSync(buf);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Float64Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFillSync(buf);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new DataView(new ArrayBuffer(10));
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFillSync(buf);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}
|
||||
|
||||
{
|
||||
const buf = Buffer.alloc(10);
|
||||
const before = buf.toString('hex');
|
||||
@ -94,6 +125,56 @@ const expectedErrorRegexp = /^TypeError: size must be a number >= 0$/;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Uint16Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFill(buf, common.mustCall((err, buf) => {
|
||||
assert.ifError(err);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Uint32Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFill(buf, common.mustCall((err, buf) => {
|
||||
assert.ifError(err);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Float32Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFill(buf, common.mustCall((err, buf) => {
|
||||
assert.ifError(err);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new Float64Array(10);
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFill(buf, common.mustCall((err, buf) => {
|
||||
assert.ifError(err);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = new DataView(new ArrayBuffer(10));
|
||||
const before = Buffer.from(buf.buffer).toString('hex');
|
||||
crypto.randomFill(buf, common.mustCall((err, buf) => {
|
||||
assert.ifError(err);
|
||||
const after = Buffer.from(buf.buffer).toString('hex');
|
||||
assert.notStrictEqual(before, after);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const buf = Buffer.alloc(10);
|
||||
const before = buf.toString('hex');
|
||||
@ -155,108 +236,228 @@ const expectedErrorRegexp = /^TypeError: size must be a number >= 0$/;
|
||||
const len = Buffer.byteLength(buf);
|
||||
assert.strictEqual(len, 10, `Expected byteLength of 10, got ${len}`);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 'test');
|
||||
}, errMessages.offsetNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 'test'),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, NaN);
|
||||
}, errMessages.offsetNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, NaN),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 'test', common.mustNotCall());
|
||||
}, errMessages.offsetNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 'test', common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, NaN, common.mustNotCall());
|
||||
}, errMessages.offsetNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, NaN, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 11);
|
||||
}, errMessages.offsetOutOfRange);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 11),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "offset" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, max);
|
||||
}, errMessages.offsetOutOfRange);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, max),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "offset" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 11, common.mustNotCall());
|
||||
}, errMessages.offsetOutOfRange);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 11, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "offset" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, max, common.mustNotCall());
|
||||
}, errMessages.offsetOutOfRange);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, max, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "offset" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 0, 'test');
|
||||
}, errMessages.sizeNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 0, 'test'),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 0, NaN);
|
||||
}, errMessages.sizeNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 0, NaN),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 0, 'test', common.mustNotCall());
|
||||
}, errMessages.sizeNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 0, 'test', common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 0, NaN, common.mustNotCall());
|
||||
}, errMessages.sizeNotNumber);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 0, NaN, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type number'
|
||||
}
|
||||
);
|
||||
|
||||
{
|
||||
const size = (-1 >>> 0) + 1;
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 0, -10);
|
||||
}, errMessages.sizeNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 0, -10),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 0, size);
|
||||
}, errMessages.sizeNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 0, size),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 0, -10, common.mustNotCall());
|
||||
}, errMessages.sizeNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 0, -10, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 0, size, common.mustNotCall());
|
||||
}, errMessages.sizeNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 0, size, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "size" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, -10);
|
||||
}, errMessages.offsetNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, -10),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, -10, common.mustNotCall());
|
||||
}, errMessages.offsetNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, -10, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 1, 10);
|
||||
}, errMessages.bufferTooSmall);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 1, 10),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "size" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 1, 10, common.mustNotCall());
|
||||
}, errMessages.bufferTooSmall);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 1, 10, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "size" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, 0, 12);
|
||||
}, errMessages.bufferTooSmall);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, 0, 12),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "size" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, 0, 12, common.mustNotCall());
|
||||
}, errMessages.bufferTooSmall);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, 0, 12, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
type: RangeError,
|
||||
message: 'The "size" argument is out of range'
|
||||
}
|
||||
);
|
||||
|
||||
{
|
||||
// Offset is too big
|
||||
const offset = (-1 >>> 0) + 1;
|
||||
assert.throws(() => {
|
||||
crypto.randomFillSync(buf, offset, 10);
|
||||
}, errMessages.offsetNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(buf, offset, 10),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
crypto.randomFill(buf, offset, 10, common.mustNotCall());
|
||||
}, errMessages.offsetNotUInt32);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(buf, offset, 10, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError,
|
||||
message: 'The "offset" argument must be of type uint32'
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,4 +466,21 @@ const expectedErrorRegexp = /^TypeError: size must be a number >= 0$/;
|
||||
// length exceeds max acceptable value"
|
||||
assert.throws(function() {
|
||||
crypto.randomBytes((-1 >>> 0) + 1);
|
||||
}, errMessages.sizeNotUInt32);
|
||||
}, /^TypeError: size must be a uint32$/);
|
||||
|
||||
[1, true, NaN, null, undefined, {}, []].forEach((i) => {
|
||||
common.expectsError(
|
||||
() => crypto.randomFillSync(i),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
}
|
||||
);
|
||||
common.expectsError(
|
||||
() => crypto.randomFill(i, common.mustNotCall()),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -197,21 +197,21 @@ const modSize = 1024;
|
||||
|
||||
// Test exceptions for invalid `padding` and `saltLength` values
|
||||
{
|
||||
const paddingNotInteger = /^TypeError: padding must be an integer$/;
|
||||
const saltLengthNotInteger = /^TypeError: saltLength must be an integer$/;
|
||||
|
||||
[null, undefined, NaN, 'boom', {}, [], true, false]
|
||||
.forEach((invalidValue) => {
|
||||
assert.throws(() => {
|
||||
common.expectsError(() => {
|
||||
crypto.createSign('SHA256')
|
||||
.update('Test123')
|
||||
.sign({
|
||||
key: keyPem,
|
||||
padding: invalidValue
|
||||
});
|
||||
}, paddingNotInteger);
|
||||
}, {
|
||||
code: 'ERR_INVALID_OPT_VALUE',
|
||||
type: TypeError
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
common.expectsError(() => {
|
||||
crypto.createSign('SHA256')
|
||||
.update('Test123')
|
||||
.sign({
|
||||
@ -219,7 +219,10 @@ const modSize = 1024;
|
||||
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
||||
saltLength: invalidValue
|
||||
});
|
||||
}, saltLengthNotInteger);
|
||||
}, {
|
||||
code: 'ERR_INVALID_OPT_VALUE',
|
||||
type: TypeError
|
||||
});
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
@ -234,9 +237,12 @@ const modSize = 1024;
|
||||
|
||||
// Test throws exception when key options is null
|
||||
{
|
||||
assert.throws(() => {
|
||||
common.expectsError(() => {
|
||||
crypto.createSign('SHA1').update('Test123').sign(null, 'base64');
|
||||
}, /^Error: No key provided to sign$/);
|
||||
}, {
|
||||
code: 'ERR_CRYPTO_SIGN_KEY_REQUIRED',
|
||||
type: Error
|
||||
});
|
||||
}
|
||||
|
||||
// RSA-PSS Sign test by verifying with 'openssl dgst -verify'
|
||||
|
@ -67,9 +67,12 @@ assert.throws(function() {
|
||||
|
||||
|
||||
// update() should only take buffers / strings
|
||||
assert.throws(function() {
|
||||
crypto.createHash('sha1').update({ foo: 'bar' });
|
||||
}, /^TypeError: Data must be a string or a buffer$/);
|
||||
common.expectsError(
|
||||
() => crypto.createHash('sha1').update({ foo: 'bar' }),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
});
|
||||
|
||||
|
||||
function validateList(list) {
|
||||
|
Loading…
Reference in New Issue
Block a user