0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/lib/internal/crypto/sig.js
Tobias Nießen 823d86c47c crypto: add key object API
This commit makes multiple important changes:

1. A new key object API is introduced. The KeyObject class itself is
   not exposed to users, instead, several new APIs can be used to
   construct key objects: createSecretKey, createPrivateKey and
   createPublicKey. The new API also allows to convert between
   different key formats, and even though the API itself is not
   compatible to the WebCrypto standard in any way, it makes
   interoperability much simpler.

2. Key objects can be used instead of the raw key material in all
   relevant crypto APIs.

3. The handling of asymmetric keys has been unified and greatly
   improved. Node.js now fully supports both PEM-encoded and
   DER-encoded public and private keys.

4. Conversions between buffers and strings have been moved to native
   code for sensitive data such as symmetric keys due to security
   considerations such as zeroing temporary buffers.

5. For compatibility with older versions of the crypto API, this
   change allows to specify Buffers and strings as the "passphrase"
   option when reading or writing an encoded key. Note that this
   can result in unexpected behavior if the password contains a
   null byte.

PR-URL: https://github.com/nodejs/node/pull/24234
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2018-12-24 14:50:16 +01:00

138 lines
3.4 KiB
JavaScript

'use strict';
const {
ERR_CRYPTO_SIGN_KEY_REQUIRED,
ERR_INVALID_OPT_VALUE
} = require('internal/errors').codes;
const { validateString } = require('internal/validators');
const { Sign: _Sign, Verify: _Verify } = internalBinding('crypto');
const {
RSA_PSS_SALTLEN_AUTO,
RSA_PKCS1_PADDING
} = internalBinding('constants').crypto;
const {
getDefaultEncoding,
kHandle,
legacyNativeHandle,
toBuf,
validateArrayBufferView,
} = require('internal/crypto/util');
const {
preparePrivateKey,
preparePublicKey
} = require('internal/crypto/keys');
const { Writable } = require('stream');
function Sign(algorithm, options) {
if (!(this instanceof Sign))
return new Sign(algorithm, options);
validateString(algorithm, 'algorithm');
this[kHandle] = new _Sign();
this[kHandle].init(algorithm);
Writable.call(this, options);
}
Object.setPrototypeOf(Sign.prototype, Writable.prototype);
Object.setPrototypeOf(Sign, Writable);
Sign.prototype._write = function _write(chunk, encoding, callback) {
this.update(chunk, encoding);
callback();
};
Sign.prototype.update = function update(data, encoding) {
encoding = encoding || getDefaultEncoding();
data = validateArrayBufferView(toBuf(data, encoding),
'data');
this[kHandle].update(data);
return this;
};
legacyNativeHandle(Sign);
function getPadding(options) {
return getIntOption('padding', RSA_PKCS1_PADDING, options);
}
function getSaltLength(options) {
return getIntOption('saltLength', RSA_PSS_SALTLEN_AUTO, options);
}
function getIntOption(name, defaultValue, options) {
if (options.hasOwnProperty(name)) {
const value = options[name];
if (value === value >> 0) {
return value;
} else {
throw new ERR_INVALID_OPT_VALUE(name, value);
}
}
return defaultValue;
}
Sign.prototype.sign = function sign(options, encoding) {
if (!options)
throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
const { data, format, type, passphrase } = preparePrivateKey(options, true);
// Options specific to RSA
const rsaPadding = getPadding(options);
const pssSaltLength = getSaltLength(options);
const ret = this[kHandle].sign(data, format, type, passphrase, rsaPadding,
pssSaltLength);
encoding = encoding || getDefaultEncoding();
if (encoding && encoding !== 'buffer')
return ret.toString(encoding);
return ret;
};
function Verify(algorithm, options) {
if (!(this instanceof Verify))
return new Verify(algorithm, options);
validateString(algorithm, 'algorithm');
this[kHandle] = new _Verify();
this[kHandle].init(algorithm);
Writable.call(this, options);
}
Object.setPrototypeOf(Verify.prototype, Writable.prototype);
Object.setPrototypeOf(Verify, Writable);
Verify.prototype._write = Sign.prototype._write;
Verify.prototype.update = Sign.prototype.update;
Verify.prototype.verify = function verify(options, signature, sigEncoding) {
const {
data,
format,
type
} = preparePublicKey(options, true);
sigEncoding = sigEncoding || getDefaultEncoding();
// Options specific to RSA
var rsaPadding = getPadding(options);
var pssSaltLength = getSaltLength(options);
signature = validateArrayBufferView(toBuf(signature, sigEncoding),
'signature');
return this[kHandle].verify(data, format, type, signature,
rsaPadding, pssSaltLength);
};
legacyNativeHandle(Verify);
module.exports = {
Sign,
Verify
};