nstdlib-nightly
Version:
Node.js standard library converted to runtime-agnostic ES modules.
290 lines (236 loc) • 7 kB
JavaScript
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/crypto/sig.js
import { codes as __codes__ } from "nstdlib/lib/internal/errors";
import {
validateFunction,
validateEncoding,
validateString,
} from "nstdlib/lib/internal/validators";
import {
Sign as _Sign,
SignJob,
Verify as _Verify,
kCryptoJobAsync,
kCryptoJobSync,
kSigEncDER,
kSigEncP1363,
kSignJobModeSign,
kSignJobModeVerify,
} from "nstdlib/stub/binding/crypto";
import {
getArrayBufferOrView,
kHandle,
} from "nstdlib/lib/internal/crypto/util";
import {
preparePrivateKey,
preparePublicOrPrivateKey,
} from "nstdlib/lib/internal/crypto/keys";
import { Writable } from "nstdlib/lib/stream";
import { Buffer } from "nstdlib/lib/buffer";
import { isArrayBufferView } from "nstdlib/lib/internal/util/types";
const {
ERR_CRYPTO_SIGN_KEY_REQUIRED,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
} = __codes__;
function Sign(algorithm, options) {
if (!(this instanceof Sign)) return new Sign(algorithm, options);
validateString(algorithm, "algorithm");
this[kHandle] = new _Sign();
this[kHandle].init(algorithm);
ReflectApply(Writable, 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) {
if (typeof data === "string") {
validateEncoding(data, encoding);
} else if (!isArrayBufferView(data)) {
throw new ERR_INVALID_ARG_TYPE(
"data",
["string", "Buffer", "TypedArray", "DataView"],
data,
);
}
this[kHandle].update(data, encoding);
return this;
};
function getPadding(options) {
return getIntOption("padding", options);
}
function getSaltLength(options) {
return getIntOption("saltLength", options);
}
function getDSASignatureEncoding(options) {
if (typeof options === "object") {
const { dsaEncoding = "der" } = options;
if (dsaEncoding === "der") return kSigEncDER;
else if (dsaEncoding === "ieee-p1363") return kSigEncP1363;
throw new ERR_INVALID_ARG_VALUE("options.dsaEncoding", dsaEncoding);
}
return kSigEncDER;
}
function getIntOption(name, options) {
const value = options[name];
if (value !== undefined) {
if (value === value >> 0) {
return value;
}
throw new ERR_INVALID_ARG_VALUE(`options.${name}`, value);
}
return undefined;
}
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);
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(options);
const ret = this[kHandle].sign(
data,
format,
type,
passphrase,
rsaPadding,
pssSaltLength,
dsaSigEnc,
);
if (encoding && encoding !== "buffer") return ret.toString(encoding);
return ret;
};
function signOneShot(algorithm, data, key, callback) {
if (algorithm != null) validateString(algorithm, "algorithm");
if (callback !== undefined) validateFunction(callback, "callback");
data = getArrayBufferOrView(data, "data");
if (!key) throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
// Options specific to RSA
const rsaPadding = getPadding(key);
const pssSaltLength = getSaltLength(key);
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(key);
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase,
} = preparePrivateKey(key);
const job = new SignJob(
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeSign,
keyData,
keyFormat,
keyType,
keyPassphrase,
data,
algorithm,
pssSaltLength,
rsaPadding,
dsaSigEnc,
);
if (!callback) {
const { 0: err, 1: signature } = job.run();
if (err !== undefined) throw err;
return Buffer.from(signature);
}
job.ondone = (error, signature) => {
if (error) return Function.prototype.call.call(callback, job, error);
Function.prototype.call.call(callback, job, null, Buffer.from(signature));
};
job.run();
}
function Verify(algorithm, options) {
if (!(this instanceof Verify)) return new Verify(algorithm, options);
validateString(algorithm, "algorithm");
this[kHandle] = new _Verify();
this[kHandle].init(algorithm);
ReflectApply(Writable, 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, passphrase } = preparePublicOrPrivateKey(
options,
true,
);
// Options specific to RSA
const rsaPadding = getPadding(options);
const pssSaltLength = getSaltLength(options);
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(options);
signature = getArrayBufferOrView(signature, "signature", sigEncoding);
return this[kHandle].verify(
data,
format,
type,
passphrase,
signature,
rsaPadding,
pssSaltLength,
dsaSigEnc,
);
};
function verifyOneShot(algorithm, data, key, signature, callback) {
if (algorithm != null) validateString(algorithm, "algorithm");
if (callback !== undefined) validateFunction(callback, "callback");
data = getArrayBufferOrView(data, "data");
if (!isArrayBufferView(data)) {
throw new ERR_INVALID_ARG_TYPE(
"data",
["Buffer", "TypedArray", "DataView"],
data,
);
}
// Options specific to RSA
const rsaPadding = getPadding(key);
const pssSaltLength = getSaltLength(key);
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(key);
if (!isArrayBufferView(signature)) {
throw new ERR_INVALID_ARG_TYPE(
"signature",
["Buffer", "TypedArray", "DataView"],
signature,
);
}
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase,
} = preparePublicOrPrivateKey(key);
const job = new SignJob(
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeVerify,
keyData,
keyFormat,
keyType,
keyPassphrase,
data,
algorithm,
pssSaltLength,
rsaPadding,
dsaSigEnc,
signature,
);
if (!callback) {
const { 0: err, 1: result } = job.run();
if (err !== undefined) throw err;
return result;
}
job.ondone = (error, result) => {
if (error) return Function.prototype.call.call(callback, job, error);
Function.prototype.call.call(callback, job, null, result);
};
job.run();
}
export { Sign };
export { signOneShot };
export { Verify };
export { verifyOneShot };