"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} - 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} - 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'); }; }); };