This commit is contained in:
2022-07-21 03:28:35 +00:00
parent d7c883d6df
commit 51b34b0e1d
30103 changed files with 4152204 additions and 23 deletions
+156
View File
@@ -0,0 +1,156 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PBES2ESParams = exports.PBKDF2Params = exports.PBES2Params = exports.PBEParameter = exports.EncryptedPrivateKeyInfo = exports.OneAsymmetricKey = exports.SubjectPublicKeyInfo = exports.KeyStructure = void 0;
var _asn = _interopRequireDefault(require("asn1.js"));
/**
* asn1def.js
*/
///////////////////////////////////////////////////////////////////////////////////////////
/**
* This is either one of subjectPublicKeyInfo, oneAsymmetricKey or encryptedPrivateKeyInfo in ASN.1 format.
* @type {AsnObject}
*/
var KeyStructure = _asn.default.define('KeyStructure', function () {
this.choice({
subjectPublicKeyInfo: this.use(SubjectPublicKeyInfo),
oneAsymmetricKey: this.use(OneAsymmetricKey),
encryptedPrivateKeyInfo: this.use(EncryptedPrivateKeyInfo)
});
});
/**
* SubjectPublicKeyInfo specified in RFC 5280 {@link https://tools.ietf.org/html/rfc5280}.
* @type {AsnObject}
*/
exports.KeyStructure = KeyStructure;
var SubjectPublicKeyInfo = _asn.default.define('SubjectPublicKeyInfo', function () {
this.seq().obj(this.key('algorithm').use(AlgorithmIdentifier), this.key('subjectPublicKey').bitstr());
}); ///////////////////////////////////////////////////////////////////////////////////////////
/**
* OneAsymmetricKey specified in RFC5958 {@link https://tools.ietf.org/html/rfc5958}.
* (old version PrivateKeyInfo {@link https://tools.ietf.org/html/rfc5208}.)
* @type {AsnObject}
*/
exports.SubjectPublicKeyInfo = SubjectPublicKeyInfo;
var OneAsymmetricKey = _asn.default.define('OneAsymmetricKey', function () {
this.seq().obj(this.key('version').use(Version), this.key('privateKeyAlgorithm').use(AlgorithmIdentifier), this.key('privateKey').octstr(), this.key('attributes').implicit(0).optional().any(), this.key('publicKey').implicit(1).optional().bitstr());
});
/**
* EncryptedPrivateKeyInfo specified in RFC5958 {@link https://tools.ietf.org/html/rfc5958}.
* @type {AsnObject}
*/
exports.OneAsymmetricKey = OneAsymmetricKey;
var EncryptedPrivateKeyInfo = _asn.default.define('EncryptedPrivateKeyInfo', function () {
this.seq().obj(this.key('encryptionAlgorithm').use(AlgorithmIdentifier), this.key('encryptedData').octstr());
}); ///////////////////////////////////////////////////////////////////////////////////////////
/**
* PBEParameter, parameter for password-based encryption, specified in RFC 8018 {@link https://tools.ietf.org/html/rfc8018}.
* @type {AsnObject}
*/
exports.EncryptedPrivateKeyInfo = EncryptedPrivateKeyInfo;
var PBEParameter = _asn.default.define('PBEParameter', function () {
this.seq().obj(this.key('salt').octstr(8), this.key('iterationCount').int());
});
/**
* PBES2Params, parameter for password-based encryption scheme 2, specified in RFC 8018 {@link https://tools.ietf.org/html/rfc8018}.
* @type {AsnObject}
*/
exports.PBEParameter = PBEParameter;
var PBES2Params = _asn.default.define('PBES2Params', function () {
this.seq().obj(this.key('keyDerivationFunc').use(AlgorithmIdentifier), this.key('encryptionScheme').use(AlgorithmIdentifier));
}); ///////////////////////////////////////////////////////////////////////////////////////////
// PBKDF2-params ::= SEQUENCE {
// salt CHOICE {
// specified OCTET STRING,
// otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
// },
// iterationCount INTEGER (1..MAX),
// keyLength INTEGER (1..MAX) OPTIONAL,
// prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
// algid-hmacWithSHA1
// }
/**
* PBKDF2Params, parameter for PBKDF2, specified in RFC 8018 {@link https://tools.ietf.org/html/rfc8018}.
* @type {AsnObject}
*/
exports.PBES2Params = PBES2Params;
var PBKDF2Params = _asn.default.define('PBKDF2Params', function () {
this.seq().obj(this.key('salt').choice({
'specified': this.octstr(),
'otherSource': this.use(AlgorithmIdentifier)
}), this.key('iterationCount').int(), this.key('keyLength').int().optional(), this.key('prf').use(AlgorithmIdentifier).def({
algorithm: [1, 2, 840, 113549, 2, 7],
// hmacWithSHA1
parameters: Buffer.from([0x05, 0x00])
}));
}); ///////////////////////////////////////////////////////////////////////////////////////////
/**
* PBES2ESParams specified in RFC 8018 {@link https://tools.ietf.org/html/rfc8018}.
* @type {{'aes192-cbc': AsnObject, 'aes128-cbc': AsnObject, 'des-ede3-cbc': Object, 'aes256-cbc': AsnObject}}
*/
exports.PBKDF2Params = PBKDF2Params;
var PBES2ESParams = {
'des-ede3-cbc': _asn.default.define('DesEde3CbcParams', function () {
this.octstr();
}),
'aes128-cbc': _asn.default.define('Aes128CbcParams', function () {
this.octstr();
}),
'aes192-cbc': _asn.default.define('Aes192CbcParams', function () {
this.octstr();
}),
'aes256-cbc': _asn.default.define('Aes256CbcParams', function () {
this.octstr();
})
}; ////////////////////////////////////////////////////////////////////////////////////
/**
* AlgorithmIdentifier given in RFC 5280 {@link https://tools.ietf.org/html/rfc5280}
* @type AsnObject
*/
exports.PBES2ESParams = PBES2ESParams;
var AlgorithmIdentifier = _asn.default.define('AlgorithmIdentifier', function () {
this.seq().obj(this.key('algorithm').objid(), this.key('parameters').optional().any());
});
/**
* Version
* @type {AsnObject}
*/
var Version = _asn.default.define('Version', function () {
this.int();
});
+156
View File
@@ -0,0 +1,156 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toJWK = exports.fromJWK = void 0;
var _asn = _interopRequireDefault(require("asn1.js"));
var _params = _interopRequireWildcard(require("./params.js"));
var _octenc = require("./octenc.js");
/**
* asn1ec.js
*/
/**
* Convert JWK to parsed ASN.1 EC key object
* @param {JsonWebKey} jwk - A key object in JWK format.
* @param {PublicOrPrivate} type - 'public' or 'private'
* @param {boolean} [compact=false] - *Only for EC public keys*, the compact form of public key is given as ASN.1 object if true.
* @return {Object} - Parsed ASN.1 object.
*/
var fromJWK = function fromJWK(jwk, type) {
var compact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (Object.keys(_params.default.namedCurves).indexOf(jwk.crv) < 0) throw new Error('UnsupportedCurve');
var octetPublicKey = (0, _octenc.fromJwk)(jwk, {
outputFormat: 'binary',
outputPublic: true,
compact: compact
});
var publicKeyAlgorithmOid = _params.default.publicKeyAlgorithms['EC'].oid;
var publicKey = {
unused: 0,
data: Array.from(octetPublicKey)
}; //Buffer.from(octkeyObj.publicKey)};
var parameters = ECParameters.encode({
type: 'namedCurve',
value: _params.default.namedCurves[jwk.crv].oid
}, 'der');
var algorithm = {
algorithm: publicKeyAlgorithmOid,
parameters: parameters
};
var decoded = {};
if (type === 'public') {
// SPKI
decoded.subjectPublicKey = publicKey;
decoded.algorithm = algorithm;
} else if (type === 'private') {
// PKCS8
var octetPrivateKey = (0, _octenc.fromJwk)(jwk, {
outputFormat: 'binary',
outputPublic: false,
compact: compact
});
decoded.version = 0; // no public key presents for v2 (0)
decoded.privateKeyAlgorithm = algorithm;
decoded.privateKey = ECPrivateKey.encode({
version: 1,
privateKey: Array.from(octetPrivateKey),
//Buffer.from(octkeyObj.privateKey),
parameters: parameters,
publicKey: publicKey
}, 'der');
}
return decoded;
};
/**
* Convert parsed ASN.1 EC key object to JWK.
* @param {Object} decoded - Parsed ASN.1 EC key object.
* @param {PublicOrPrivate} type - 'public' or 'private'
* @return {JsonWebKey} - Converted key objects in JWK format.
* @throws {Error} - Throws if UnsupportedCurve.
*/
exports.fromJWK = fromJWK;
var toJWK = function toJWK(decoded, type) {
if (type === 'public') {
// SPKI
decoded.algorithm.parameters = ECParameters.decode(decoded.algorithm.parameters, 'der'); // overwrite nested binary object as parsed object
var octPubKey = new Uint8Array(decoded.subjectPublicKey.data); // convert oct key to jwk
var namedCurves = (0, _params.getAlgorithmFromOid)(decoded.algorithm.parameters.value, _params.default.namedCurves);
if (namedCurves.length < 1) throw new Error('UnsupportedCurve');
return (0, _octenc.toJwk)(octPubKey, namedCurves[0], {
outputPublic: true
});
} else if (type === 'private') {
// PKCS8
decoded.privateKeyAlgorithm.parameters = ECParameters.decode(decoded.privateKeyAlgorithm.parameters, 'der'); // Work around for optional private key parameter field.
try {
decoded.privateKey = ECPrivateKey.decode(decoded.privateKey, 'der');
} catch (e) {
decoded.privateKey = ECPrivateKeyAlt.decode(decoded.privateKey, 'der');
}
var octPrivKey = new Uint8Array(decoded.privateKey.privateKey);
var _namedCurves = (0, _params.getAlgorithmFromOid)(decoded.privateKeyAlgorithm.parameters.value, _params.default.namedCurves);
if (_namedCurves.length < 1) throw new Error('UnsupportedCurve');
return (0, _octenc.toJwk)(octPrivKey, _namedCurves[0], {
outputPublic: false
});
}
}; /////////////////////////
/**
* ECParameters specified in RFC 5480 {@link https://tools.ietf.org/html/rfc5480}.
* @type {AsnObject}
*/
exports.toJWK = toJWK;
var ECParameters = _asn.default.define('ECParameters', function () {
this.choice({
namedCurve: this.objid()
});
});
/**
* ECPrivateKey specified in RFC 5915 {@link https://tools.ietf.org/html/rfc5915}.
* @type {AsnObject}
*/
var ECPrivateKey = _asn.default.define('ECPrivateKey', function () {
this.seq().obj(this.key('version').int(), this.key('privateKey').octstr(), this.key('parameters').explicit(0).optional().any(), // rfc suggested that this must be implemented
this.key('publicKey').explicit(1).optional().bitstr() // rfc suggested that this must be implemented
);
});
/**
* ECPrivateKey Alternative for an work around...
* @type {AsnObject}
*/
var ECPrivateKeyAlt = _asn.default.define('ECPrivateKey', function () {
this.seq().obj(this.key('version').int(), this.key('privateKey').octstr(), // this.key('parameters').explicit(0).optional().any(), // rfc suggested that this must be implemented
this.key('publicKey').explicit(1).optional().bitstr() // rfc suggested that this must be implemented
);
});
+229
View File
@@ -0,0 +1,229 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toJwk = exports.fromJwk = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var asn1ec = _interopRequireWildcard(require("./asn1ec.js"));
var asn1rsa = _interopRequireWildcard(require("./asn1rsa.js"));
var _params = _interopRequireWildcard(require("./params.js"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _buffer = _interopRequireDefault(require("buffer"));
var _asn1def = require("./asn1def.js");
var _rfc = require("./rfc8018.js");
var _util = require("./util.js");
/**
* asn1enc.js
*/
var Buffer = _buffer.default.Buffer;
/**
* Convert jwk to spki/pkcs8 in string or binary format.
* @param {JsonWebKey} jwkey - A key object in JWK format to be encoded.
* @param {boolean} outputPublic - Derive public key from private key when true
* @param {AsnFormat} format - 'pem' or 'der'
* @param {boolean} compact - 'true' or 'false' for EC public key compressed representation in der/pem
* @param {String} passphrase - if passphrase is given and the given key is private key, it will be encoded with the passphrase.
* @param {AsnEncryptOptionsWithPassphrase} encOptions - ASN.1 encryption options
* @return {Uint8Array|String} - Encoded private key in DER or PEM
*/
var fromJwk =
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(jwkey, format, _ref) {
var outputPublic, _ref$compact, compact, encOptions, orgType, type, decoded, binKey;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
outputPublic = _ref.outputPublic, _ref$compact = _ref.compact, compact = _ref$compact === void 0 ? false : _ref$compact, encOptions = _ref.encOptions;
orgType = (0, _util.getJwkType)(jwkey);
type = typeof outputPublic === 'boolean' && outputPublic ? 'public' : orgType;
if (jwkey.kty === 'EC') {
decoded = asn1ec.fromJWK(jwkey, type, compact);
} else if (jwkey.kty === 'RSA') {
decoded = asn1rsa.fromJwk(jwkey, type);
}
if (!(type === 'public')) {
_context.next = 8;
break;
}
binKey = _asn1def.SubjectPublicKeyInfo.encode(decoded, 'der');
_context.next = 14;
break;
case 8:
binKey = _asn1def.OneAsymmetricKey.encode(decoded, 'der');
if (!(typeof encOptions.passphrase !== 'undefined' && encOptions.passphrase.length > 0)) {
_context.next = 14;
break;
}
_context.next = 12;
return (0, _rfc.encryptEncryptedPrivateKeyInfo)(binKey, encOptions);
case 12:
binKey = _context.sent;
type = 'encryptedPrivate';
case 14:
binKey = new Uint8Array(binKey);
return _context.abrupt("return", format === 'pem' ? _jsEncodingUtils.default.formatter.binToPem(binKey, type) : binKey);
case 16:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function fromJwk(_x, _x2, _x3) {
return _ref2.apply(this, arguments);
};
}();
/**
* Convert SPKI/PKCS8 key in string or binary format to JWK.
* @param {PEM|DER} key - Key object.
* @param {AsnFormat} format - 'pem' or 'der'
* @param {boolean} [outputPublic] - Export public key even from private key if true.
* @param {String} [passphrase] - Encrypt private key if passphrase is given.
* @return {JsonWebKey} - Obtained key object in JWK format.
* @throws {Error} Throws if UnsupportedKeyStructure, UnsupportedKey or InvalidKeyType.
*/
exports.fromJwk = fromJwk;
var toJwk =
/*#__PURE__*/
function () {
var _ref4 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(key, format, _ref3) {
var outputPublic, passphrase, binKey, decoded, type, keyTypes;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
outputPublic = _ref3.outputPublic, passphrase = _ref3.passphrase;
// Peel the pem strings
binKey = format === 'pem' ? _jsEncodingUtils.default.formatter.pemToBin(key) : key; // decode binary spki/pkcs8-formatted key to parsed object
_context2.prev = 2;
decoded = _asn1def.KeyStructure.decode(Buffer.from(binKey), 'der');
_context2.next = 9;
break;
case 6:
_context2.prev = 6;
_context2.t0 = _context2["catch"](2);
throw new Error('FailedToDecodeKey');
case 9:
if (!(decoded.type === 'subjectPublicKeyInfo')) {
_context2.next = 14;
break;
}
type = 'public';
decoded = decoded.value;
_context2.next = 26;
break;
case 14:
type = typeof outputPublic === 'boolean' && outputPublic ? 'public' : 'private';
if (!(decoded.type === 'encryptedPrivateKeyInfo')) {
_context2.next = 21;
break;
}
_context2.next = 18;
return (0, _rfc.decryptEncryptedPrivateKeyInfo)(decoded.value, passphrase);
case 18:
decoded = _context2.sent;
_context2.next = 26;
break;
case 21:
if (!(decoded.type === 'oneAsymmetricKey')) {
_context2.next = 25;
break;
}
decoded = decoded.value;
_context2.next = 26;
break;
case 25:
throw new Error('UnsupportedKeyStructure');
case 26:
keyTypes = (0, _params.getAlgorithmFromOid)(type === 'public' ? decoded.algorithm.algorithm : decoded.privateKeyAlgorithm.algorithm, _params.default.publicKeyAlgorithms);
if (!(keyTypes.length < 1)) {
_context2.next = 29;
break;
}
throw new Error('UnsupportedKey');
case 29:
if (!(keyTypes[0] === 'EC')) {
_context2.next = 33;
break;
}
return _context2.abrupt("return", asn1ec.toJWK(decoded, type));
case 33:
if (!(keyTypes[0] === 'RSA')) {
_context2.next = 37;
break;
}
return _context2.abrupt("return", asn1rsa.toJwk(decoded, type));
case 37:
throw new Error('InvalidKeyType');
case 38:
case "end":
return _context2.stop();
}
}
}, _callee2, null, [[2, 6]]);
}));
return function toJwk(_x4, _x5, _x6) {
return _ref4.apply(this, arguments);
};
}();
exports.toJwk = toJwk;
+182
View File
@@ -0,0 +1,182 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toJwk = exports.fromJwk = void 0;
var _asn = _interopRequireDefault(require("asn1.js"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _buffer = _interopRequireDefault(require("buffer"));
var _params = _interopRequireDefault(require("./params.js"));
var _util = require("./util");
/**
* asn1rsa.js
*/
var Buffer = _buffer.default.Buffer;
/**
* 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 {Object} - Parsed object of ASN.1 encoded key object.
*/
var fromJwk = function fromJwk(jwk, type) {
var publicKeyAlgorithmOid = _params.default.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 = _jsEncodingUtils.default.encoder.decodeBase64Url(jwk.n);
var nLen = modulusBytes.length;
var modulusLength = nLen % 128 === 0 ? nLen : nLen + (128 - nLen % 128);
var modulus = new _asn.default.bignum((0, _util.appendLeadingZeros)(modulusBytes, modulusLength)); // JWA RFC
var publicExponent = new _asn.default.bignum(_jsEncodingUtils.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 _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.d), modulusLength)),
prime1: new _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.p), modulusLength)),
prime2: new _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.q), modulusLength)),
exponent1: new _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.dp), modulusLength)),
exponent2: new _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.dq), modulusLength)),
coefficient: new _asn.default.bignum((0, _util.appendLeadingZeros)(_jsEncodingUtils.default.encoder.decodeBase64Url(jwk.qi), modulusLength))
}, 'der');
}
return decoded;
};
/**
* 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.
*/
exports.fromJwk = fromJwk;
var toJwk = function toJwk(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: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(modulus)),
// prune leading zeros https://tools.ietf.org/html/rfc7518#section-6.3
e: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(publicExponent))
};
} else if (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 = {};
privateKeyElems.modulus = decoded.privateKey.modulus; // calculate key length from modulus n
var _nLen = privateKeyElems.modulus.byteLength();
var _len = _nLen % 128 === 0 ? _nLen : _nLen + (128 - _nLen % 128); // this is actual key length, e.g., 256 bytes
// convert BN to Uint8Array
privateKeyElems.modulus = new Uint8Array(privateKeyElems.modulus.toArray('be', _len)); // n of length len
privateKeyElems.publicExponent = new Uint8Array(decoded.privateKey.publicExponent.toArray('be', decoded.privateKey.publicExponent.byteLength())); // e of arbitrary small length
privateKeyElems.privateExponent = new Uint8Array(decoded.privateKey.privateExponent.toArray('be', _len)); // d of length len
var keys = ['prime1', 'prime2', 'exponent1', 'exponent2', 'coefficient']; // elements of length len/2
keys.forEach(function (key) {
privateKeyElems[key] = new Uint8Array(decoded.privateKey[key].toArray('be', _len >> 1));
}); // prune leading zeros JWW RSA private key: https://tools.ietf.org/html/rfc7517
return {
kty: 'RSA',
n: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.modulus)),
e: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.publicExponent)),
d: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.privateExponent)),
p: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.prime1)),
q: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.prime2)),
dp: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.exponent1)),
dq: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.exponent2)),
qi: _jsEncodingUtils.default.encoder.encodeBase64Url((0, _util.pruneLeadingZeros)(privateKeyElems.coefficient))
};
}
}; ///////////
// https://tools.ietf.org/html/rfc3447
exports.toJwk = toJwk;
var RSAPublicKey = _asn.default.define('RSAPublicKey', function () {
this.seq().obj(this.key('modulus').int(), // n
this.key('publicExponent').int() // e
);
});
var RSAPrivateKey = _asn.default.define('RSAPrivateKey', function () {
this.seq().obj(this.key('version').int(), // 0
this.key('modulus').int(), // n
this.key('publicExponent').int(), // e
this.key('privateExponent').int(), // d
this.key('prime1').int(), // p
this.key('prime2').int(), // q
this.key('exponent1').int(), // d mod (p-1)
this.key('exponent2').int(), // d mod (q-1)
this.key('coefficient').int(), // (inverse of q) mod p
this.key('otherPrimeInfos').optional().use(OtherPrimeInfos));
});
var OtherPrimeInfos = _asn.default.define('OtherPrimeInfos', function () {
this.seqof(OtherPrimeInfo);
});
var OtherPrimeInfo = _asn.default.define('OtherPrimeInfo', function () {
this.seq().obj(this.key('prime').int(), this.key('exponent').int(), this.key('coefficient').int());
});
+231
View File
@@ -0,0 +1,231 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toJwkFrom = exports.fromJwkTo = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var asn1enc = _interopRequireWildcard(require("./asn1enc.js"));
var octenc = _interopRequireWildcard(require("./octenc.js"));
/**
* converter.js
*/
// ASN.1 in RFC5280 (SPKI) and RFC5208 (PKCS8) -> RSA and EC, encode='asn', format='pem' or 'der'
// -> SPKI (in X.509): RFC5280 for public key, PKCS8: RFC5208 for private key
// Octet Form in ANSI X9.63 -> EC, encode='oct', format='string' or 'binary', compact=true or false
// -> Standards for Efficient Cryptography Group (SECG), "SEC1: Elliptic Curve Cryptography", Version 1.0, September 2000.
/**
* Convert JWK to ASN.1 (for RSA and EC) and Octet (for EC) encoded keys.
* @param {String} output - 'pem', 'der', or 'oct' (only EC JWK), output format.
* @param {JsonWebKey} jwkey - A JWK to be encoded.
* @param {KeyExportOptions} options - Options to export key including encryption options.
* For EC JWK : options.compact = true or false
* For EC JWK with output = 'oct' : options.format = 'binary' or 'string'
* For both: outputPublic (optional) : boolean. derived key type. from private key, public key can be derived when true.
* @return {PEM|DER|OctetEC} - Output key object.
*/
var fromJwkTo =
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
var output,
jwkey,
options,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
output = _args.length > 0 && _args[0] !== undefined ? _args[0] : 'pem';
jwkey = _args.length > 1 ? _args[1] : undefined;
options = _args.length > 2 && _args[2] !== undefined ? _args[2] : {};
if (!(['pem', 'der', 'oct'].indexOf(output) < 0)) {
_context.next = 5;
break;
}
throw new Error('InvalidOutputForm');
case 5:
if (!((0, _typeof2.default)(jwkey) !== 'object')) {
_context.next = 7;
break;
}
throw new Error('InvalidJWKAsObject');
case 7:
if (!(jwkey.kty !== 'EC' && jwkey.kty !== 'RSA')) {
_context.next = 9;
break;
}
throw new Error('UnsupportedKeyType');
case 9:
if (!(typeof options.outputPublic !== 'undefined' && typeof options.outputPublic !== 'boolean')) {
_context.next = 11;
break;
}
throw new Error('outputPublicMustBeBoolean');
case 11:
// default values
if (jwkey.key === 'EC' && typeof options.compact !== 'boolean') options.compact = false;
if (output === 'oct' && options.output !== 'string') options.output = 'binary';
if (typeof options.encryptParams === 'undefined') options.encryptParams = {};
if ((output === 'der' || output === 'pem') && typeof options.encryptParams.passphrase === 'undefined') options.encryptParams.passphrase = ''; // In the case of PEM/DER
if (!(output === 'der' || output === 'pem')) {
_context.next = 21;
break;
}
_context.next = 18;
return asn1enc.fromJwk(jwkey, output, {
outputPublic: options.outputPublic,
compact: options.compact,
encOptions: options.encryptParams
});
case 18:
return _context.abrupt("return", _context.sent);
case 21:
if (!(output === 'oct' && jwkey.kty === 'EC')) {
_context.next = 25;
break;
}
return _context.abrupt("return", octenc.fromJwk(jwkey, {
outputPublic: options.outputPublic,
outputFormat: options.output,
compact: options.compact
}));
case 25:
throw new Error('UnsupportedConversion');
case 26:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function fromJwkTo() {
return _ref.apply(this, arguments);
};
}();
/**
* Convert ASN.1 encoded (for RSA and EC) or octet formed (for EC) keys to JWK.
* @param {String} input - 'pem', 'der' or 'oct', input key format.
* @param {PEM|DER|OctetEC} key - A key object to be encoded.
* @param {JwkExportOptionsInternal} [options={}] - options to export JWK keys.
* @return {JsonWebKey} - Obtained key object in JWK format.
* @throws {Error} - Throws if InvalidInputForm, InappropriateOptions, outputPublicMustBeBoolean or UnsupportedConversion
*/
exports.fromJwkTo = fromJwkTo;
var toJwkFrom =
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(input, key) {
var options,
_args2 = arguments;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
options = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : {};
if (!(['pem', 'der', 'oct'].indexOf(input) < 0)) {
_context2.next = 3;
break;
}
throw new Error('InvalidInputForm');
case 3:
if (!(input === 'oct' && !options.namedCurve)) {
_context2.next = 5;
break;
}
throw new Error('InappropriateOptions');
case 5:
if (!(typeof options.outputPublic !== 'undefined' && typeof options.outputPublic !== 'boolean')) {
_context2.next = 7;
break;
}
throw new Error('outputPublicMustBeBoolean');
case 7:
// default values
if ((input === 'der' || input === 'pem') && typeof options.passphrase === 'undefined') options.passphrase = ''; // In the case of PEM
if (!(input === 'der' || input === 'pem')) {
_context2.next = 14;
break;
}
_context2.next = 11;
return asn1enc.toJwk(key, input, {
outputPublic: options.outputPublic,
passphrase: options.passphrase
});
case 11:
return _context2.abrupt("return", _context2.sent);
case 14:
if (!(input === 'oct')) {
_context2.next = 18;
break;
}
return _context2.abrupt("return", octenc.toJwk(key, options.namedCurve, {
outputPublic: options.outputPublic
}));
case 18:
throw new Error('UnsupportedConversion');
case 19:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return function toJwkFrom(_x, _x2) {
return _ref2.apply(this, arguments);
};
}();
exports.toJwkFrom = toJwkFrom;
+27
View File
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Key", {
enumerable: true,
get: function get() {
return _key.Key;
}
});
exports.default = void 0;
var _key = require("./key.js");
/**
* index.js
*/
// import {fromJwkTo, toJwkFrom} from './converter.js';
// import {getJwkThumbprint} from './thumbprint.js';
// import {isAsn1Encrypted} from './util.js';
// export default {fromJwkTo, toJwkFrom, getJwkThumbprint, isAsn1Encrypted, Key};
// export {fromJwkTo, toJwkFrom, getJwkThumbprint, isAsn1Encrypted, Key};
var _default = {
Key: _key.Key
};
exports.default = _default;
File diff suppressed because one or more lines are too long
+601
View File
@@ -0,0 +1,601 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Key = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _converter = require("./converter.js");
var _thumbprint = require("./thumbprint.js");
var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _util = require("./util.js");
/**
* key.js
*/
/**
* Key class to abstract public and private key objects in string or binary.
* This class provides functions to interchangeably convert key formats,
* and key objects will be used for the root package, js-crypto-utils, as inputs to exposed APIs.
*/
var Key =
/*#__PURE__*/
function () {
/**
* @constructor
* @param {String} format - Key format: 'jwk', 'der', 'pem' or 'oct' (only for ECC key).
* @param {JsonWebKey|PEM|DER|OctetEC} key - Key object in the specified format.
* @param {Object} [options={}] - Required if format='oct', and then it is {namedCurve: String}.
* @throws {Error} - Throws if the input format and key are incompatible to the constructor.
*/
function Key(format, key) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
(0, _classCallCheck2.default)(this, Key);
var localKey = (0, _lodash.default)(key);
var localOpt = (0, _lodash.default)(options);
this._jwk = {};
this._der = null;
this._oct = {}; // only for EC keys
this._current = {
jwk: false,
der: false,
oct: false
};
if (format === 'jwk') {
this._setJwk(localKey);
} else if (format === 'der' || format === 'pem') {
if (format === 'der' && !(localKey instanceof Uint8Array)) throw new Error('DerKeyMustBeUint8Array');
if (format === 'pem' && typeof localKey !== 'string') throw new Error('PemKeyMustBeString');
this._setAsn1(localKey, format);
} else if (format === 'oct') {
if (typeof localOpt.namedCurve !== 'string') throw new Error('namedCurveMustBeSpecified');
if (!(localKey instanceof Uint8Array)) throw new Error('OctetKeyMustBeUint8Array');
this._setSec1(localKey, localOpt.namedCurve);
} else throw new Error('UnsupportedType');
} ///////////////////////////////////////////////////////////
// private method handling instance variables
// all instance variables must be set via these methods
/**
* Set a key in JWK to the Key object.
* @param {JsonWebKey} jwkey - The Json Web Key.
* @private
*/
(0, _createClass2.default)(Key, [{
key: "_setJwk",
value: function _setJwk(jwkey) {
this._type = (0, _util.getJwkType)(jwkey); // this also check key format
this._jwk = jwkey;
if (this._isEncrypted) this._der = null;
this._isEncrypted = false;
this._setCurrentStatus();
}
/**
* Set a key in DER or PEM to the Key object.
* @param {DER|PEM} asn1key - The DER key byte array or PEM key string.
* @param {String} format - 'der' or 'pem' specifying the format.
* @private
*/
}, {
key: "_setAsn1",
value: function _setAsn1(asn1key, format) {
this._type = (0, _util.isAsn1Public)(asn1key, format) ? 'public' : 'private'; // this also check key format
this._isEncrypted = (0, _util.isAsn1Encrypted)(asn1key, format);
this._der = format === 'pem' ? _jsEncodingUtils.default.formatter.pemToBin(asn1key) : asn1key;
if (this._isEncrypted) {
this._jwk = {};
this._oct = {};
}
this._setCurrentStatus();
}
/**
* Set a key in SEC1 = Octet format to the Key Object.
* @param {OctetEC} sec1key - The Octet SEC1 key byte array.
* @param {String} namedCurve - Name of curve like 'P-256'.
* @private
*/
}, {
key: "_setSec1",
value: function _setSec1(sec1key, namedCurve) {
this._type = (0, _util.getSec1KeyType)(sec1key, namedCurve); // this also check key format
this._oct = {
namedCurve: namedCurve,
key: sec1key
};
if (this._isEncrypted) this._der = null;
this._isEncrypted = false;
this._setCurrentStatus();
}
/**
* Set the current internal status. In particular, manage what the object is based on.
* @private
*/
}, {
key: "_setCurrentStatus",
value: function _setCurrentStatus() {
this._current.jwk = typeof this._jwk.kty === 'string' && (this._jwk.kty === 'RSA' || this._jwk.kty === 'EC');
this._current.der = typeof this._der !== 'undefined' && this._der instanceof Uint8Array && this._der.length > 0;
this._current.oct = typeof this._oct.key !== 'undefined' && this._oct.key instanceof Uint8Array && this._oct.key.length > 0 && typeof this._oct.namedCurve === 'string';
} ///////////////////////////////////////////////////////////
// (pseudo) public methods allowed to be accessed from outside
/**
* Convert the stored key and export the key in desired format.
* Imported key must be basically decrypted except the case where the key is exported as-is.
* @param {String} format - Intended format of exported key. 'jwk', 'pem', 'der' or 'oct'
* @param {KeyExportOptions} [options={}] - Optional arguments.
* @return {Promise<JsonWebKey|PEM|DER|OctetEC>} - Exported key object.
*/
}, {
key: "export",
value: function () {
var _export2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
var format,
options,
jwkey,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
format = _args.length > 0 && _args[0] !== undefined ? _args[0] : 'jwk';
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
if (!(['pem', 'der', 'jwk', 'oct'].indexOf(format) < 0)) {
_context.next = 4;
break;
}
throw new Error('UnsupportedFormat');
case 4:
if (!(this._isEncrypted && this._type === 'private')) {
_context.next = 10;
break;
}
if (!((format === 'der' || format === 'pem') && Object.keys(options).length === 0 && this._current.der)) {
_context.next = 9;
break;
}
return _context.abrupt("return", format === 'pem' ? _jsEncodingUtils.default.formatter.binToPem(this._der, 'encryptedPrivate') : this._der);
case 9:
throw new Error('DecryptionRequired');
case 10:
if (!this._current.jwk) {
_context.next = 14;
break;
}
jwkey = this._jwk;
_context.next = 27;
break;
case 14:
if (!this._current.oct) {
_context.next = 20;
break;
}
_context.next = 17;
return (0, _converter.toJwkFrom)('oct', this._oct.key, {
namedCurve: this._oct.namedCurve
});
case 17:
jwkey = _context.sent;
_context.next = 27;
break;
case 20:
if (!this._current.der) {
_context.next = 26;
break;
}
_context.next = 23;
return (0, _converter.toJwkFrom)('der', this._der);
case 23:
jwkey = _context.sent;
_context.next = 27;
break;
case 26:
throw new Error('InvalidStatus');
case 27:
this._setJwk(jwkey); // store jwk if the exiting private key is not encrypted
// then export as the key in intended format
if (!(format === 'der' || format === 'pem')) {
_context.next = 35;
break;
}
if (typeof options.encryptParams === 'undefined') options.encryptParams = {};
_context.next = 32;
return (0, _converter.fromJwkTo)(format, jwkey, {
outputPublic: options.outputPublic,
compact: options.compact,
//passphrase: options.encryptParams.passphrase,
encryptParams: options.encryptParams
});
case 32:
return _context.abrupt("return", _context.sent);
case 35:
if (!(format === 'oct')) {
_context.next = 41;
break;
}
_context.next = 38;
return (0, _converter.fromJwkTo)(format, jwkey, {
outputPublic: options.outputPublic,
output: options.output,
compact: options.compact
});
case 38:
return _context.abrupt("return", _context.sent);
case 41:
return _context.abrupt("return", jwkey);
case 42:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
function _export() {
return _export2.apply(this, arguments);
}
return _export;
}()
/**
* Encrypt stored key and set the encrypted key to this instance.
* @param {String} passphrase - String passphrase.
* @return {Promise<boolean>} - Always true otherwise thrown.
* @throws {Error} - Throws if AlreadyEncrypted.
*/
}, {
key: "encrypt",
value: function () {
var _encrypt = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(passphrase) {
var options;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (!this._isEncrypted) {
_context2.next = 2;
break;
}
throw new Error('AlreadyEncrypted');
case 2:
options = {
encryptParams: {
passphrase: passphrase
}
};
_context2.t0 = this;
_context2.next = 6;
return this.export('der', options);
case 6:
_context2.t1 = _context2.sent;
_context2.t0._setAsn1.call(_context2.t0, _context2.t1, 'der');
return _context2.abrupt("return", true);
case 9:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function encrypt(_x) {
return _encrypt.apply(this, arguments);
}
return encrypt;
}()
/**
* Decrypted stored key and set the decrypted key in JWK to this instance.
* @param {String} passphrase - String passphrase.
* @return {Promise<boolean>} - Always true otherwise thrown.
* @throws {Error} - Throws if NotEncrypted or FailedToDecrypt.
*/
}, {
key: "decrypt",
value: function () {
var _decrypt = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3(passphrase) {
var jwkey;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
if (this._isEncrypted) {
_context3.next = 2;
break;
}
throw new Error('NotEncrypted');
case 2:
if (!(this._current.der && typeof passphrase === 'string')) {
_context3.next = 8;
break;
}
_context3.next = 5;
return (0, _converter.toJwkFrom)('der', this._der, {
passphrase: passphrase
});
case 5:
jwkey = _context3.sent;
_context3.next = 9;
break;
case 8:
throw new Error('FailedToDecrypt');
case 9:
this._setJwk(jwkey);
return _context3.abrupt("return", true);
case 11:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
function decrypt(_x2) {
return _decrypt.apply(this, arguments);
}
return decrypt;
}()
/**
* Conpute JWK thumbprint specified in RFC7638 {@link https://tools.ietf.org/html/rfc7638}.
* @param {String} [alg='SHA-256'] - Name of hash algorithm for thumbprint computation like 'SHA-256'.
* @param {JwkThumbpirntFormat} [output='binary'] - Output format of JWK thumbprint. 'binary', 'hex' or 'base64'.
* @return {Promise<Uint8Array|String>} - Computed thumbprint.
* @throws {Error} - Throws if DecryptionRequired.
*/
}, {
key: "getJwkThumbprint",
value: function () {
var _getJwkThumbprint2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee4() {
var alg,
output,
_args4 = arguments;
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
alg = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : 'SHA-256';
output = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : 'binary';
if (!this._isEncrypted) {
_context4.next = 4;
break;
}
throw new Error('DecryptionRequired');
case 4:
_context4.t0 = _thumbprint.getJwkThumbprint;
_context4.next = 7;
return this.export('jwk');
case 7:
_context4.t1 = _context4.sent;
_context4.t2 = alg;
_context4.t3 = output;
_context4.next = 12;
return (0, _context4.t0)(_context4.t1, _context4.t2, _context4.t3);
case 12:
return _context4.abrupt("return", _context4.sent);
case 13:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
function getJwkThumbprint() {
return _getJwkThumbprint2.apply(this, arguments);
}
return getJwkThumbprint;
}() // getters
/**
* Get keyType in JWK format
* @return {Promise<String>} - 'RSA' or 'EC'
* @throws {Error} - Throws if DecryptionRequired.
*/
}, {
key: "keyType",
get: function get() {
var _this = this;
if (this._isEncrypted) throw new Error('DecryptionRequired');
return new Promise(
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee5(resolve, reject) {
var jwkey;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return _this.export('jwk').catch(function (e) {
reject(e);
});
case 2:
jwkey = _context5.sent;
resolve(jwkey.kty);
case 4:
case "end":
return _context5.stop();
}
}
}, _callee5);
}));
return function (_x3, _x4) {
return _ref.apply(this, arguments);
};
}());
}
/**
* Get jwkThumbprint of this key.
* @return {Promise<Uint8Array>} - Returns binary thumbprint.
*/
}, {
key: "jwkThumbprint",
get: function get() {
return this.getJwkThumbprint();
}
/**
* Check if this is encrypted.
* @return {boolean}
*/
}, {
key: "isEncrypted",
get: function get() {
return this._isEncrypted;
}
/**
* Check if this is a private key.
* @return {boolean}
*/
}, {
key: "isPrivate",
get: function get() {
return this._type === 'private';
}
/**
* Returns the key in DER format.
* @return {Promise<DER>}
*/
}, {
key: "der",
get: function get() {
return this.export('der');
}
/**
* Returns the key in PEM format.
* @return {Promise<PEM>}
*/
}, {
key: "pem",
get: function get() {
return this.export('pem');
}
/**
* Returns the key in JWK format
* @return {Promise<JsonWebKey>}
*/
}, {
key: "jwk",
get: function get() {
return this.export('jwk');
}
/**
* Returns the 'EC' key in Octet SEC1 format.
* @return {Promise<OctetEC>}
*/
}, {
key: "oct",
get: function get() {
return this.export('oct', {
output: 'string'
});
}
}]);
return Key;
}();
exports.Key = Key;
+118
View File
@@ -0,0 +1,118 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toJwk = exports.fromJwk = void 0;
var _params = _interopRequireDefault(require("./params.js"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _elliptic = _interopRequireDefault(require("elliptic"));
var _util = require("./util.js");
/**
* octenc.js
*/
var Ec = _elliptic.default.ec;
/**
* Convert JWK EC public/private keys to octet form.
* Compressed form of EC public key is referred to RFC 5480 {@link https://tools.ietf.org/html/rfc5480}.
* @param {JsonWebKey} jwkey - A key object in JWK format to be encoded to SEC1 octet format key.
* @param {boolean} [outputPublic] - Export public key even from private key if true.
* @param {OctetFormat} [outputFormat='binary'] - 'binary' or 'string'.
* @param {boolean} [compact=false] - Export compressed form of public key if true.
* @return {JsonWebKey} - Encoded key object in JWK format.
*/
var fromJwk = function fromJwk(jwkey, _ref) {
var outputPublic = _ref.outputPublic,
_ref$outputFormat = _ref.outputFormat,
outputFormat = _ref$outputFormat === void 0 ? 'binary' : _ref$outputFormat,
_ref$compact = _ref.compact,
compact = _ref$compact === void 0 ? false : _ref$compact;
// original key type
var orgType = (0, _util.getJwkType)(jwkey);
var type = typeof outputPublic === 'boolean' && outputPublic ? 'public' : orgType;
if (type === 'public') {
var bufX = _jsEncodingUtils.default.encoder.decodeBase64Url(jwkey.x);
var bufY = _jsEncodingUtils.default.encoder.decodeBase64Url(jwkey.y);
var publicKey;
if (compact) {
// compressed form
// http://www.secg.org/SEC1-Ver-1.0.pdf
publicKey = new Uint8Array(bufX.length + 1);
publicKey[0] = 0xFF & (0x01 & bufY.slice(-1)[0]) + 0x02;
publicKey.set(bufX, 1);
} else {
// uncompressed form
publicKey = new Uint8Array(bufX.length + bufY.length + 1);
publicKey[0] = 0xFF & 0x04;
publicKey.set(bufX, 1);
publicKey.set(bufY, bufX.length + 1);
}
return outputFormat === 'string' ? _jsEncodingUtils.default.encoder.arrayBufferToHexString(publicKey) : publicKey;
} else if (type === 'private') {
if (!jwkey.d) throw new Error('InvalidKey');
var bufD = _jsEncodingUtils.default.encoder.decodeBase64Url(jwkey.d);
return outputFormat === 'string' ? _jsEncodingUtils.default.encoder.arrayBufferToHexString(bufD) : bufD;
}
};
/**
* Convert Octet form of EC public/private keys to JWK.
* @param {String|Uint8Array} octkey - OctetEC key object in hex string format or Uint8Array.
* @param {String} namedCurve - Name of elliptic curve like 'P-256'.
* @param {boolean} [outputPublic] - Export public key even from private key if true.
* @return {JsonWebKey} - Derived key object in JWK format.
*/
exports.fromJwk = fromJwk;
var toJwk = function toJwk(octkey, namedCurve, _ref2) {
var outputPublic = _ref2.outputPublic;
if (Object.keys(_params.default.namedCurves).indexOf(namedCurve) < 0) throw new Error('UnsupportedCurve'); // original key type and check the key structure
var orgType = (0, _util.getSec1KeyType)(octkey, namedCurve);
var type = typeof outputPublic === 'boolean' && outputPublic ? 'public' : orgType; // format conversion
var binKey = typeof octkey === 'string' ? _jsEncodingUtils.default.encoder.hexStringToArrayBuffer(octkey) : octkey; // instantiation
var curve = _params.default.namedCurves[namedCurve].indutnyName;
var ec = new Ec(curve); // derive key object from binary key
var ecKey = orgType === 'public' ? ec.keyFromPublic(binKey) : ec.keyFromPrivate(binKey);
var publicKey = new Uint8Array(ecKey.getPublic('array'));
var len = _params.default.namedCurves[namedCurve].payloadSize;
var bufX = publicKey.slice(1, len + 1);
var bufY = publicKey.slice(len + 1, len * 2 + 1);
var jwKey = {
// https://www.rfc-editor.org/rfc/rfc7518.txt
kty: 'EC',
crv: namedCurve,
x: _jsEncodingUtils.default.encoder.encodeBase64Url(bufX),
// oct to base64url
y: _jsEncodingUtils.default.encoder.encodeBase64Url(bufY) // ext: true
};
if (type === 'private') {
// octkey is exactly private key if type is private.
jwKey.d = _jsEncodingUtils.default.encoder.encodeBase64Url(binKey);
}
return jwKey;
};
exports.toJwk = toJwk;
+157
View File
@@ -0,0 +1,157 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getAlgorithmFromOid = getAlgorithmFromOid;
exports.getAlgorithmFromOidStrict = exports.default = void 0;
/**
* params.js
*/
var _default = {
// oid is referred to rfc5480 https://www.ietf.org/rfc/rfc5480.txt
namedCurves: {
'P-256': {
indutnyName: 'p256',
payloadSize: 32,
oid: [1, 2, 840, 10045, 3, 1, 7]
},
'P-384': {
indutnyName: 'p384',
payloadSize: 48,
oid: [1, 3, 132, 0, 34]
},
'P-521': {
indutnyName: 'p521',
payloadSize: 66,
oid: [1, 3, 132, 0, 35]
},
'P-256K': {
indutnyName: 'secp256k1',
payloadSize: 32,
oid: [1, 3, 132, 0, 10]
}
},
// https://tools.ietf.org/html/rfc3279
publicKeyAlgorithms: {
'EC': {
oid: [1, 2, 840, 10045, 2, 1]
},
'RSA': {
oid: [1, 2, 840, 113549, 1, 1, 1]
}
},
passwordBasedEncryptionSchemes: {
// PBES1
'pbeWithMD5AndDES-CBC': {
oid: [1, 2, 840, 113549, 1, 5, 3],
hash: 'MD5',
encrypt: 'DES-CBC'
},
'pbeWithSHA1AndDES-CBC': {
oid: [1, 2, 840, 113549, 1, 5, 10],
hash: 'SHA-1',
encrypt: 'DES-CBC'
},
// PBES2
'pbes2': {
oid: [1, 2, 840, 113549, 1, 5, 13]
}
},
keyDerivationFunctions: {
'pbkdf2': {
oid: [1, 2, 840, 113549, 1, 5, 12],
defaultSaltLen: 8
}
},
pbkdf2Prfs: {
'hmacWithSHA1': {
oid: [1, 2, 840, 113549, 2, 7],
hash: 'SHA-1'
},
'hmacWithSHA256': {
oid: [1, 2, 840, 113549, 2, 9],
hash: 'SHA-256'
},
'hmacWithSHA384': {
oid: [1, 2, 840, 113549, 2, 10],
hash: 'SHA-384'
},
'hmacWithSHA512': {
oid: [1, 2, 840, 113549, 2, 11],
hash: 'SHA-512'
}
},
encryptionSchemes: {
'des-ede3-cbc': {
oid: [1, 2, 840, 113549, 3, 7],
keyLength: 24,
ivLength: 8
},
'aes128-cbc': {
oid: [2, 16, 840, 1, 101, 3, 4, 1, 2],
keyLength: 16,
ivLength: 16
},
'aes192-cbc': {
oid: [2, 16, 840, 1, 101, 3, 4, 1, 22],
keyLength: 24,
ivLength: 16
},
'aes256-cbc': {
oid: [2, 16, 840, 1, 101, 3, 4, 1, 42],
keyLength: 32,
ivLength: 16
}
},
hashes: {
'SHA-256': {
hashSize: 32
},
'SHA-384': {
hashSize: 48
},
'SHA-512': {
hashSize: 64
},
'SHA-1': {
hashSize: 20
},
// SHOULD NOT USE
'MD5': {
hashSize: 16 // SHOULD NOT USE
}
}
};
/**
* Get algorithm name from ObjectIdentifier array loosely.
* @param {Array} oid - ObjectIdentifier.
* @param {Object} oidDict - Dictionary of ObjectIdentifier.
* @return {Array} - Array of ObjectIdentifier array.
*/
exports.default = _default;
function getAlgorithmFromOid(oid, oidDict) {
return Object.keys(oidDict).filter(function (k) {
return oidDict[k].oid.toString() === oid.toString();
});
}
/**
* Get algorithm name from ObjectIdentifier array strictly.
* @param {Array} oid - ObjectIdentifier.
* @param {Object} dict - Dictionary of ObjectIdentifier.
* @return {Array} - Exactly one ObjectIdentifier.
* @throws {Error} - Throws if UnsupportedAlgorithm.
*/
var getAlgorithmFromOidStrict = function getAlgorithmFromOidStrict(oid, dict) {
var array = getAlgorithmFromOid(oid, dict);
if (array.length === 0) throw new Error('UnsupportedAlgorithm');
return array[0];
};
exports.getAlgorithmFromOidStrict = getAlgorithmFromOidStrict;
+631
View File
@@ -0,0 +1,631 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.decryptEncryptedPrivateKeyInfo = exports.encryptEncryptedPrivateKeyInfo = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _params = _interopRequireWildcard(require("./params.js"));
var _asn1def = require("./asn1def.js");
var _des = _interopRequireDefault(require("des.js"));
var _buffer = _interopRequireDefault(require("buffer"));
var _asn = _interopRequireDefault(require("asn1.js"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _jsCryptoPbkdf = _interopRequireDefault(require("js-crypto-pbkdf"));
var _jsCryptoAes = _interopRequireDefault(require("js-crypto-aes"));
var _jsCryptoRandom = _interopRequireDefault(require("js-crypto-random"));
/**
* rfc8081
*/
var Buffer = _buffer.default.Buffer;
var BN = _asn.default.bignum; ///////////////////////////////////////////////////////////////////
/**
* Generate EncryptedPrivateKeyInfo ASN.1 object.
* @param {DER} binKey - Binary key in DER format.
* @param {AsnEncryptOptionsWithPassphrase} [options={passphrase: ''}] - Encryption options for ASN.1 private key.
* @return {Promise<DER>} - Encrypted private key in DER.
*/
var encryptEncryptedPrivateKeyInfo =
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(binKey) {
var options,
kdfAlgorithm,
encryptedPBES2,
encryptedPBES1,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {
passphrase: ''
};
// default params
if (typeof options.algorithm === 'undefined') options.algorithm = 'pbes2';
if (typeof options.iterationCount === 'undefined') options.iterationCount = 2048;
if (!(options.algorithm === 'pbes2')) {
_context.next = 15;
break;
}
if (typeof options.cipher === 'undefined') options.cipher = 'aes256-cbc';
if (typeof options.prf === 'undefined') options.prf = 'hmacWithSHA256';
kdfAlgorithm = 'pbkdf2'; // TODO: currently only pbkdf2 is available
_context.next = 9;
return encryptPBES2(binKey, options.passphrase, kdfAlgorithm, options.prf, options.iterationCount, options.cipher);
case 9:
encryptedPBES2 = _context.sent;
_context.next = 12;
return encodePBES2(encryptedPBES2);
case 12:
return _context.abrupt("return", _context.sent);
case 15:
_context.next = 17;
return encryptPBES1(binKey, options.passphrase, options.algorithm, options.iterationCount);
case 17:
encryptedPBES1 = _context.sent;
encryptedPBES1.encryptionAlgorithm.algorithm = _params.default.passwordBasedEncryptionSchemes[encryptedPBES1.encryptionAlgorithm.algorithm].oid;
encryptedPBES1.encryptionAlgorithm.parameters = _asn1def.PBEParameter.encode(encryptedPBES1.encryptionAlgorithm.parameters, 'der');
return _context.abrupt("return", _asn1def.EncryptedPrivateKeyInfo.encode(encryptedPBES1, 'der'));
case 21:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function encryptEncryptedPrivateKeyInfo(_x) {
return _ref.apply(this, arguments);
};
}();
/**
* Decrypt EncryptedPrivateKeyInfo
* @param {Object} epki - Parsed encrypted
* @param {String} passphrase - Passphrase to decyrpt the object.
* @return {Promise<Object>} - Decrypted object.
*/
exports.encryptEncryptedPrivateKeyInfo = encryptEncryptedPrivateKeyInfo;
var decryptEncryptedPrivateKeyInfo =
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(epki, passphrase) {
var decoded;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
decoded = {}; // encryptionAlgorithm.algorithm
decoded.encryptionAlgorithm = {
algorithm: (0, _params.getAlgorithmFromOidStrict)(epki.encryptionAlgorithm.algorithm, _params.default.passwordBasedEncryptionSchemes)
};
if (decoded.encryptionAlgorithm.algorithm === 'pbes2') {
decoded.encryptionAlgorithm.parameters = decodePBES2(epki.encryptionAlgorithm.parameters);
} else {
decoded.encryptionAlgorithm.parameters = _asn1def.PBEParameter.decode(epki.encryptionAlgorithm.parameters, 'der');
}
decoded.encryptedData = epki.encryptedData; // decrypt
if (!(decoded.encryptionAlgorithm.algorithm === 'pbes2')) {
_context2.next = 10;
break;
}
_context2.next = 7;
return decryptPBES2(decoded, passphrase);
case 7:
return _context2.abrupt("return", _context2.sent);
case 10:
_context2.next = 12;
return decryptPBES1(decoded, passphrase);
case 12:
return _context2.abrupt("return", _context2.sent);
case 13:
case "end":
return _context2.stop();
}
}
}, _callee2);
}));
return function decryptEncryptedPrivateKeyInfo(_x2, _x3) {
return _ref2.apply(this, arguments);
};
}(); //////////////////////////////
exports.decryptEncryptedPrivateKeyInfo = decryptEncryptedPrivateKeyInfo;
var encodePBES2 = function encodePBES2(decoded) {
var epki = {
encryptionAlgorithm: {}
}; // algorithm
epki.encryptionAlgorithm.algorithm = _params.default.passwordBasedEncryptionSchemes[decoded.encryptionAlgorithm.algorithm].oid; // kdf
var kdf = decoded.encryptionAlgorithm.parameters.keyDerivationFunc;
if (kdf.algorithm === 'pbkdf2') {
kdf.parameters.prf.algorithm = _params.default.pbkdf2Prfs[kdf.parameters.prf.algorithm].oid;
kdf.parameters = _asn1def.PBKDF2Params.encode(kdf.parameters, 'der');
} else throw new Error('UnsupportedKDF');
kdf.algorithm = _params.default.keyDerivationFunctions[kdf.algorithm].oid; // encryptionScheme
var eS = decoded.encryptionAlgorithm.parameters.encryptionScheme;
if (Object.keys(_asn1def.PBES2ESParams).indexOf(eS.algorithm) >= 0) {
eS.parameters = _asn1def.PBES2ESParams[eS.algorithm].encode(eS.parameters, 'der');
} else throw new Error('UnsupportedCipher');
eS.algorithm = _params.default.encryptionSchemes[eS.algorithm].oid; // params
epki.encryptionAlgorithm.parameters = _asn1def.PBES2Params.encode({
keyDerivationFunc: kdf,
encryptionScheme: eS
}, 'der'); // encoded data
epki.encryptedData = decoded.encryptedData;
return _asn1def.EncryptedPrivateKeyInfo.encode(epki, 'der');
};
var decodePBES2 = function decodePBES2(rawParams) {
var pbes2Params = _asn1def.PBES2Params.decode(rawParams, 'der'); // keyDerivationFunc
var kdfAlgorithm = (0, _params.getAlgorithmFromOidStrict)(pbes2Params.keyDerivationFunc.algorithm, _params.default.keyDerivationFunctions);
var iterationCount;
var salt;
var prf;
if (kdfAlgorithm === 'pbkdf2') {
var pbkdf2Params = _asn1def.PBKDF2Params.decode(pbes2Params.keyDerivationFunc.parameters, 'der');
prf = {
algorithm: (0, _params.getAlgorithmFromOidStrict)(pbkdf2Params.prf.algorithm, _params.default.pbkdf2Prfs),
parameters: pbkdf2Params.prf.parameters
};
iterationCount = pbkdf2Params.iterationCount;
salt = {
type: pbkdf2Params.salt.type,
value: pbkdf2Params.salt.value
};
} else throw new Error('UnsupportedKDF'); //encryptionScheme
var encryptionScheme = (0, _params.getAlgorithmFromOidStrict)(pbes2Params.encryptionScheme.algorithm, _params.default.encryptionSchemes);
var encryptionParams;
if (Object.keys(_asn1def.PBES2ESParams).indexOf(encryptionScheme) >= 0) {
encryptionParams = _asn1def.PBES2ESParams[encryptionScheme].decode(pbes2Params.encryptionScheme.parameters, 'der');
} else throw new Error('UnsupportedCipher'); // TODO: Other Encryption Scheme
return {
keyDerivationFunc: {
algorithm: kdfAlgorithm,
parameters: {
salt: salt,
iterationCount: iterationCount,
prf: prf
}
},
encryptionScheme: {
algorithm: encryptionScheme,
parameters: encryptionParams
}
};
}; //////////////////////
// PBES2 RFC8018 Section 6.2.1
var encryptPBES2 =
/*#__PURE__*/
function () {
var _ref3 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3(binKey, passphrase, kdfAlgorithm, prf, iterationCount, cipher) {
var pBuffer, salt, keyLength, key, iv, encryptedData, CBC, ct;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
// kdf
pBuffer = _jsEncodingUtils.default.encoder.stringToArrayBuffer(passphrase);
_context3.next = 3;
return _jsCryptoRandom.default.getRandomBytes(_params.default.keyDerivationFunctions[kdfAlgorithm].defaultSaltLen);
case 3:
salt = _context3.sent;
// TODO: currently only salt length of 8 is available
keyLength = _params.default.encryptionSchemes[cipher].keyLength; // get keyLength
if (!(kdfAlgorithm === 'pbkdf2')) {
_context3.next = 11;
break;
}
_context3.next = 8;
return _jsCryptoPbkdf.default.pbkdf2(pBuffer, salt, iterationCount, keyLength, _params.default.pbkdf2Prfs[prf].hash);
case 8:
key = _context3.sent;
_context3.next = 12;
break;
case 11:
throw new Error('UnsupportedKDF');
case 12:
if (!(cipher === 'des-ede3-cbc')) {
_context3.next = 23;
break;
}
_context3.t0 = Buffer;
_context3.next = 16;
return _jsCryptoRandom.default.getRandomBytes(_params.default.encryptionSchemes[cipher].ivLength);
case 16:
_context3.t1 = _context3.sent;
iv = _context3.t0.from.call(_context3.t0, _context3.t1);
CBC = _des.default.CBC.instantiate(_des.default.EDE);
ct = CBC.create({
type: 'encrypt',
key: Buffer.from(key),
iv: iv
});
encryptedData = Buffer.from(ct.update(binKey).concat(ct.final()));
_context3.next = 36;
break;
case 23:
if (!(cipher === 'aes128-cbc' || cipher === 'aes192-cbc' || cipher === 'aes256-cbc')) {
_context3.next = 35;
break;
}
_context3.next = 26;
return _jsCryptoRandom.default.getRandomBytes(_params.default.encryptionSchemes[cipher].ivLength);
case 26:
iv = _context3.sent;
_context3.t2 = Buffer;
_context3.next = 30;
return _jsCryptoAes.default.encrypt(new Uint8Array(binKey), key, {
name: 'AES-CBC',
iv: iv
});
case 30:
_context3.t3 = _context3.sent;
encryptedData = _context3.t2.from.call(_context3.t2, _context3.t3);
iv = Buffer.from(iv);
_context3.next = 36;
break;
case 35:
throw new Error('UnsupportedCipher');
case 36:
return _context3.abrupt("return", {
encryptedData: encryptedData,
encryptionAlgorithm: {
algorithm: 'pbes2',
parameters: {
keyDerivationFunc: {
algorithm: kdfAlgorithm,
parameters: {
salt: {
type: 'specified',
value: Buffer.from(salt)
},
iterationCount: new BN(iterationCount),
prf: {
algorithm: prf,
parameters: Buffer.from([0x05, 0x00])
}
}
},
encryptionScheme: {
algorithm: cipher,
parameters: iv
}
}
}
});
case 37:
case "end":
return _context3.stop();
}
}
}, _callee3);
}));
return function encryptPBES2(_x4, _x5, _x6, _x7, _x8, _x9) {
return _ref3.apply(this, arguments);
};
}(); //////////////////////////////
// PBES2 RFC8018 Section 6.2.2
var decryptPBES2 =
/*#__PURE__*/
function () {
var _ref4 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee4(decoded, passphrase) {
var kdf, eS, keyLength, key, pBuffer, salt, iterationCount, prf, out, iv, CBC, pt, _iv;
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
kdf = decoded.encryptionAlgorithm.parameters.keyDerivationFunc;
eS = decoded.encryptionAlgorithm.parameters.encryptionScheme; // pbkdf2
keyLength = _params.default.encryptionSchemes[eS.algorithm].keyLength; // get keyLength
if (!(kdf.algorithm === 'pbkdf2')) {
_context4.next = 15;
break;
}
pBuffer = _jsEncodingUtils.default.encoder.stringToArrayBuffer(passphrase);
if (!(kdf.parameters.salt.type !== 'specified')) {
_context4.next = 7;
break;
}
throw new Error('UnsupportedSaltSource');
case 7:
salt = new Uint8Array(kdf.parameters.salt.value);
iterationCount = kdf.parameters.iterationCount.toNumber();
prf = kdf.parameters.prf.algorithm;
_context4.next = 12;
return _jsCryptoPbkdf.default.pbkdf2(pBuffer, salt, iterationCount, keyLength, _params.default.pbkdf2Prfs[prf].hash);
case 12:
key = _context4.sent;
_context4.next = 16;
break;
case 15:
throw new Error('UnsupportedKDF');
case 16:
if (!(eS.algorithm === 'des-ede3-cbc')) {
_context4.next = 23;
break;
}
iv = eS.parameters;
CBC = _des.default.CBC.instantiate(_des.default.EDE);
pt = CBC.create({
type: 'decrypt',
key: key,
iv: iv
});
out = Buffer.from(pt.update(decoded.encryptedData).concat(pt.final()));
_context4.next = 33;
break;
case 23:
if (!(eS.algorithm === 'aes128-cbc' || eS.algorithm === 'aes192-cbc' || eS.algorithm === 'aes256-cbc')) {
_context4.next = 32;
break;
}
_iv = new Uint8Array(eS.parameters);
_context4.t0 = Buffer;
_context4.next = 28;
return _jsCryptoAes.default.decrypt(new Uint8Array(decoded.encryptedData), key, {
name: 'AES-CBC',
iv: _iv
});
case 28:
_context4.t1 = _context4.sent;
out = _context4.t0.from.call(_context4.t0, _context4.t1);
_context4.next = 33;
break;
case 32:
throw new Error('UnsupportedEncryptionAlgorithm');
case 33:
return _context4.abrupt("return", _asn1def.OneAsymmetricKey.decode(out, 'der'));
case 34:
case "end":
return _context4.stop();
}
}
}, _callee4);
}));
return function decryptPBES2(_x10, _x11) {
return _ref4.apply(this, arguments);
};
}(); //////////////////////////////
// PBES1 RFC8018 Section 6.1.1
var encryptPBES1 =
/*#__PURE__*/
function () {
var _ref5 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee5(binKey, passphrase, algorithm, iterationCount) {
var pBuffer, salt, hash, keyIv, key, iv, encrypt, out, CBC, ct;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
// pbkdf1
pBuffer = _jsEncodingUtils.default.encoder.stringToArrayBuffer(passphrase);
_context5.next = 3;
return _jsCryptoRandom.default.getRandomBytes(8);
case 3:
salt = _context5.sent;
// defined as 8 octet
hash = _params.default.passwordBasedEncryptionSchemes[algorithm].hash;
_context5.next = 7;
return _jsCryptoPbkdf.default.pbkdf1(pBuffer, salt, iterationCount, 16, hash);
case 7:
keyIv = _context5.sent;
key = keyIv.slice(0, 8);
iv = keyIv.slice(8, 16); // decryption
encrypt = _params.default.passwordBasedEncryptionSchemes[algorithm].encrypt;
if (!(encrypt === 'DES-CBC')) {
_context5.next = 17;
break;
}
CBC = _des.default.CBC.instantiate(_des.default.DES);
ct = CBC.create({
type: 'encrypt',
key: key,
iv: iv
});
out = Buffer.from(ct.update(binKey).concat(ct.final()));
_context5.next = 18;
break;
case 17:
throw new Error('UnsupportedEncryptionAlgorithm');
case 18:
return _context5.abrupt("return", {
encryptionAlgorithm: {
algorithm: algorithm,
parameters: {
salt: Buffer.from(salt),
iterationCount: new BN(iterationCount)
}
},
encryptedData: out
});
case 19:
case "end":
return _context5.stop();
}
}
}, _callee5);
}));
return function encryptPBES1(_x12, _x13, _x14, _x15) {
return _ref5.apply(this, arguments);
};
}(); //////////////////////////////
// PBES1 RFC8018 Section 6.1.2
var decryptPBES1 =
/*#__PURE__*/
function () {
var _ref6 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee6(decoded, passphrase) {
var pBuffer, salt, hash, iterationCount, keyIv, key, iv, encrypt, out, CBC, ct;
return _regenerator.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
// pbkdf1
pBuffer = _jsEncodingUtils.default.encoder.stringToArrayBuffer(passphrase);
salt = new Uint8Array(decoded.encryptionAlgorithm.parameters.salt);
hash = _params.default.passwordBasedEncryptionSchemes[decoded.encryptionAlgorithm.algorithm].hash;
iterationCount = decoded.encryptionAlgorithm.parameters.iterationCount.toNumber();
_context6.next = 6;
return _jsCryptoPbkdf.default.pbkdf1(pBuffer, salt, iterationCount, 16, hash);
case 6:
keyIv = _context6.sent;
key = keyIv.slice(0, 8);
iv = keyIv.slice(8, 16); // decryption
encrypt = _params.default.passwordBasedEncryptionSchemes[decoded.encryptionAlgorithm.algorithm].encrypt;
if (!(encrypt === 'DES-CBC')) {
_context6.next = 16;
break;
}
CBC = _des.default.CBC.instantiate(_des.default.DES);
ct = CBC.create({
type: 'decrypt',
key: key,
iv: iv
});
out = Buffer.from(ct.update(decoded.encryptedData).concat(ct.final()));
_context6.next = 17;
break;
case 16:
throw new Error('UnsupportedEncryptionAlgorithm');
case 17:
return _context6.abrupt("return", _asn1def.OneAsymmetricKey.decode(out, 'der'));
case 18:
case "end":
return _context6.stop();
}
}
}, _callee6);
}));
return function decryptPBES1(_x16, _x17) {
return _ref6.apply(this, arguments);
};
}();
+135
View File
@@ -0,0 +1,135 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getJwkThumbprint = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _jsCryptoHash = _interopRequireDefault(require("js-crypto-hash"));
var _buffer = _interopRequireDefault(require("buffer"));
/**
* thumbprint.js
*/
var Buffer = _buffer.default.Buffer;
/**
* Compute JWK public key thumbprint specified in RFC7638
* https://tools.ietf.org/html/rfc7638
* @param {JsonWebKey} jwkey - A key object in JWK format
* @param {String} [alg='SHA-256'] - Name of hash algorithm to compute the thumbprint.
* @param {JwkThumbpirntFormat} [output='binary'] - Output format, 'binary', 'hex' or 'base64'
* @return {Promise<String|Uint8Array>} - The computed JWK thumbprint.
*/
var getJwkThumbprint =
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(jwkey) {
var alg,
output,
jsonString,
uint8json,
thumbPrintBuf,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
alg = _args.length > 1 && _args[1] !== undefined ? _args[1] : 'SHA-256';
output = _args.length > 2 && _args[2] !== undefined ? _args[2] : 'binary';
if (!(['hex', 'binary'].indexOf(output) < 0)) {
_context.next = 4;
break;
}
throw new Error('UnsupportedOutputFormat');
case 4:
if (!(jwkey.kty === 'EC')) {
_context.next = 8;
break;
}
jsonString = JSON.stringify({
crv: jwkey.crv,
kty: jwkey.kty,
x: jwkey.x,
y: jwkey.y
});
_context.next = 13;
break;
case 8:
if (!(jwkey.kty === 'RSA')) {
_context.next = 12;
break;
}
jsonString = JSON.stringify({
e: jwkey.e,
kty: jwkey.kty,
n: jwkey.n
});
_context.next = 13;
break;
case 12:
throw new Error('UnsupportedKeyType');
case 13:
uint8json = new Uint8Array(Buffer.from(jsonString, 'utf8'));
_context.next = 16;
return _jsCryptoHash.default.compute(uint8json, alg);
case 16:
thumbPrintBuf = _context.sent;
if (!(output === 'hex')) {
_context.next = 21;
break;
}
return _context.abrupt("return", _jsEncodingUtils.default.encoder.arrayBufferToHexString(thumbPrintBuf));
case 21:
if (!(output === 'base64')) {
_context.next = 25;
break;
}
return _context.abrupt("return", _jsEncodingUtils.default.encoder.encodeBase64(thumbPrintBuf));
case 25:
if (!(output === 'binary')) {
_context.next = 27;
break;
}
return _context.abrupt("return", thumbPrintBuf);
case 27:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function getJwkThumbprint(_x) {
return _ref.apply(this, arguments);
};
}();
exports.getJwkThumbprint = getJwkThumbprint;
+56
View File
@@ -0,0 +1,56 @@
/**
* @typedef {String} PEM - ASN.1 encoded key in PEM format.
*/
/**
* @typedef {Uint8Array|Buffer} DER - ASN.1 encoded key in DER format.
*/
/**
* @typedef {Uint8Array|Buffer|String} OctetEC - SEC1 Octet form EC key.
*/
/**
* @typedef {Object} KeyExportOptions - Export options for Key Class.
* @property {boolean} [outputPublic] - Derive public key from private key if true.
* @property {boolean} [compact] - Generate compressed EC public key when format = 'der', 'pem' or 'oct', only for EC key if true.
* @property {OctetFormat} [output='binary'] - Active only for OctetEC key. 'binary' or 'string'. Default value would be 'binary'.
* @property {AsnEncryptOptionsWithPassphrase} [encryptParams] - Generate encrypted der/pem private key when format = 'der' or 'pem'.
*/
/**
* @typedef {Object} JwkExportOptionsInternal - Options for converters to JWK.
* @property {String} [namedCurve] - Name of curve used for EC keys.
* @property {boolean} [outputPublic] - Export public key even from private key if true.
* @property {String} [passphrase] - Encrypt private key if this is given.
*/
/**
* @typedef {Object} AsnEncryptOptionsWithPassphrase - Encryption options for exported key in key Class.
* @property {String} passphrase - (Re-)generate encrypted der/pem with the given passphrase
* @property {String} [algorithm='pbes2'] - 'pbes2' (default), 'pbeWithMD5AndDES-CBC' or 'pbeWithSHA1AndDES'
* @property {String} [prf='hmacWithSHA256] - 'hmacWithSHA256' (default), 'hmacWithSHA384', 'hmacWithSHA512' or 'hmacWithSHA1' when if algorithm = 'pbes2'.
* @property {Number} [iterationCount = 2048] - Iteration count for PBKDF 1/2.
* @property {String} [cipher='aes256-cbc'] - 'aes256-cbc' (default), 'aes128-cbc' or 'des-ede3-cbc'.
*/
/**
* @typedef {Entity} AsnObject - asn1.js Entity object.
*/
/**
* @typedef {'pem'|'der'} AsnFormat - Key format of ASN.1 encoded key object.
*/
/**
* @typedef {'string'|'binary'} OctetFormat - Representation of SEC1 Octet EC key.
*/
/**
* @typedef {'public'|'private'} PublicOrPrivate - Key type of public or private.
*/
/**
* @typedef {'binary'|'hex'|'base64'} JwkThumbpirntFormat - Representation of JWK thumbprint.
*/
"use strict";
+161
View File
@@ -0,0 +1,161 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.appendLeadingZeros = exports.pruneLeadingZeros = exports.getJwkType = exports.getSec1KeyType = exports.getAsn1KeyType = exports.isAsn1Public = exports.isAsn1Encrypted = void 0;
var _jsEncodingUtils = _interopRequireDefault(require("js-encoding-utils"));
var _params = _interopRequireDefault(require("./params.js"));
var _asn1def = require("./asn1def.js");
/**
* util.js
*/
/**
* Check if the given key is encrypted.
* @param {DER|PEM} key - Private key object in ASN.1 encoding.
* @param {AsnFormat} [format='pem'] - pem or der
* @return {boolean} - True if encrypted.
*/
var isAsn1Encrypted = function isAsn1Encrypted(key) {
var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'pem';
var keyType;
try {
keyType = getAsn1KeyType(key, format);
} catch (e) {
return false;
}
return keyType === 'encryptedPrivate';
};
/**
* Check if the given key is public.
* @param {DER|PEM} key - Public key object in ASN.1 encoding.
* @param {AsnFormat} format - pem or der
* @return {boolean} - True if public.
*/
exports.isAsn1Encrypted = isAsn1Encrypted;
var isAsn1Public = function isAsn1Public(key) {
var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'pem';
var keyType;
try {
keyType = getAsn1KeyType(key, format);
} catch (e) {
return false;
}
return keyType === 'public';
};
/**
* Retrieve the key type of public or private in ASN.1 format
* @param {DER|PEM} key - Key object in ASN.1 encoding.
* @param {AsnFormat} format - pem or der
* @return {'public'|'private'|'encryptedPrivate'} - The key type of the given key.
* @throws {Error} - Throws if NotSpkiNorPkcs8Key.
*/
exports.isAsn1Public = isAsn1Public;
var getAsn1KeyType = function getAsn1KeyType(key) {
var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'pem';
// Peel the pem strings
var binKey = format === 'pem' ? _jsEncodingUtils.default.formatter.pemToBin(key, 'private') : key;
var decoded = _asn1def.KeyStructure.decode(Buffer.from(binKey), 'der');
if (decoded.type === 'encryptedPrivateKeyInfo') return 'encryptedPrivate';else if (decoded.type === 'oneAsymmetricKey') return 'private';else if (decoded.type === 'subjectPublicKeyInfo') return 'public';else throw new Error('NotSpkiNorPkcs8Key');
};
/**
* Retrieve the type of SEC1 octet key.
* @param {OctetEC} sec1key - Key object in OctetEC encoding in String (hex string) or Uint8Array.
* @param {String} namedCurve - Name of elliptic curve like 'P-256'.
* @return {PublicOrPrivate} - public or private
* @throws {Error} - Throws if UnsupportedKeyStructure.
*/
exports.getAsn1KeyType = getAsn1KeyType;
var getSec1KeyType = function getSec1KeyType(sec1key, namedCurve) {
var format;
if (sec1key instanceof Uint8Array) format = 'binary';else if (typeof sec1key === 'string') format = 'string';else throw new Error('InvalidObjectType');
var binKey = format === 'string' ? _jsEncodingUtils.default.encoder.hexStringToArrayBuffer(sec1key) : sec1key;
var len = _params.default.namedCurves[namedCurve].payloadSize; // original key type
if (binKey.length <= len) return 'private';else if (binKey.length === 2 * len + 1 && binKey[0] === 0x04 || binKey.length === len + 1 && (binKey[0] === 0x02 || binKey[0] === 0x03)) return 'public';else throw new Error('UnsupportedKeyStructure');
};
/**
* Check key type of JWK.
* @param {JsonWebKey} jwkey - Key object in JWK format.
* @return {PublicOrPrivate} - public or private
* @throws {Error} - Throws if InvalidECKey, InvalidRSAKey or UnsupportedJWKType.
*/
exports.getSec1KeyType = getSec1KeyType;
var getJwkType = function getJwkType(jwkey) {
if (jwkey.kty === 'EC') {
if (jwkey.x && jwkey.y && jwkey.d) return 'private';else if (jwkey.x && jwkey.y) return 'public';else throw new Error('InvalidECKey');
} else if (jwkey.kty === 'RSA') {
if (jwkey.n && jwkey.e && jwkey.d && jwkey.p && jwkey.q && jwkey.dp && jwkey.dq && jwkey.qi) return 'private';else if (jwkey.n && jwkey.e) return 'public';else throw new Error('InvalidRSAKey');
} else throw new Error('UnsupportedJWKType');
};
/**
* Prune leading zeros of an octet sequence in Uint8Array for jwk formatting of RSA.
* https://tools.ietf.org/html/rfc7518#section-6.3
* @param {Uint8Array} array - The octet sequence.
* @return {Uint8Array} - An octet sequence pruned leading zeros of length equal to or shorter than the input array.
* @throws {Error} - Throws if NonUint8Array.
*/
exports.getJwkType = getJwkType;
var pruneLeadingZeros = function pruneLeadingZeros(array) {
if (!(array instanceof Uint8Array)) throw new Error('NonUint8Array');
var offset = 0;
for (var i = 0; i < array.length; i++) {
if (array[i] !== 0x00) break;
offset++;
}
var returnArray = new Uint8Array(array.length - offset);
returnArray.set(array.slice(offset, array.length));
return returnArray;
}; // for pem/oct/der formatting from jwk of RSA
/**
* Append leading zeros and generate an octet sequence of fixed length.
* @param {Uint8Array} array - An octet sequence.
* @param {Number} len - Intended length of output sequence.
* @returns {Uint8Array} - An octet sequence with leading zeros.
* @throws {Error} - Throws if NonUint8Array or InvalidLength.
*/
exports.pruneLeadingZeros = pruneLeadingZeros;
var appendLeadingZeros = function appendLeadingZeros(array, len) {
if (!(array instanceof Uint8Array)) throw new Error('NonUint8Array');
if (array.length > len) throw new Error('InvalidLength');
var returnArray = new Uint8Array(len); // initialized with zeros
returnArray.set(array, len - array.length);
return returnArray;
};
exports.appendLeadingZeros = appendLeadingZeros;