forked from daren.hsu/line_push
501 lines
15 KiB
JavaScript
501 lines
15 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.decrypt = exports.encrypt = exports.unwrapKey = exports.wrapKey = void 0;
|
|
|
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
|
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
|
|
/**
|
|
* webapi.js
|
|
*/
|
|
|
|
/**
|
|
* WebCrypto KeyWrapping function simply uses encrypt function.
|
|
* @param keyToBeWrapped {Uint8Array} - plaintext key
|
|
* @param wrappingKey {Uint8Array} - wrapping key
|
|
* @param name {string} - 'AES-KW'
|
|
* @param iv {Uint8Array} - default is '0xA6A6A6A6A6A6A6A6'
|
|
* @param nodeCrypto {Object} - crypto.subtle object
|
|
* @return {Uint8Array} - Unwrapped Key
|
|
*/
|
|
var wrapKey =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref2 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee(keyToBeWrapped, wrappingKey, _ref, webCrypto) {
|
|
var _ref$name, name, iv, kek, cek, data;
|
|
|
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
while (1) {
|
|
switch (_context.prev = _context.next) {
|
|
case 0:
|
|
_ref$name = _ref.name, name = _ref$name === void 0 ? 'AES-KW' : _ref$name, iv = _ref.iv;
|
|
|
|
if (!(typeof window.msCrypto === 'undefined')) {
|
|
_context.next = 20;
|
|
break;
|
|
}
|
|
|
|
_context.prev = 2;
|
|
_context.next = 5;
|
|
return webCrypto.importKey('raw', wrappingKey, {
|
|
name: name
|
|
}, false, ['wrapKey', 'unwrapKey']);
|
|
|
|
case 5:
|
|
kek = _context.sent;
|
|
_context.next = 8;
|
|
return webCrypto.importKey('raw', keyToBeWrapped, {
|
|
name: name
|
|
}, true, ['wrapKey', 'unwrapKey']);
|
|
|
|
case 8:
|
|
cek = _context.sent;
|
|
_context.next = 11;
|
|
return webCrypto.wrapKey('raw', cek, kek, {
|
|
name: name,
|
|
iv: iv
|
|
});
|
|
|
|
case 11:
|
|
data = _context.sent;
|
|
return _context.abrupt("return", new Uint8Array(data));
|
|
|
|
case 15:
|
|
_context.prev = 15;
|
|
_context.t0 = _context["catch"](2);
|
|
throw new Error("WebCrypto_FailedToWrapKey - ".concat(_context.t0.message));
|
|
|
|
case 18:
|
|
_context.next = 21;
|
|
break;
|
|
|
|
case 20:
|
|
throw new Error('ThrowAwayIeAsap');
|
|
|
|
case 21:
|
|
case "end":
|
|
return _context.stop();
|
|
}
|
|
}
|
|
}, _callee, null, [[2, 15]]);
|
|
}));
|
|
|
|
return function wrapKey(_x, _x2, _x3, _x4) {
|
|
return _ref2.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* WebCrypto KeyUnwrapping function as well as keyWrapping
|
|
* @param wrappedKey {Uint8Array} - Wrapped key
|
|
* @param unwrappingKey {Uint8Array} - Key used for wrapping
|
|
* @param name {string} - 'AES-KW'
|
|
* @param iv {Uint8Array} - default is '0xA6A6A6A6A6A6A6A6'
|
|
* @param nodeCrypto {Object} - crypto.subtle object
|
|
* @return {Uint8Array} - Unwrapped Key
|
|
*/
|
|
|
|
|
|
exports.wrapKey = wrapKey;
|
|
|
|
var unwrapKey =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref4 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee2(wrappedKey, unwrappingKey, _ref3, webCrypto) {
|
|
var _ref3$name, name, iv, kek, cek;
|
|
|
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
while (1) {
|
|
switch (_context2.prev = _context2.next) {
|
|
case 0:
|
|
_ref3$name = _ref3.name, name = _ref3$name === void 0 ? 'AES-KW' : _ref3$name, iv = _ref3.iv;
|
|
|
|
if (!(typeof window.msCrypto === 'undefined')) {
|
|
_context2.next = 21;
|
|
break;
|
|
}
|
|
|
|
_context2.prev = 2;
|
|
_context2.next = 5;
|
|
return webCrypto.importKey('raw', unwrappingKey, {
|
|
name: name
|
|
}, false, ['wrapKey', 'unwrapKey']);
|
|
|
|
case 5:
|
|
kek = _context2.sent;
|
|
_context2.next = 8;
|
|
return webCrypto.unwrapKey('raw', wrappedKey, kek, {
|
|
name: name,
|
|
iv: iv
|
|
}, {
|
|
name: 'AES-GCM'
|
|
}, true, ['encrypt', 'decrypt']);
|
|
|
|
case 8:
|
|
cek = _context2.sent;
|
|
_context2.t0 = Uint8Array;
|
|
_context2.next = 12;
|
|
return webCrypto.exportKey('raw', cek);
|
|
|
|
case 12:
|
|
_context2.t1 = _context2.sent;
|
|
return _context2.abrupt("return", new _context2.t0(_context2.t1));
|
|
|
|
case 16:
|
|
_context2.prev = 16;
|
|
_context2.t2 = _context2["catch"](2);
|
|
throw new Error("WebCrypto_FailedToUnwrapKey - ".concat(_context2.t2.message));
|
|
|
|
case 19:
|
|
_context2.next = 22;
|
|
break;
|
|
|
|
case 21:
|
|
throw new Error('ThrowAwayMsIeAsap');
|
|
|
|
case 22:
|
|
case "end":
|
|
return _context2.stop();
|
|
}
|
|
}
|
|
}, _callee2, null, [[2, 16]]);
|
|
}));
|
|
|
|
return function unwrapKey(_x5, _x6, _x7, _x8) {
|
|
return _ref4.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* Encrypt data through AES of WebCrypto API.
|
|
* @param {Uint8Array} msg - Plaintext message to be encrypted.
|
|
* @param {Uint8Array} key - Byte array of symmetric key.
|
|
* @param {String} name - Name of AES algorithm like 'AES-GCM'.
|
|
* @param {Uint8Array} [iv] - Byte array of initial vector if required.
|
|
* @param {Uint8Array} [additionalData] - Byte array of additional data if required.
|
|
* @param {Number} [tagLength] - Authentication tag length if required.
|
|
* @param {Object} webCrypto - WebCrypto object, i.e., window.crypto.subtle or window.msCrypto.subtle
|
|
* @return {Promise<Uint8Array>} - Encrypted data byte array.
|
|
* @throws {Error} - Throws if UnsupportedCipher.
|
|
*/
|
|
|
|
|
|
exports.unwrapKey = unwrapKey;
|
|
|
|
var encrypt =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref6 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee3(msg, key, _ref5, webCrypto) {
|
|
var _ref5$name, name, iv, additionalData, tagLength, encryptionConfig, sessionKeyObj, data, _sessionKeyObj, encryptedObj, _data;
|
|
|
|
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
while (1) {
|
|
switch (_context3.prev = _context3.next) {
|
|
case 0:
|
|
_ref5$name = _ref5.name, name = _ref5$name === void 0 ? 'AES-GCM' : _ref5$name, iv = _ref5.iv, additionalData = _ref5.additionalData, tagLength = _ref5.tagLength;
|
|
encryptionConfig = setCipherParams({
|
|
name: name,
|
|
iv: iv,
|
|
additionalData: additionalData,
|
|
tagLength: tagLength
|
|
});
|
|
|
|
if (!(typeof window.msCrypto === 'undefined')) {
|
|
_context3.next = 18;
|
|
break;
|
|
}
|
|
|
|
_context3.prev = 3;
|
|
_context3.next = 6;
|
|
return webCrypto.importKey('raw', key, encryptionConfig, false, ['encrypt', 'decrypt']);
|
|
|
|
case 6:
|
|
sessionKeyObj = _context3.sent;
|
|
_context3.next = 9;
|
|
return webCrypto.encrypt(encryptionConfig, sessionKeyObj, msg);
|
|
|
|
case 9:
|
|
data = _context3.sent;
|
|
return _context3.abrupt("return", new Uint8Array(data));
|
|
|
|
case 13:
|
|
_context3.prev = 13;
|
|
_context3.t0 = _context3["catch"](3);
|
|
throw new Error("WebCrypto_EncryptionFailure: ".concat(_context3.t0.message));
|
|
|
|
case 16:
|
|
_context3.next = 38;
|
|
break;
|
|
|
|
case 18:
|
|
_context3.prev = 18;
|
|
_context3.next = 21;
|
|
return msImportKey('raw', key, encryptionConfig, false, ['encrypt', 'decrypt'], webCrypto);
|
|
|
|
case 21:
|
|
_sessionKeyObj = _context3.sent;
|
|
_context3.next = 24;
|
|
return msEncrypt(encryptionConfig, _sessionKeyObj, msg, webCrypto);
|
|
|
|
case 24:
|
|
encryptedObj = _context3.sent;
|
|
|
|
if (!(name === 'AES-GCM')) {
|
|
_context3.next = 32;
|
|
break;
|
|
}
|
|
|
|
_data = new Uint8Array(encryptedObj.ciphertext.byteLength + encryptedObj.tag.byteLength);
|
|
|
|
_data.set(new Uint8Array(encryptedObj.ciphertext));
|
|
|
|
_data.set(new Uint8Array(encryptedObj.tag), encryptedObj.ciphertext.byteLength);
|
|
|
|
return _context3.abrupt("return", _data);
|
|
|
|
case 32:
|
|
return _context3.abrupt("return", new Uint8Array(encryptedObj));
|
|
|
|
case 33:
|
|
_context3.next = 38;
|
|
break;
|
|
|
|
case 35:
|
|
_context3.prev = 35;
|
|
_context3.t1 = _context3["catch"](18);
|
|
throw new Error("ThrowAwayMsIeAsap: ".concat(_context3.t1.message));
|
|
|
|
case 38:
|
|
case "end":
|
|
return _context3.stop();
|
|
}
|
|
}
|
|
}, _callee3, null, [[3, 13], [18, 35]]);
|
|
}));
|
|
|
|
return function encrypt(_x9, _x10, _x11, _x12) {
|
|
return _ref6.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* Decrypt data through AES of WebCrypto API.
|
|
* @param {Uint8Array} data - Encrypted message to be decrypted.
|
|
* @param {Uint8Array} key - Byte array of symmetric key.
|
|
* @param {String} name - Name of AES algorithm like 'AES-GCM'.
|
|
* @param {Uint8Array} [iv] - Byte array of initial vector if required.
|
|
* @param {Uint8Array} [additionalData] - Byte array of additional data if required.
|
|
* @param {Number} [tagLength] - Authentication tag length if required.
|
|
* @param {Object} webCrypto - WebCrypto object, i.e., window.crypto.subtle or window.msCrypto.subtle
|
|
* @return {Promise<Uint8Array>} - Decrypted plaintext message.
|
|
* @throws {Error} - Throws if UnsupportedCipher or DecryptionFailure.
|
|
*/
|
|
|
|
|
|
exports.encrypt = encrypt;
|
|
|
|
var decrypt =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref8 = (0, _asyncToGenerator2.default)(
|
|
/*#__PURE__*/
|
|
_regenerator.default.mark(function _callee4(data, key, _ref7, webCrypto) {
|
|
var name, iv, additionalData, tagLength, decryptionConfig, sessionKeyObj, msg, _sessionKeyObj2, _msg, ciphertext, tag;
|
|
|
|
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
while (1) {
|
|
switch (_context4.prev = _context4.next) {
|
|
case 0:
|
|
name = _ref7.name, iv = _ref7.iv, additionalData = _ref7.additionalData, tagLength = _ref7.tagLength;
|
|
decryptionConfig = setCipherParams({
|
|
name: name,
|
|
iv: iv,
|
|
additionalData: additionalData,
|
|
tagLength: tagLength
|
|
});
|
|
|
|
if (window.msCrypto) {
|
|
_context4.next = 18;
|
|
break;
|
|
}
|
|
|
|
_context4.prev = 3;
|
|
_context4.next = 6;
|
|
return webCrypto.importKey('raw', key, decryptionConfig, false, ['encrypt', 'decrypt']);
|
|
|
|
case 6:
|
|
sessionKeyObj = _context4.sent;
|
|
_context4.next = 9;
|
|
return webCrypto.decrypt(decryptionConfig, sessionKeyObj, data);
|
|
|
|
case 9:
|
|
msg = _context4.sent;
|
|
return _context4.abrupt("return", new Uint8Array(msg));
|
|
|
|
case 13:
|
|
_context4.prev = 13;
|
|
_context4.t0 = _context4["catch"](3);
|
|
throw new Error("WebCrypto_DecryptionFailure: ".concat(_context4.t0.message));
|
|
|
|
case 16:
|
|
_context4.next = 39;
|
|
break;
|
|
|
|
case 18:
|
|
_context4.prev = 18;
|
|
_context4.next = 21;
|
|
return msImportKey('raw', key, decryptionConfig, false, ['encrypt', 'decrypt'], webCrypto);
|
|
|
|
case 21:
|
|
_sessionKeyObj2 = _context4.sent;
|
|
|
|
if (!(name === 'AES-GCM')) {
|
|
_context4.next = 30;
|
|
break;
|
|
}
|
|
|
|
ciphertext = data.slice(0, data.length - tagLength);
|
|
tag = data.slice(data.length - tagLength, data.length);
|
|
_context4.next = 27;
|
|
return msDecrypt(Object.assign(decryptionConfig, {
|
|
tag: tag
|
|
}), _sessionKeyObj2, ciphertext, webCrypto);
|
|
|
|
case 27:
|
|
_msg = _context4.sent;
|
|
_context4.next = 33;
|
|
break;
|
|
|
|
case 30:
|
|
_context4.next = 32;
|
|
return msDecrypt(decryptionConfig, _sessionKeyObj2, data, webCrypto);
|
|
|
|
case 32:
|
|
_msg = _context4.sent;
|
|
|
|
case 33:
|
|
return _context4.abrupt("return", new Uint8Array(_msg));
|
|
|
|
case 36:
|
|
_context4.prev = 36;
|
|
_context4.t1 = _context4["catch"](18);
|
|
throw new Error("ThrowAwayMsIeAsap: ".concat(_context4.t1.message));
|
|
|
|
case 39:
|
|
case "end":
|
|
return _context4.stop();
|
|
}
|
|
}
|
|
}, _callee4, null, [[3, 13], [18, 36]]);
|
|
}));
|
|
|
|
return function decrypt(_x13, _x14, _x15, _x16) {
|
|
return _ref8.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* Set params for encryption algorithms.
|
|
* @param {String} name - Name of AES algorithm like 'AES-GCM'.
|
|
* @param {Uint8Array} [iv] - Byte array of initial vector if required.
|
|
* @param {Uint8Array} [additionalData] - Byte array of additional data if required.
|
|
* @param {Number} [tagLength] - Authentication tag length if required.
|
|
*/
|
|
|
|
|
|
exports.decrypt = decrypt;
|
|
|
|
var setCipherParams = function setCipherParams(_ref9) {
|
|
var name = _ref9.name,
|
|
iv = _ref9.iv,
|
|
additionalData = _ref9.additionalData,
|
|
tagLength = _ref9.tagLength;
|
|
var alg = {};
|
|
|
|
switch (name) {
|
|
case 'AES-GCM':
|
|
{
|
|
Object.assign(alg, {
|
|
name: name,
|
|
iv: iv,
|
|
tagLength: tagLength * 8
|
|
});
|
|
Object.assign(alg, additionalData.length > 0 ? {
|
|
additionalData: additionalData
|
|
} : {});
|
|
break;
|
|
}
|
|
|
|
case 'AES-CBC':
|
|
{
|
|
alg.name = name;
|
|
alg.iv = iv;
|
|
break;
|
|
}
|
|
|
|
case 'AES-CTR':
|
|
{
|
|
if (iv.length === 0 || iv.length > 16) throw new Error('InvalidIVLength');
|
|
alg.name = name;
|
|
alg.counter = new Uint8Array(16);
|
|
alg.counter.set(iv);
|
|
alg.counter[15] += 1;
|
|
alg.length = 128; // todo: this might be (16 - iv.length) * 8.
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return alg;
|
|
}; // function definitions for IE
|
|
|
|
|
|
var msImportKey = function msImportKey(type, key, alg, ext, use, webCrypto) {
|
|
return new Promise(function (resolve, reject) {
|
|
var op = webCrypto.importKey(type, key, alg, ext, use);
|
|
|
|
op.oncomplete = function (evt) {
|
|
resolve(evt.target.result);
|
|
};
|
|
|
|
op.onerror = function () {
|
|
reject('KeyImportingFailed');
|
|
};
|
|
});
|
|
};
|
|
|
|
var msEncrypt = function msEncrypt(alg, key, msg, webCrypto) {
|
|
return new Promise(function (resolve, reject) {
|
|
var op = webCrypto.encrypt(alg, key, msg);
|
|
|
|
op.oncomplete = function (evt) {
|
|
resolve(evt.target.result);
|
|
};
|
|
|
|
op.onerror = function () {
|
|
reject('EncryptionFailure');
|
|
};
|
|
});
|
|
};
|
|
|
|
var msDecrypt = function msDecrypt(alg, key, data, webCrypto) {
|
|
return new Promise(function (resolve, reject) {
|
|
var op = webCrypto.decrypt(alg, key, data);
|
|
|
|
op.oncomplete = function (evt) {
|
|
resolve(evt.target.result);
|
|
};
|
|
|
|
op.onerror = function () {
|
|
reject('DecryptionFailure');
|
|
};
|
|
});
|
|
}; |