"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 _params = _interopRequireDefault(require("./params.js")); /** * nodeapi.js */ /** * Node.js 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} - NodeCrypto object * @return {Uint8Array} - Unwrapped Key */ var wrapKey = function wrapKey(keyToBeWrapped, wrappingKey, _ref, nodeCrypto) { var _ref$name = _ref.name, name = _ref$name === void 0 ? 'AES-KW' : _ref$name, iv = _ref.iv; return encrypt(keyToBeWrapped, wrappingKey, { name: name, iv: iv }, nodeCrypto, true); }; /** * Node.js 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} - NodeCrypto object * @return {Uint8Array} - Unwrapped Key */ exports.wrapKey = wrapKey; var unwrapKey = function unwrapKey(wrappedKey, unwrappingKey, _ref2, nodeCrypto) { var _ref2$name = _ref2.name, name = _ref2$name === void 0 ? 'AES-KW' : _ref2$name, iv = _ref2.iv; return decrypt(wrappedKey, unwrappingKey, { name: name, iv: iv }, nodeCrypto, true); }; /** * Encrypt plaintext message via AES Node.js crypto 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} nodeCrypto - NodeCrypto object, i.e., require(crypto) in Node.js. * @param wrapKey {Boolean} [false] - true if called as AES-KW * @return {Uint8Array} - Encrypted message byte array. * @throws {Error} - Throws error if UnsupportedCipher. */ exports.unwrapKey = unwrapKey; var encrypt = function encrypt(msg, key, _ref3, nodeCrypto) { var name = _ref3.name, iv = _ref3.iv, additionalData = _ref3.additionalData, tagLength = _ref3.tagLength; var wrapKey = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; var alg = getNodeName(name, key.byteLength, wrapKey ? _params.default.wrapKeys : _params.default.ciphers); var cipher; switch (name) { case 'AES-GCM': { cipher = nodeCrypto.createCipheriv(alg, key, iv, { authTagLength: tagLength }); cipher.setAAD(additionalData); break; } case 'AES-CTR': { if (iv.length === 0 || iv.length > 16) throw new Error('InvalidIVLength'); var counter = new Uint8Array(16); counter.set(iv); counter[15] += 1; cipher = nodeCrypto.createCipheriv(alg, key, counter); break; } default: { // AES-CBC or AES-KW cipher = nodeCrypto.createCipheriv(alg, key, iv); break; } } var body; var final; var tag; try { body = new Uint8Array(cipher.update(msg)); final = new Uint8Array(cipher.final()); tag = new Uint8Array([]); if (name === 'AES-GCM') tag = new Uint8Array(cipher.getAuthTag()); } catch (e) { throw new Error('NodeCrypto_EncryptionFailure'); } var data = new Uint8Array(body.length + final.length + tag.length); data.set(body); data.set(final, body.length); data.set(tag, body.length + final.length); return data; }; /** * Decrypt data through AES Node.js crypto 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} nodeCrypto - NodeCrypto object, i.e., require(crypto) in Node.js. * @return {Uint8Array} - Decrypted message byte array. * @param unwrapKey {Boolean} [false] - true if called as AES-KW * @throws {Error} - Throws error if UnsupportedCipher or DecryptionFailure. */ exports.encrypt = encrypt; var decrypt = function decrypt(data, key, _ref4, nodeCrypto) { var name = _ref4.name, iv = _ref4.iv, additionalData = _ref4.additionalData, tagLength = _ref4.tagLength; var unwrapKey = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; var alg = getNodeName(name, key.byteLength, unwrapKey ? _params.default.wrapKeys : _params.default.ciphers); var decipher; var body; switch (name) { case 'AES-GCM': { decipher = nodeCrypto.createDecipheriv(alg, key, iv, { authTagLength: tagLength }); decipher.setAAD(additionalData); body = data.slice(0, data.length - tagLength); var tag = data.slice(data.length - tagLength); decipher.setAuthTag(tag); break; } case 'AES-CTR': { if (iv.length === 0 || iv.length > 16) throw new Error('InvalidIVLength'); var counter = new Uint8Array(16); counter.set(iv); counter[15] += 1; decipher = nodeCrypto.createDecipheriv(alg, key, counter); body = data; break; } default: { // AES-CBC or AES-KW decipher = nodeCrypto.createDecipheriv(alg, key, iv); body = data; break; } } var decryptedBody; var final; try { decryptedBody = decipher.update(body); final = decipher.final(); } catch (e) { throw new Error('NodeCrypto_DecryptionFailure'); } var msg = new Uint8Array(final.length + decryptedBody.length); msg.set(decryptedBody); msg.set(final, decryptedBody.length); return msg; }; /** * get node algorithm name * @param name {string} - name of webcrypto alg like AES-GCM * @param keyLength {number} - aes encryption key * @param dict {object} - params.ciphers or params.wrapKeys * @return {string} - node algorithm name */ exports.decrypt = decrypt; var getNodeName = function getNodeName(name, keyLength, dict) { var alg = dict[name].nodePrefix; alg = "".concat(alg).concat((keyLength * 8).toString()); return alg + dict[name].nodeSuffix; };