456 lines
14 KiB
JavaScript
456 lines
14 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.deriveSecret = exports.verify = exports.sign = exports.generateKey = void 0;
|
|
|
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
|
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
|
|
var util = _interopRequireWildcard(require("js-crypto-env"));
|
|
|
|
var webapi = _interopRequireWildcard(require("./webapi.js"));
|
|
|
|
var nodeapi = _interopRequireWildcard(require("./nodeapi.js"));
|
|
|
|
var purejs = _interopRequireWildcard(require("./purejs.js"));
|
|
|
|
/**
|
|
* ec.js
|
|
*/
|
|
|
|
/**
|
|
* Generate elliptic curve cryptography public/private key pair. Generated keys are in JWK.
|
|
* @param {String} [namedCurve='P-256'] - Name of curve like 'P-256'.
|
|
* @return {Promise<{publicKey: JsonWebKey, privateKey: JsonWebKey }>} - The generated keys.
|
|
* @throws {Error} - Throws if UnsupportedEnvironment, i.e., neither WebCrypto, NodeCrypto, nor PureJS codes works.
|
|
*/
|
|
var generateKey =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee() {
|
|
var namedCurve,
|
|
webCrypto,
|
|
nodeCrypto,
|
|
native,
|
|
errMsg,
|
|
keyPair,
|
|
_args = arguments;
|
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
while (1) {
|
|
switch (_context.prev = _context.next) {
|
|
case 0:
|
|
namedCurve = _args.length > 0 && _args[0] !== undefined ? _args[0] : 'P-256';
|
|
webCrypto = util.getWebCrypto(); // web crypto api
|
|
|
|
nodeCrypto = util.getNodeCrypto(); // implementation on node.js
|
|
|
|
native = true;
|
|
keyPair = {};
|
|
|
|
if (!(typeof webCrypto !== 'undefined' && typeof webCrypto.generateKey === 'function' && typeof webCrypto.exportKey === 'function')) {
|
|
_context.next = 11;
|
|
break;
|
|
}
|
|
|
|
_context.next = 8;
|
|
return webapi.generateKey(namedCurve, webCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 8:
|
|
keyPair = _context.sent;
|
|
_context.next = 18;
|
|
break;
|
|
|
|
case 11:
|
|
if (!(typeof nodeCrypto !== 'undefined')) {
|
|
_context.next = 17;
|
|
break;
|
|
}
|
|
|
|
_context.next = 14;
|
|
return nodeapi.generateKey(namedCurve, nodeCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 14:
|
|
keyPair = _context.sent;
|
|
_context.next = 18;
|
|
break;
|
|
|
|
case 17:
|
|
native = false;
|
|
|
|
case 18:
|
|
if (!(native === false)) {
|
|
_context.next = 22;
|
|
break;
|
|
}
|
|
|
|
_context.next = 21;
|
|
return purejs.generateKey(namedCurve).catch(function (e) {
|
|
errMsg = "".concat(errMsg, " => ").concat(e.message);
|
|
throw new Error("UnsupportedEnvironment: ".concat(errMsg));
|
|
});
|
|
|
|
case 21:
|
|
keyPair = _context.sent;
|
|
|
|
case 22:
|
|
return _context.abrupt("return", keyPair);
|
|
|
|
case 23:
|
|
case "end":
|
|
return _context.stop();
|
|
}
|
|
}
|
|
}, _callee);
|
|
}));
|
|
|
|
return function generateKey() {
|
|
return _ref.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* Sign message with ECDSA.
|
|
* @param {Uint8Array} msg - Byte array of message to be signed.
|
|
* @param {JsonWebKey} privateJwk - Private key object in JWK format.
|
|
* @param {String} [hash='SHA-256'] - Name of hash algorithm used in singing, like 'SHA-256'.
|
|
* @param {String} [signatureFormat='raw'] - Signature format. 'raw' indicates the purely raw byte array of signature. It can also take 'der', and then the output is ASN.1 DER formatted.
|
|
* @return {Promise<Uint8Array>} - Output signature byte array in raw or der format.
|
|
* @throws {Error} - Throws if UnsupportedEnvironment, i.e., neither WebCrypto, NodeCrypto, nor PureJS codes works.
|
|
*/
|
|
|
|
|
|
exports.generateKey = generateKey;
|
|
|
|
var sign =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref2 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee2(msg, privateJwk) {
|
|
var hash,
|
|
signatureFormat,
|
|
webCrypto,
|
|
nodeCrypto,
|
|
native,
|
|
errMsg,
|
|
signature,
|
|
_args2 = arguments;
|
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
while (1) {
|
|
switch (_context2.prev = _context2.next) {
|
|
case 0:
|
|
hash = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : 'SHA-256';
|
|
signatureFormat = _args2.length > 3 && _args2[3] !== undefined ? _args2[3] : 'raw';
|
|
|
|
if (!(signatureFormat !== 'raw' && signatureFormat !== 'der')) {
|
|
_context2.next = 4;
|
|
break;
|
|
}
|
|
|
|
throw new Error('InvalidSignatureFormat');
|
|
|
|
case 4:
|
|
webCrypto = util.getWebCrypto(); // web crypto api
|
|
|
|
nodeCrypto = util.getNodeCrypto(); // implementation on node.js
|
|
|
|
native = true;
|
|
|
|
if (!(typeof webCrypto !== 'undefined' && typeof webCrypto.importKey === 'function' && typeof webCrypto.sign === 'function')) {
|
|
_context2.next = 13;
|
|
break;
|
|
}
|
|
|
|
_context2.next = 10;
|
|
return webapi.sign(msg, privateJwk, hash, signatureFormat, webCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 10:
|
|
signature = _context2.sent;
|
|
_context2.next = 20;
|
|
break;
|
|
|
|
case 13:
|
|
if (!(typeof nodeCrypto !== 'undefined')) {
|
|
_context2.next = 19;
|
|
break;
|
|
}
|
|
|
|
_context2.next = 16;
|
|
return nodeapi.sign(msg, privateJwk, hash, signatureFormat, nodeCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 16:
|
|
signature = _context2.sent;
|
|
_context2.next = 20;
|
|
break;
|
|
|
|
case 19:
|
|
native = false;
|
|
|
|
case 20:
|
|
if (!(native === false)) {
|
|
_context2.next = 24;
|
|
break;
|
|
}
|
|
|
|
_context2.next = 23;
|
|
return purejs.sign(msg, privateJwk, hash, signatureFormat).catch(function (e) {
|
|
errMsg = "".concat(errMsg, " => ").concat(e.message);
|
|
throw new Error("UnsupportedEnvironment: ".concat(errMsg));
|
|
});
|
|
|
|
case 23:
|
|
signature = _context2.sent;
|
|
|
|
case 24:
|
|
return _context2.abrupt("return", signature);
|
|
|
|
case 25:
|
|
case "end":
|
|
return _context2.stop();
|
|
}
|
|
}
|
|
}, _callee2);
|
|
}));
|
|
|
|
return function sign(_x, _x2) {
|
|
return _ref2.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* Verify signature with ECDSA.
|
|
* @param {Uint8Array} msg - Byte array of message that have been signed.
|
|
* @param {Uint8Array} signature - Byte array of signature for the given message.
|
|
* @param {JsonWebKey} publicJwk - Public key object in JWK format.
|
|
* @param {String} [hash='SHA-256'] - Name of hash algorithm used in singing, like 'SHA-256'.
|
|
* @param {String} [signatureFormat='raw'] - Signature format. 'raw' indicates the purely raw byte array of signature. It can also take 'der', and then the input must be in ASN.1 DER format.
|
|
* @return {Promise<boolean>} - The result of verification.
|
|
* @throws {Error} - Throws if UnsupportedEnvironment, i.e., neither WebCrypto, NodeCrypto, nor PureJS codes works.
|
|
*/
|
|
|
|
|
|
exports.sign = sign;
|
|
|
|
var verify =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref3 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee3(msg, signature, publicJwk) {
|
|
var hash,
|
|
signatureFormat,
|
|
webCrypto,
|
|
nodeCrypto,
|
|
native,
|
|
errMsg,
|
|
valid,
|
|
_args3 = arguments;
|
|
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
while (1) {
|
|
switch (_context3.prev = _context3.next) {
|
|
case 0:
|
|
hash = _args3.length > 3 && _args3[3] !== undefined ? _args3[3] : 'SHA-256';
|
|
signatureFormat = _args3.length > 4 && _args3[4] !== undefined ? _args3[4] : 'raw';
|
|
|
|
if (!(signatureFormat !== 'raw' && signatureFormat !== 'der')) {
|
|
_context3.next = 4;
|
|
break;
|
|
}
|
|
|
|
throw new Error('InvalidSignatureFormat');
|
|
|
|
case 4:
|
|
webCrypto = util.getWebCrypto(); // web crypto api
|
|
|
|
nodeCrypto = util.getNodeCrypto(); // implementation on node.js
|
|
|
|
native = true;
|
|
|
|
if (!(typeof webCrypto !== 'undefined' && typeof webCrypto.importKey === 'function' && typeof webCrypto.verify === 'function')) {
|
|
_context3.next = 13;
|
|
break;
|
|
}
|
|
|
|
_context3.next = 10;
|
|
return webapi.verify(msg, signature, publicJwk, hash, signatureFormat, webCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 10:
|
|
valid = _context3.sent;
|
|
_context3.next = 20;
|
|
break;
|
|
|
|
case 13:
|
|
if (!(typeof nodeCrypto !== 'undefined')) {
|
|
_context3.next = 19;
|
|
break;
|
|
}
|
|
|
|
_context3.next = 16;
|
|
return nodeapi.verify(msg, signature, publicJwk, hash, signatureFormat, nodeCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 16:
|
|
valid = _context3.sent;
|
|
_context3.next = 20;
|
|
break;
|
|
|
|
case 19:
|
|
native = false;
|
|
|
|
case 20:
|
|
if (!(native === false)) {
|
|
_context3.next = 24;
|
|
break;
|
|
}
|
|
|
|
_context3.next = 23;
|
|
return purejs.verify(msg, signature, publicJwk, hash, signatureFormat).catch(function (e) {
|
|
errMsg = "".concat(errMsg, " => ").concat(e.message);
|
|
throw new Error("UnsupportedEnvironment: ".concat(errMsg));
|
|
});
|
|
|
|
case 23:
|
|
valid = _context3.sent;
|
|
|
|
case 24:
|
|
return _context3.abrupt("return", valid);
|
|
|
|
case 25:
|
|
case "end":
|
|
return _context3.stop();
|
|
}
|
|
}
|
|
}, _callee3);
|
|
}));
|
|
|
|
return function verify(_x3, _x4, _x5) {
|
|
return _ref3.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* ECDH: Elliptic Curve Diffie-Hellman Key Exchange, which derives shared secret from my private key and destination's public key.
|
|
* **NOTE** We SHOULD NOT use the derived secret as an encryption key directly.
|
|
* We should employ an appropriate key derivation procedure like HKDF to use the secret for symmetric key encryption.
|
|
* @param {JsonWebKey} publicJwk - Remote public key object in JWK format.
|
|
* @param {JsonWebKey} privateJwk - Local (my) private key object in JWK format.
|
|
* @return {Promise<Uint8Array>} - The derived master secret via ECDH.
|
|
* @throws {Error} - Throws if UnsupportedEnvironment, i.e., neither WebCrypto, NodeCrypto, nor PureJS codes works.
|
|
*/
|
|
|
|
|
|
exports.verify = verify;
|
|
|
|
var deriveSecret =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref4 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee4(publicJwk, privateJwk) {
|
|
var webCrypto, nodeCrypto, native, errMsg, secret;
|
|
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
while (1) {
|
|
switch (_context4.prev = _context4.next) {
|
|
case 0:
|
|
if (!(publicJwk.crv !== privateJwk.crv)) {
|
|
_context4.next = 2;
|
|
break;
|
|
}
|
|
|
|
throw new Error('UnmatchedCurveName');
|
|
|
|
case 2:
|
|
webCrypto = util.getWebCrypto(); // web crypto api
|
|
|
|
nodeCrypto = util.getNodeCrypto(); // implementation on node.js
|
|
|
|
native = true;
|
|
|
|
if (!(typeof webCrypto !== 'undefined' && typeof webCrypto.importKey === 'function' && typeof webCrypto.deriveBits === 'function')) {
|
|
_context4.next = 11;
|
|
break;
|
|
}
|
|
|
|
_context4.next = 8;
|
|
return webapi.deriveSecret(publicJwk, privateJwk, webCrypto).catch(function (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
});
|
|
|
|
case 8:
|
|
secret = _context4.sent;
|
|
_context4.next = 12;
|
|
break;
|
|
|
|
case 11:
|
|
if (typeof nodeCrypto !== 'undefined') {
|
|
// for node
|
|
try {
|
|
secret = nodeapi.deriveSecret(publicJwk, privateJwk, nodeCrypto);
|
|
} catch (e) {
|
|
errMsg = e.message;
|
|
native = false;
|
|
}
|
|
} else native = false;
|
|
|
|
case 12:
|
|
if (!(native === false)) {
|
|
_context4.next = 23;
|
|
break;
|
|
}
|
|
|
|
_context4.prev = 13;
|
|
_context4.next = 16;
|
|
return purejs.deriveSecret(publicJwk, privateJwk);
|
|
|
|
case 16:
|
|
secret = _context4.sent;
|
|
_context4.next = 23;
|
|
break;
|
|
|
|
case 19:
|
|
_context4.prev = 19;
|
|
_context4.t0 = _context4["catch"](13);
|
|
errMsg = "".concat(errMsg, " => ").concat(_context4.t0.message);
|
|
throw new Error("UnsupportedEnvironment: ".concat(errMsg));
|
|
|
|
case 23:
|
|
return _context4.abrupt("return", secret);
|
|
|
|
case 24:
|
|
case "end":
|
|
return _context4.stop();
|
|
}
|
|
}
|
|
}, _callee4, null, [[13, 19]]);
|
|
}));
|
|
|
|
return function deriveSecret(_x6, _x7) {
|
|
return _ref4.apply(this, arguments);
|
|
};
|
|
}();
|
|
|
|
exports.deriveSecret = deriveSecret; |