UNPKG

pubnub

Version:

Publish & Subscribe Real-time Messaging with PubNub

336 lines (335 loc) 12.9 kB
"use strict"; /** * Legacy cryptography module. * * @internal */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const base64_codec_1 = require("../base64_codec"); const hmac_sha256_1 = __importDefault(require("./hmac-sha256")); /** * Convert bytes array to words array. * * @param b - Bytes array (buffer) which should be converted. * * @returns Word sized array. * * @internal */ /* eslint-disable @typescript-eslint/no-explicit-any */ function bufferToWordArray(b) { const wa = []; let i; for (i = 0; i < b.length; i += 1) { wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } // @ts-expect-error Bundled library without types. return hmac_sha256_1.default.lib.WordArray.create(wa, b.length); } /** * Legacy cryptography module for files and signature. * * @internal */ class default_1 { constructor(configuration) { this.configuration = configuration; /** * Crypto initialization vector. */ this.iv = '0123456789012345'; /** * List os allowed cipher key encodings. */ this.allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; /** * Allowed cipher key lengths. */ this.allowedKeyLengths = [128, 256]; /** * Allowed crypto modes. */ this.allowedModes = ['ecb', 'cbc']; this.logger = configuration.logger; this.defaultOptions = { encryptKey: true, keyEncoding: 'utf8', keyLength: 256, mode: 'cbc', }; } /** * Update registered loggers' manager. * * @param [logger] - Logger, which crypto should use. */ set logger(logger) { this._logger = logger; if (this.logger) { this.logger.debug('Crypto', () => ({ messageType: 'object', message: this.configuration, details: 'Create with configuration:', ignoredKeys(key, obj) { return typeof obj[key] === 'function' || key === 'logger'; }, })); } } /** * Get loggers' manager. * * @returns Loggers' manager (if set). */ get logger() { return this._logger; } /** * Generate HMAC-SHA256 hash from input data. * * @param data - Data from which hash should be generated. * * @returns HMAC-SHA256 hash from provided `data`. */ HMACSHA256(data) { // @ts-expect-error Bundled library without types. const hash = hmac_sha256_1.default.HmacSHA256(data, this.configuration.secretKey); // @ts-expect-error Bundled library without types. return hash.toString(hmac_sha256_1.default.enc.Base64); } /** * Generate SHA256 hash from input data. * * @param data - Data from which hash should be generated. * * @returns SHA256 hash from provided `data`. */ SHA256(data) { // @ts-expect-error Bundled library without types. return hmac_sha256_1.default.SHA256(data).toString(hmac_sha256_1.default.enc.Hex); } /** * Encrypt provided data. * * @param data - Source data which should be encrypted. * @param [customCipherKey] - Custom cipher key (different from defined on client level). * @param [options] - Specific crypto configuration options. * * @returns Encrypted `data`. */ encrypt(data, customCipherKey, options) { if (this.configuration.customEncrypt) { if (this.logger) this.logger.warn('Crypto', "'customEncrypt' is deprecated. Consult docs for better alternative."); return this.configuration.customEncrypt(data); } return this.pnEncrypt(data, customCipherKey, options); } /** * Decrypt provided data. * * @param data - Encrypted data which should be decrypted. * @param [customCipherKey] - Custom cipher key (different from defined on client level). * @param [options] - Specific crypto configuration options. * * @returns Decrypted `data`. */ decrypt(data, customCipherKey, options) { if (this.configuration.customDecrypt) { if (this.logger) this.logger.warn('Crypto', "'customDecrypt' is deprecated. Consult docs for better alternative."); return this.configuration.customDecrypt(data); } return this.pnDecrypt(data, customCipherKey, options); } /** * Encrypt provided data. * * @param data - Source data which should be encrypted. * @param [customCipherKey] - Custom cipher key (different from defined on client level). * @param [options] - Specific crypto configuration options. * * @returns Encrypted `data` as string. */ pnEncrypt(data, customCipherKey, options) { const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; if (!decidedCipherKey) return data; if (this.logger) { this.logger.debug('Crypto', () => ({ messageType: 'object', message: Object.assign({ data, cipherKey: decidedCipherKey }, (options !== null && options !== void 0 ? options : {})), details: 'Encrypt with parameters:', })); } options = this.parseOptions(options); const mode = this.getMode(options); const cipherKey = this.getPaddedKey(decidedCipherKey, options); if (this.configuration.useRandomIVs) { const waIv = this.getRandomIV(); // @ts-expect-error Bundled library without types. const waPayload = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; // @ts-expect-error Bundled library without types. return waIv.clone().concat(waPayload.clone()).toString(hmac_sha256_1.default.enc.Base64); } const iv = this.getIV(options); // @ts-expect-error Bundled library without types. const encryptedHexArray = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; // @ts-expect-error Bundled library without types. const base64Encrypted = encryptedHexArray.toString(hmac_sha256_1.default.enc.Base64); return base64Encrypted || data; } /** * Decrypt provided data. * * @param data - Encrypted data which should be decrypted. * @param [customCipherKey] - Custom cipher key (different from defined on client level). * @param [options] - Specific crypto configuration options. * * @returns Decrypted `data`. */ pnDecrypt(data, customCipherKey, options) { const decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; if (!decidedCipherKey) return data; if (this.logger) { this.logger.debug('Crypto', () => ({ messageType: 'object', message: Object.assign({ data, cipherKey: decidedCipherKey }, (options !== null && options !== void 0 ? options : {})), details: 'Decrypt with parameters:', })); } options = this.parseOptions(options); const mode = this.getMode(options); const cipherKey = this.getPaddedKey(decidedCipherKey, options); if (this.configuration.useRandomIVs) { const ciphertext = new Uint8ClampedArray((0, base64_codec_1.decode)(data)); const iv = bufferToWordArray(ciphertext.slice(0, 16)); const payload = bufferToWordArray(ciphertext.slice(16)); try { // @ts-expect-error Bundled library without types. const plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( // @ts-expect-error Bundled library without types. hmac_sha256_1.default.enc.Utf8); return JSON.parse(plainJSON); } catch (e) { if (this.logger) this.logger.error('Crypto', () => ({ messageType: 'error', message: e })); return null; } } else { const iv = this.getIV(options); try { // @ts-expect-error Bundled library without types. const ciphertext = hmac_sha256_1.default.enc.Base64.parse(data); // @ts-expect-error Bundled library without types. const plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(hmac_sha256_1.default.enc.Utf8); return JSON.parse(plainJSON); } catch (e) { if (this.logger) this.logger.error('Crypto', () => ({ messageType: 'error', message: e })); return null; } } } /** * Pre-process provided custom crypto configuration. * * @param incomingOptions - Configuration which should be pre-processed before use. * * @returns Normalized crypto configuration options. */ parseOptions(incomingOptions) { var _a, _b, _c, _d; if (!incomingOptions) return this.defaultOptions; // Defaults const options = { encryptKey: (_a = incomingOptions.encryptKey) !== null && _a !== void 0 ? _a : this.defaultOptions.encryptKey, keyEncoding: (_b = incomingOptions.keyEncoding) !== null && _b !== void 0 ? _b : this.defaultOptions.keyEncoding, keyLength: (_c = incomingOptions.keyLength) !== null && _c !== void 0 ? _c : this.defaultOptions.keyLength, mode: (_d = incomingOptions.mode) !== null && _d !== void 0 ? _d : this.defaultOptions.mode, }; // Validation if (this.allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) options.keyEncoding = this.defaultOptions.keyEncoding; if (this.allowedKeyLengths.indexOf(options.keyLength) === -1) options.keyLength = this.defaultOptions.keyLength; if (this.allowedModes.indexOf(options.mode.toLowerCase()) === -1) options.mode = this.defaultOptions.mode; return options; } /** * Decode provided cipher key. * * @param key - Key in `encoding` provided by `options`. * @param options - Crypto configuration options with cipher key details. * * @returns Array buffer with decoded key. */ decodeKey(key, options) { // @ts-expect-error Bundled library without types. if (options.keyEncoding === 'base64') return hmac_sha256_1.default.enc.Base64.parse(key); // @ts-expect-error Bundled library without types. if (options.keyEncoding === 'hex') return hmac_sha256_1.default.enc.Hex.parse(key); return key; } /** * Add padding to the cipher key. * * @param key - Key which should be padded. * @param options - Crypto configuration options with cipher key details. * * @returns Properly padded cipher key. */ getPaddedKey(key, options) { key = this.decodeKey(key, options); // @ts-expect-error Bundled library without types. if (options.encryptKey) return hmac_sha256_1.default.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); return key; } /** * Cipher mode. * * @param options - Crypto configuration with information about cipher mode. * * @returns Crypto cipher mode. */ getMode(options) { // @ts-expect-error Bundled library without types. if (options.mode === 'ecb') return hmac_sha256_1.default.mode.ECB; // @ts-expect-error Bundled library without types. return hmac_sha256_1.default.mode.CBC; } /** * Cipher initialization vector. * * @param options - Crypto configuration with information about cipher mode. * * @returns Initialization vector. */ getIV(options) { // @ts-expect-error Bundled library without types. return options.mode === 'cbc' ? hmac_sha256_1.default.enc.Utf8.parse(this.iv) : null; } /** * Random initialization vector. * * @returns Generated random initialization vector. */ getRandomIV() { // @ts-expect-error Bundled library without types. return hmac_sha256_1.default.lib.WordArray.random(16); } } exports.default = default_1;