js-crypto-key-utils
Version:
Universal Module for Cryptographic Key Utilities in JavaScript, including PEM-JWK converters
192 lines • 9.96 kB
JavaScript
/**
* asn1rsa.js
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toJwk = exports.fromJwk = void 0;
var asn1_js_1 = __importDefault(require("asn1.js"));
var js_encoding_utils_1 = __importDefault(require("js-encoding-utils"));
var BufferMod = __importStar(require("buffer"));
var Buffer = BufferMod.Buffer;
var params = __importStar(require("./params"));
var util_1 = require("./util");
/**
* Encode RSA JWK key to ASN.1 DER or PEM of SPKI/OneAsymmetricKey.
* @param {JsonWebKey} jwk - A key object in JWK format to be encoded.
* @param {PublicOrPrivate} type - 'public' or 'private'.
* @returns {DecodedAsn1Key} - Parsed object of ASN.1 encoded key object.
*/
var fromJwk = function (jwk, type) {
var publicKeyAlgorithmOid = params.publicKeyAlgorithms['RSA'].oid;
// Parameters is always null Ox0500 in ASN.1 as shown in the Section 2.3.1 https://tools.ietf.org/html/rfc3279
var parameters = Buffer.from([0x05, 0x00]);
var algorithm = { algorithm: publicKeyAlgorithmOid, parameters: parameters };
// to append leading zeros (pruned when making JWK) in order to make binary of intended bit length
// https://tools.ietf.org/html/rfc7518#section-6.3
var modulusBytes = js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.n);
var nLen = modulusBytes.length;
var modulusLength = (nLen % 128 === 0) ? nLen : nLen + (128 - (nLen % 128));
var modulus = new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(modulusBytes, modulusLength)); // JWA RFC
var publicExponent = new asn1_js_1.default.bignum(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.e));
var decoded = {};
if (type === 'public') { // SPKI
decoded.subjectPublicKey = {
unused: 0,
data: RSAPublicKey.encode({ modulus: modulus, publicExponent: publicExponent }, 'der')
};
decoded.algorithm = algorithm;
}
else if (type === 'private') { // PKCS8
decoded.version = 0; // no public key presents for v2 (0)
decoded.privateKeyAlgorithm = algorithm;
decoded.privateKey = RSAPrivateKey.encode({
version: 0,
modulus: modulus,
publicExponent: publicExponent,
privateExponent: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.d), modulusLength)),
prime1: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.p), modulusLength)),
prime2: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.q), modulusLength)),
exponent1: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.dp), modulusLength)),
exponent2: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.dq), modulusLength)),
coefficient: new asn1_js_1.default.bignum((0, util_1.appendLeadingZeros)(js_encoding_utils_1.default.encoder.decodeBase64Url(jwk.qi), modulusLength))
}, 'der');
}
return decoded;
};
exports.fromJwk = fromJwk;
/**
* Convert RSA spki/pkcs8 public/private keys to JWK
* @param {Object} decoded - Parsed object of RSA key to be encoded.
* @param {PublicOrPrivate} type - 'public' or 'private'
* @return {JsonWebKey} - Encoded RSA key object in JWK format.
*/
var toJwk = function (decoded, type) {
if (type === 'public') { // SPKI
// algorithm.algorithm.parameters is always null Ox0500 in ASN.1
// as shown in the Section 2.3.1 https://tools.ietf.org/html/rfc3279
// overwrite nested binary object as parsed object
decoded.subjectPublicKey.data = RSAPublicKey.decode(decoded.subjectPublicKey.data, 'der');
var modulus = decoded.subjectPublicKey.data.modulus;
var publicExponent = decoded.subjectPublicKey.data.publicExponent;
// convert n and e from BN
// modulus n
var nLen = modulus.byteLength();
var len = (nLen % 128 === 0) ? nLen : nLen + (128 - (nLen % 128));
modulus = new Uint8Array(modulus.toArray('be', len));
// // publicExponent e;
publicExponent = new Uint8Array(publicExponent.toArray('be', publicExponent.byteLength()));
return {
kty: 'RSA',
n: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(modulus)),
e: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(publicExponent))
};
}
else { // type === 'private', PKCS8
// privateKeyAlgorithm.algorithm.parameters is always null Ox0500 in ASN.1
// as shown in the Section 2.3.1 https://tools.ietf.org/html/rfc3279
// overwrite nested binary object as parsed object
decoded.privateKey = RSAPrivateKey.decode(decoded.privateKey, 'der');
var privateKeyElems_1 = {}; // work around
privateKeyElems_1.modulus = decoded.privateKey.modulus;
// calculate key length from modulus n
var nLen = privateKeyElems_1.modulus.byteLength();
var len_1 = (nLen % 128 === 0) ? nLen : nLen + (128 - (nLen % 128)); // this is actual key length, e.g., 256 bytes
// convert BN to Uint8Array
privateKeyElems_1.modulus = new Uint8Array(privateKeyElems_1.modulus.toArray('be', len_1)); // n of length len
privateKeyElems_1.publicExponent = new Uint8Array(decoded.privateKey.publicExponent.toArray('be', decoded.privateKey.publicExponent.byteLength())); // e of arbitrary small length
privateKeyElems_1.privateExponent = new Uint8Array(decoded.privateKey.privateExponent.toArray('be', len_1)); // d of length len
var keys = ['prime1', 'prime2', 'exponent1', 'exponent2', 'coefficient']; // elements of length len/2
keys.forEach(function (key) {
privateKeyElems_1[key] = new Uint8Array(decoded.privateKey[key].toArray('be', (len_1 >> 1)));
});
// prune leading zeros JWW RSA private key: https://tools.ietf.org/html/rfc7517
return {
kty: 'RSA',
n: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.modulus)),
e: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.publicExponent)),
d: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.privateExponent)),
p: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.prime1)),
q: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.prime2)),
dp: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.exponent1)),
dq: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.exponent2)),
qi: js_encoding_utils_1.default.encoder.encodeBase64Url((0, util_1.pruneLeadingZeros)(privateKeyElems_1.coefficient))
};
}
};
exports.toJwk = toJwk;
///////////
// https://tools.ietf.org/html/rfc3447
var RSAPublicKey = asn1_js_1.default.define('RSAPublicKey', function () {
// @ts-ignore
this.seq().obj(
// @ts-ignore
this.key('modulus').int(), // n
// @ts-ignore
this.key('publicExponent').int() // e
);
});
var RSAPrivateKey = asn1_js_1.default.define('RSAPrivateKey', function () {
// @ts-ignore
this.seq().obj(
// @ts-ignore
this.key('version').int(), // 0
// @ts-ignore
this.key('modulus').int(), // n
// @ts-ignore
this.key('publicExponent').int(), // e
// @ts-ignore
this.key('privateExponent').int(), // d
// @ts-ignore
this.key('prime1').int(), // p
// @ts-ignore
this.key('prime2').int(), // q
// @ts-ignore
this.key('exponent1').int(), // d mod (p-1)
// @ts-ignore
this.key('exponent2').int(), // d mod (q-1)
// @ts-ignore
this.key('coefficient').int(), // (inverse of q) mod p
// @ts-ignore
this.key('otherPrimeInfos').optional().use(OtherPrimeInfos));
});
var OtherPrimeInfos = asn1_js_1.default.define('OtherPrimeInfos', function () {
// @ts-ignore
this.seqof(OtherPrimeInfo);
});
var OtherPrimeInfo = asn1_js_1.default.define('OtherPrimeInfo', function () {
// @ts-ignore
this.seq().obj(
// @ts-ignore
this.key('prime').int(),
// @ts-ignore
this.key('exponent').int(),
// @ts-ignore
this.key('coefficient').int());
});
//# sourceMappingURL=asn1rsa.js.map
;