crypto-es
Version:
A cryptography algorithms library compatible with ES6 and TypeScript
1 lines • 39.5 kB
Source Map (JSON)
{"version":3,"file":"cipher-core.mjs","names":["block: number[] | undefined","Pkcs7: Padding","paddingWords: number[]","modeCreator: ((cipher: Cipher, iv?: number[]) => BlockCipherMode) | undefined","finalProcessedBlocks: WordArray","OpenSSLFormatter: Format","wordArray: WordArray","salt: WordArray | undefined","OpenSSLKdf: Kdf","_salt: WordArray","key: WordArray"],"sources":["../src/cipher-core.ts"],"sourcesContent":["/* eslint-disable no-use-before-define */\n\nimport {\n Base,\n WordArray,\n BufferedBlockAlgorithm,\n Hasher,\n HasherCfg,\n Hex,\n} from './core';\nimport { Base64 } from './enc-base64';\nimport { EvpKDFAlgo } from './evpkdf';\n\n// Re-export WordArray for convenience\nexport { WordArray } from './core';\n\n/**\n * Configuration options for ciphers\n */\nexport interface CipherCfg {\n /** Initialization vector */\n iv?: WordArray;\n /** Block cipher mode */\n mode?: typeof BlockCipherMode;\n /** Padding strategy */\n padding?: Padding;\n /** Formatter for serialization */\n format?: Format;\n /** Key derivation function */\n kdf?: Kdf;\n /** Salt for key derivation */\n salt?: WordArray | string;\n /** Hasher for key derivation */\n hasher?: new (cfg?: HasherCfg) => Hasher;\n /** Drop value for RC4Drop */\n drop?: number;\n}\n\n/**\n * Cipher parameters configuration\n */\nexport interface CipherParamsCfg {\n /** The raw ciphertext */\n ciphertext?: WordArray;\n /** The key to this ciphertext */\n key?: WordArray;\n /** The IV used in the ciphering operation */\n iv?: WordArray;\n /** The salt used with a key derivation function */\n salt?: WordArray;\n /** The cipher algorithm */\n algorithm?: typeof Cipher;\n /** The block mode used in the ciphering operation */\n mode?: typeof BlockCipherMode;\n /** The padding scheme used in the ciphering operation */\n padding?: Padding;\n /** The block size of the cipher */\n blockSize?: number;\n /** The default formatting strategy */\n formatter?: Format;\n /** Allow additional properties */\n [key: string]: unknown;\n}\n\n/**\n * Cipher object interface\n */\nexport interface CipherObj {\n /**\n * Encrypts a message\n * @param message - The message to encrypt\n * @param key - The key\n * @param cfg - Configuration options\n * @returns The encrypted cipher params\n */\n encrypt(message: WordArray | string, key: WordArray | string, cfg?: CipherCfg): CipherParams;\n \n /**\n * Decrypts ciphertext\n * @param ciphertext - The ciphertext to decrypt\n * @param key - The key\n * @param cfg - Configuration options\n * @returns The decrypted plaintext\n */\n decrypt(ciphertext: CipherParams | CipherParamsCfg | string, key: WordArray | string, cfg?: CipherCfg): WordArray;\n}\n\n/**\n * Padding strategy interface\n */\nexport interface Padding {\n /**\n * Pads data to a multiple of blockSize\n * @param data - The data to pad\n * @param blockSize - The block size in words\n */\n pad(data: WordArray, blockSize: number): void;\n \n /**\n * Unpads data\n * @param data - The data to unpad\n */\n unpad(data: WordArray): void;\n}\n\n/**\n * Format strategy interface\n */\nexport interface Format {\n /**\n * Converts cipher params to string\n * @param cipherParams - The cipher params\n * @returns The string representation\n */\n stringify(cipherParams: CipherParams): string;\n \n /**\n * Parses string to cipher params\n * @param str - The string to parse\n * @param cipher - The cipher class\n * @returns The cipher params\n */\n parse(str: string, cipher?: any): CipherParams;\n}\n\n/**\n * Key derivation function interface\n */\nexport interface Kdf {\n /**\n * Derives key and IV from password\n * @param password - The password\n * @param keySize - Key size in words\n * @param ivSize - IV size in words\n * @param salt - Optional salt\n * @param hasher - Optional hasher\n * @returns The derived cipher params\n */\n execute(\n password: string,\n keySize: number,\n ivSize: number,\n salt?: WordArray | string,\n hasher?: new (cfg?: HasherCfg) => Hasher\n ): CipherParams;\n}\n\n/**\n * Abstract base cipher template.\n * Provides the foundation for all encryption and decryption algorithms.\n * \n * @property keySize - This cipher's key size in words (default: 4 = 128 bits)\n * @property ivSize - This cipher's IV size in words (default: 4 = 128 bits)\n * @property _ENC_XFORM_MODE - A constant representing encryption mode\n * @property _DEC_XFORM_MODE - A constant representing decryption mode\n */\nexport abstract class Cipher extends BufferedBlockAlgorithm {\n /** Encryption mode constant */\n static readonly _ENC_XFORM_MODE: number = 1;\n \n /** Decryption mode constant */\n static readonly _DEC_XFORM_MODE: number = 2;\n \n /** Default key size in words (128 bits) */\n static keySize: number = 128 / 32;\n \n /** Default IV size in words (128 bits) */\n static ivSize: number = 128 / 32;\n \n /** Configuration options */\n cfg: CipherCfg;\n \n /** Transform mode (encryption or decryption) */\n protected _xformMode: number;\n \n /** The key */\n protected _key: WordArray;\n \n /** Block size in words */\n blockSize: number = 128 / 32;\n\n /**\n * Initializes a newly created cipher.\n * \n * @param xformMode - Either the encryption or decryption transformation mode constant\n * @param key - The key\n * @param cfg - Configuration options to use for this operation\n * @example\n * ```javascript\n * const cipher = new AESAlgo(\n * Cipher._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }\n * );\n * ```\n */\n constructor(xformMode: number, key: WordArray, cfg?: CipherCfg) {\n super();\n this.cfg = Object.assign({}, cfg);\n this._xformMode = xformMode;\n this._key = key;\n // Note: reset() is called by subclasses after initialization\n }\n\n /**\n * Creates this cipher in encryption mode.\n * \n * @param key - The key\n * @param cfg - Configuration options to use for this operation\n * @returns A cipher instance\n * @static\n * @example\n * ```javascript\n * const cipher = AESAlgo.createEncryptor(keyWordArray, { iv: ivWordArray });\n * ```\n */\n static createEncryptor<T extends Cipher>(\n this: new (xformMode: number, key: WordArray, cfg?: CipherCfg) => T,\n key: WordArray,\n cfg?: CipherCfg\n ): T {\n return (this as any).create(Cipher._ENC_XFORM_MODE, key, cfg);\n }\n\n /**\n * Creates this cipher in decryption mode.\n * \n * @param key - The key\n * @param cfg - Configuration options to use for this operation\n * @returns A cipher instance\n * @static\n * @example\n * ```javascript\n * const cipher = AESAlgo.createDecryptor(keyWordArray, { iv: ivWordArray });\n * ```\n */\n static createDecryptor<T extends Cipher>(\n this: new (xformMode: number, key: WordArray, cfg?: CipherCfg) => T,\n key: WordArray,\n cfg?: CipherCfg\n ): T {\n return (this as any).create(Cipher._DEC_XFORM_MODE, key, cfg);\n }\n\n /**\n * Factory method to create a cipher instance.\n * \n * @param xformMode - Transform mode\n * @param key - The key\n * @param cfg - Configuration options\n * @returns A cipher instance\n * @static\n */\n static create<T extends Cipher>(\n this: new (xformMode: number, key: WordArray, cfg?: CipherCfg) => T,\n xformMode: number,\n key: WordArray,\n cfg?: CipherCfg\n ): T;\n static create<T extends Base>(this: new (...args: any[]) => T, ...args: any[]): T;\n static create(this: any, ...args: any[]): any {\n // Handle both Cipher and Base cases\n if (args.length >= 2 && typeof args[0] === 'number') {\n // Cipher case: xformMode, key, cfg\n const [xformMode, key, cfg] = args;\n const instance = new this(xformMode, key, cfg);\n // Call reset after construction to properly initialize\n instance.reset();\n return instance;\n } else {\n // Base case: pass all arguments\n return new this(...args);\n }\n }\n\n /**\n * Creates shortcut functions to a cipher's object interface.\n * \n * @param SubCipher - The cipher to create a helper for\n * @returns An object with encrypt and decrypt shortcut functions\n * @static\n * @example\n * ```javascript\n * const AES = Cipher._createHelper(AESAlgo);\n * ```\n */\n static _createHelper(SubCipher: typeof Cipher): CipherObj {\n const selectCipherStrategy = (key: WordArray | string): typeof SerializableCipher => {\n if (typeof key === 'string') {\n return PasswordBasedCipher;\n }\n return SerializableCipher;\n };\n\n return {\n encrypt(message: WordArray | string, key: WordArray | string, cfg?: CipherCfg): CipherParams {\n return selectCipherStrategy(key).encrypt(SubCipher, message, key, cfg);\n },\n\n decrypt(\n ciphertext: CipherParams | CipherParamsCfg | string,\n key: WordArray | string,\n cfg?: CipherCfg\n ): WordArray {\n return selectCipherStrategy(key).decrypt(SubCipher, ciphertext, key, cfg);\n },\n };\n }\n\n /**\n * Resets this cipher to its initial state.\n * \n * @example\n * ```javascript\n * cipher.reset();\n * ```\n */\n reset(): void {\n super.reset();\n this._doReset();\n }\n\n /**\n * Adds data to be encrypted or decrypted.\n * \n * @param dataUpdate - The data to encrypt or decrypt\n * @returns The data after processing\n * @example\n * ```javascript\n * const encrypted = cipher.process('data');\n * const encrypted = cipher.process(wordArray);\n * ```\n */\n process(dataUpdate: WordArray | string): WordArray {\n this._append(dataUpdate);\n return this._process();\n }\n\n /**\n * Finalizes the encryption or decryption process.\n * Note that the finalize operation is effectively a destructive, read-once operation.\n * \n * @param dataUpdate - The final data to encrypt or decrypt\n * @returns The data after final processing\n * @example\n * ```javascript\n * const encrypted = cipher.finalize();\n * const encrypted = cipher.finalize('data');\n * const encrypted = cipher.finalize(wordArray);\n * ```\n */\n finalize(dataUpdate?: WordArray | string): WordArray {\n if (dataUpdate) {\n this._append(dataUpdate);\n }\n const finalProcessedData = this._doFinalize();\n return finalProcessedData;\n }\n\n /**\n * Reset implementation for concrete cipher\n * Must be implemented by subclasses\n */\n protected abstract _doReset(): void;\n\n /**\n * Finalize implementation for concrete cipher\n * Must be implemented by subclasses\n */\n protected abstract _doFinalize(): WordArray;\n\n /**\n * Encrypt a block of data\n * Must be implemented by block ciphers\n */\n encryptBlock?(words: number[], offset: number): void;\n\n /**\n * Decrypt a block of data\n * Must be implemented by block ciphers\n */\n decryptBlock?(words: number[], offset: number): void;\n}\n\n/**\n * Abstract base stream cipher template.\n * Stream ciphers process data one unit at a time rather than in blocks.\n * \n * @property blockSize - The number of 32-bit words this cipher operates on (default: 1 = 32 bits)\n */\nexport abstract class StreamCipher extends Cipher {\n blockSize: number = 1;\n\n constructor(xformMode: number, key: WordArray, cfg?: CipherCfg) {\n super(xformMode, key, cfg);\n this.blockSize = 1;\n // Don't call reset() here - let it be called after construction\n // to avoid field initialization issues\n }\n\n protected _doFinalize(): WordArray {\n // Process partial blocks\n const finalProcessedBlocks = this._process(true);\n return finalProcessedBlocks;\n }\n}\n\n/**\n * Abstract base block cipher mode template.\n * Defines how multiple blocks are processed together.\n */\nexport class BlockCipherMode extends Base {\n /** The cipher instance */\n _cipher: Cipher;\n \n /** The initialization vector */\n _iv?: number[];\n \n /** The previous block (for chaining modes) */\n _prevBlock?: number[];\n\n /**\n * Initializes a newly created mode.\n * \n * @param cipher - A block cipher instance\n * @param iv - The IV words\n * @example\n * ```javascript\n * const mode = new CBCMode(cipher, iv.words);\n * ```\n */\n constructor(cipher: Cipher, iv?: number[]) {\n super();\n this._cipher = cipher;\n this._iv = iv;\n }\n\n /**\n * Creates this mode for encryption.\n * \n * @param cipher - A block cipher instance\n * @param iv - The IV words\n * @returns The mode instance\n * @static\n * @example\n * ```javascript\n * const mode = CBC.createEncryptor(cipher, iv.words);\n * ```\n */\n static createEncryptor(cipher: Cipher, iv?: number[]): BlockCipherMode {\n return (this as any).Encryptor.create(cipher, iv);\n }\n\n /**\n * Creates this mode for decryption.\n * \n * @param cipher - A block cipher instance\n * @param iv - The IV words\n * @returns The mode instance\n * @static\n * @example\n * ```javascript\n * const mode = CBC.createDecryptor(cipher, iv.words);\n * ```\n */\n static createDecryptor(cipher: Cipher, iv?: number[]): BlockCipherMode {\n return (this as any).Decryptor.create(cipher, iv);\n }\n\n /**\n * Process a block of data\n * Must be implemented by concrete modes\n */\n processBlock(_words: number[], _offset: number): void {\n // Abstract method\n }\n}\n\n/**\n * XOR blocks for cipher block chaining\n * @private\n */\nfunction xorBlock(this: BlockCipherMode, words: number[], offset: number, blockSize: number): void {\n const _words = words;\n let block: number[] | undefined;\n\n // Shortcut\n const iv = this._iv;\n\n // Choose mixing block\n if (iv) {\n block = iv;\n // Remove IV for subsequent blocks\n this._iv = undefined;\n } else {\n block = this._prevBlock;\n }\n\n // XOR blocks\n if (block) {\n for (let i = 0; i < blockSize; i += 1) {\n _words[offset + i] ^= block[i];\n }\n }\n}\n\n/**\n * CBC Encryptor\n */\nclass CBCEncryptor extends BlockCipherMode {\n /**\n * Processes the data block at offset.\n * \n * @param words - The data words to operate on\n * @param offset - The offset where the block starts\n * @example\n * ```javascript\n * mode.processBlock(data.words, offset);\n * ```\n */\n processBlock(words: number[], offset: number): void {\n const cipher = this._cipher;\n const blockSize = cipher.blockSize;\n\n // XOR and encrypt\n xorBlock.call(this, words, offset, blockSize);\n cipher.encryptBlock!(words, offset);\n\n // Remember this block to use with next block\n this._prevBlock = words.slice(offset, offset + blockSize);\n }\n}\n\n/**\n * CBC Decryptor\n */\nclass CBCDecryptor extends BlockCipherMode {\n /**\n * Processes the data block at offset.\n * \n * @param words - The data words to operate on\n * @param offset - The offset where the block starts\n * @example\n * ```javascript\n * mode.processBlock(data.words, offset);\n * ```\n */\n processBlock(words: number[], offset: number): void {\n const cipher = this._cipher;\n const blockSize = cipher.blockSize;\n\n // Remember this block to use with next block\n const thisBlock = words.slice(offset, offset + blockSize);\n\n // Decrypt and XOR\n cipher.decryptBlock!(words, offset);\n xorBlock.call(this, words, offset, blockSize);\n\n // This block becomes the previous block\n this._prevBlock = thisBlock;\n }\n}\n\n/**\n * Cipher Block Chaining mode.\n * Each block is XORed with the previous ciphertext block before encryption.\n */\nexport class CBC extends BlockCipherMode {\n /** CBC Encryptor */\n static Encryptor = CBCEncryptor;\n\n /** CBC Decryptor */\n static Decryptor = CBCDecryptor;\n}\n\n/**\n * PKCS #5/7 padding strategy.\n * Pads data with bytes all of the same value as the count of padding bytes.\n */\nexport const Pkcs7: Padding = {\n /**\n * Pads data using the algorithm defined in PKCS #5/7.\n * \n * @param data - The data to pad\n * @param blockSize - The multiple that the data should be padded to\n * @example\n * ```javascript\n * Pkcs7.pad(wordArray, 4);\n * ```\n */\n pad(data: WordArray, blockSize: number): void {\n // Shortcut\n const blockSizeBytes = blockSize * 4;\n\n // Count padding bytes\n const nPaddingBytes = blockSizeBytes - (data.sigBytes % blockSizeBytes);\n\n // Create padding word\n const paddingWord = (nPaddingBytes << 24)\n | (nPaddingBytes << 16)\n | (nPaddingBytes << 8)\n | nPaddingBytes;\n\n // Create padding\n const paddingWords: number[] = [];\n for (let i = 0; i < nPaddingBytes; i += 4) {\n paddingWords.push(paddingWord);\n }\n const padding = WordArray.create(paddingWords, nPaddingBytes);\n\n // Add padding\n data.concat(padding);\n },\n\n /**\n * Unpads data that had been padded using the algorithm defined in PKCS #5/7.\n * \n * @param data - The data to unpad\n * @example\n * ```javascript\n * Pkcs7.unpad(wordArray);\n * ```\n */\n unpad(data: WordArray): void {\n // Get number of padding bytes from last byte\n const nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;\n\n // Remove padding\n data.sigBytes -= nPaddingBytes;\n }\n};\n\n/**\n * Abstract base block cipher template.\n * Block ciphers process data in fixed-size blocks.\n * \n * @property blockSize - The number of 32-bit words this cipher operates on (default: 4 = 128 bits)\n */\nexport abstract class BlockCipher extends Cipher {\n /** Block mode instance */\n protected _mode?: BlockCipherMode & { __creator?: Function };\n\n /**\n * Initializes a newly created block cipher.\n * \n * @param xformMode - Transform mode\n * @param key - The key\n * @param cfg - Configuration options\n */\n constructor(xformMode: number, key: WordArray, cfg?: CipherCfg) {\n super(xformMode, key, Object.assign(\n {\n mode: CBC,\n padding: Pkcs7,\n },\n cfg\n ));\n this.blockSize = 128 / 32;\n // Don't call reset() here - let it be called after construction\n // to avoid field initialization issues\n }\n\n reset(): void {\n // Reset cipher\n super.reset();\n\n // Shortcuts\n const { cfg } = this;\n const { iv, mode } = cfg;\n\n // Reset block mode\n let modeCreator: ((cipher: Cipher, iv?: number[]) => BlockCipherMode) | undefined;\n \n if (this._xformMode === (this.constructor as typeof Cipher)._ENC_XFORM_MODE) {\n modeCreator = mode?.createEncryptor;\n } else {\n modeCreator = mode?.createDecryptor;\n // Keep at least one block in the buffer for unpadding\n this._minBufferSize = 1;\n }\n\n if (modeCreator && mode) {\n this._mode = modeCreator.call(mode, this, iv?.words) as BlockCipherMode & { __creator?: Function };\n this._mode.__creator = modeCreator;\n }\n }\n\n protected _doProcessBlock(words: number[], offset: number): void {\n this._mode?.processBlock(words, offset);\n }\n\n /**\n * Encrypt a block of data\n * Must be implemented by block ciphers\n */\n abstract encryptBlock(words: number[], offset: number): void;\n\n /**\n * Decrypt a block of data\n * Must be implemented by block ciphers\n */\n abstract decryptBlock(words: number[], offset: number): void;\n\n protected _doFinalize(): WordArray {\n let finalProcessedBlocks: WordArray;\n\n // Shortcut\n const { padding } = this.cfg;\n\n // Finalize\n if (this._xformMode === (this.constructor as typeof Cipher)._ENC_XFORM_MODE) {\n // Pad data\n if (padding) {\n padding.pad(this._data, this.blockSize);\n }\n\n // Process final blocks\n finalProcessedBlocks = this._process(true);\n } else {\n // Process final blocks\n finalProcessedBlocks = this._process(true);\n\n // Unpad data\n if (padding) {\n padding.unpad(finalProcessedBlocks);\n }\n }\n\n return finalProcessedBlocks;\n }\n}\n\n/**\n * A collection of cipher parameters.\n * Encapsulates all the parameters used in a cipher operation.\n * \n * @property ciphertext - The raw ciphertext\n * @property key - The key to this ciphertext\n * @property iv - The IV used in the ciphering operation\n * @property salt - The salt used with a key derivation function\n * @property algorithm - The cipher algorithm\n * @property mode - The block mode used in the ciphering operation\n * @property padding - The padding scheme used in the ciphering operation\n * @property blockSize - The block size of the cipher\n * @property formatter - The default formatting strategy\n */\nexport class CipherParams extends Base implements CipherParamsCfg {\n ciphertext?: WordArray;\n key?: WordArray;\n iv?: WordArray;\n salt?: WordArray;\n algorithm?: typeof Cipher;\n mode?: typeof BlockCipherMode;\n padding?: Padding;\n blockSize?: number;\n formatter?: Format;\n [key: string]: unknown;\n\n /**\n * Initializes a newly created cipher params object.\n * \n * @param cipherParams - An object with any of the possible cipher parameters\n * @example\n * ```javascript\n * const cipherParams = new CipherParams({\n * ciphertext: ciphertextWordArray,\n * key: keyWordArray,\n * iv: ivWordArray,\n * salt: saltWordArray,\n * algorithm: AESAlgo,\n * mode: CBC,\n * padding: Pkcs7,\n * blockSize: 4,\n * formatter: OpenSSLFormatter\n * });\n * ```\n */\n constructor(cipherParams?: CipherParamsCfg) {\n super();\n if (cipherParams) {\n this.mixIn(cipherParams);\n }\n // Set default formatter if not provided\n if (!this.formatter) {\n this.formatter = OpenSSLFormatter;\n }\n }\n\n /**\n * Factory method to create cipher params\n * \n * @param cipherParams - The cipher parameters\n * @returns A new CipherParams instance\n * @static\n */\n static create(cipherParams?: CipherParamsCfg): CipherParams;\n static create<T extends CipherParams>(this: new (...args: any[]) => T, ...args: any[]): T;\n static create(...args: any[]): any {\n const [cipherParams] = args;\n return new CipherParams(cipherParams);\n }\n\n /**\n * Converts this cipher params object to a string.\n * \n * @param formatter - The formatting strategy to use\n * @returns The stringified cipher params\n * @throws Error if neither the formatter nor the default formatter is set\n * @example\n * ```javascript\n * const string = cipherParams.toString();\n * const string = cipherParams.toString(OpenSSLFormatter);\n * ```\n */\n toString(formatter?: Format): string {\n const fmt = formatter || this.formatter;\n if (!fmt) {\n throw new Error('cipher params formatter required');\n }\n return fmt.stringify(this);\n }\n}\n\n/**\n * OpenSSL formatting strategy.\n * Formats cipher params in OpenSSL-compatible format.\n */\nexport const OpenSSLFormatter: Format = {\n /**\n * Converts a cipher params object to an OpenSSL-compatible string.\n * \n * @param cipherParams - The cipher params object\n * @returns The OpenSSL-compatible string\n * @example\n * ```javascript\n * const openSSLString = OpenSSLFormatter.stringify(cipherParams);\n * ```\n */\n stringify(cipherParams: CipherParams): string {\n let wordArray: WordArray;\n\n // Shortcuts\n const { ciphertext, salt } = cipherParams;\n\n // Format\n if (salt && ciphertext) {\n wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);\n } else if (ciphertext) {\n wordArray = ciphertext;\n } else {\n // No ciphertext, return empty\n wordArray = new WordArray();\n }\n\n return wordArray.toString(Base64);\n },\n\n /**\n * Converts an OpenSSL-compatible string to a cipher params object.\n * \n * @param openSSLStr - The OpenSSL-compatible string\n * @returns The cipher params object\n * @example\n * ```javascript\n * const cipherParams = OpenSSLFormatter.parse(openSSLString);\n * ```\n */\n parse(openSSLStr: string): CipherParams {\n let salt: WordArray | undefined;\n\n // Parse base64\n const ciphertext = Base64.parse(openSSLStr);\n\n // Shortcut\n const ciphertextWords = ciphertext.words;\n\n // Test for salt\n if (ciphertextWords[0] === 0x53616c74 && ciphertextWords[1] === 0x65645f5f) {\n // Extract salt\n salt = WordArray.create(ciphertextWords.slice(2, 4));\n\n // Remove salt from ciphertext\n ciphertextWords.splice(0, 4);\n ciphertext.sigBytes -= 16;\n }\n\n return CipherParams.create({ ciphertext, salt });\n }\n};\n\n/**\n * A cipher wrapper that returns ciphertext as a serializable cipher params object.\n * Handles the serialization and deserialization of cipher operations.\n */\nexport class SerializableCipher extends Base {\n /** Configuration options */\n static cfg: { format: Format } = { format: OpenSSLFormatter };\n\n /**\n * Encrypts a message.\n * \n * @param cipher - The cipher algorithm to use\n * @param message - The message to encrypt\n * @param key - The key\n * @param cfg - Configuration options to use for this operation\n * @returns A cipher params object\n * @static\n * @example\n * ```javascript\n * const ciphertextParams = SerializableCipher.encrypt(AESAlgo, message, key);\n * const ciphertextParams = SerializableCipher.encrypt(AESAlgo, message, key, { iv: iv });\n * ```\n */\n static encrypt(\n cipher: typeof Cipher,\n message: WordArray | string,\n key: WordArray | string,\n cfg?: CipherCfg\n ): CipherParams {\n // Apply config defaults\n const _cfg = Object.assign({}, this.cfg, cfg);\n\n // Encrypt\n const encryptor = (cipher as any).createEncryptor(key as WordArray, _cfg);\n const ciphertext = encryptor.finalize(message);\n\n // Shortcut\n const cipherCfg = encryptor.cfg;\n\n // Create and return serializable cipher params\n return CipherParams.create({\n ciphertext,\n key: key as WordArray,\n iv: cipherCfg.iv,\n algorithm: cipher,\n mode: cipherCfg.mode,\n padding: cipherCfg.padding,\n blockSize: encryptor.blockSize,\n formatter: _cfg.format || OpenSSLFormatter,\n });\n }\n\n /**\n * Decrypts serialized ciphertext.\n * \n * @param cipher - The cipher algorithm to use\n * @param ciphertext - The ciphertext to decrypt\n * @param key - The key\n * @param cfg - Configuration options to use for this operation\n * @returns The plaintext\n * @static\n * @example\n * ```javascript\n * const plaintext = SerializableCipher.decrypt(AESAlgo, formattedCiphertext, key, { iv: iv });\n * const plaintext = SerializableCipher.decrypt(AESAlgo, ciphertextParams, key, { iv: iv });\n * ```\n */\n static decrypt(\n cipher: typeof Cipher,\n ciphertext: CipherParams | CipherParamsCfg | string,\n key: WordArray | string,\n cfg?: CipherCfg\n ): WordArray {\n // Apply config defaults\n const _cfg = Object.assign({}, this.cfg, cfg);\n\n // Convert string to CipherParams\n const _ciphertext = this._parse(ciphertext, _cfg.format);\n\n // Decrypt\n const plaintext = (cipher as any).createDecryptor(key as WordArray, _cfg).finalize(_ciphertext.ciphertext!);\n\n return plaintext;\n }\n\n /**\n * Converts serialized ciphertext to CipherParams.\n * \n * @param ciphertext - The ciphertext\n * @param format - The formatting strategy to use to parse serialized ciphertext\n * @returns The unserialized ciphertext\n * @static\n * @private\n */\n protected static _parse(\n ciphertext: CipherParams | CipherParamsCfg | string,\n format?: Format\n ): CipherParams {\n if (typeof ciphertext === 'string') {\n if (!format) {\n throw new Error('Format required to parse string');\n }\n return format.parse(ciphertext, this);\n }\n if (ciphertext instanceof CipherParams) {\n return ciphertext;\n }\n return new CipherParams(ciphertext);\n }\n}\n\n/**\n * OpenSSL key derivation function.\n * Derives a key and IV from a password using the OpenSSL method.\n */\nexport const OpenSSLKdf: Kdf = {\n /**\n * Derives a key and IV from a password.\n * \n * @param password - The password to derive from\n * @param keySize - The size in words of the key to generate\n * @param ivSize - The size in words of the IV to generate\n * @param salt - A 64-bit salt to use (if omitted, a salt will be generated randomly)\n * @param hasher - The hasher to use\n * @returns A cipher params object with the key, IV, and salt\n * @example\n * ```javascript\n * const derivedParams = OpenSSLKdf.execute('Password', 256/32, 128/32);\n * const derivedParams = OpenSSLKdf.execute('Password', 256/32, 128/32, 'saltsalt');\n * ```\n */\n execute(\n password: string,\n keySize: number,\n ivSize: number,\n salt?: WordArray | string,\n hasher?: new (cfg?: HasherCfg) => Hasher\n ): CipherParams {\n let _salt: WordArray;\n\n // Generate random salt\n if (!salt) {\n _salt = WordArray.random(64 / 8);\n } else if (typeof salt === 'string') {\n // Parse string salt as hex or utf8\n _salt = Hex.parse(salt);\n } else {\n _salt = salt;\n }\n\n // Derive key and IV\n let key: WordArray;\n if (!hasher) {\n key = EvpKDFAlgo.create({ keySize: keySize + ivSize }).compute(password, _salt);\n } else {\n key = EvpKDFAlgo.create({ keySize: keySize + ivSize, hasher }).compute(password, _salt);\n }\n\n // Separate key and IV\n const iv = WordArray.create(key.words.slice(keySize), ivSize * 4);\n key.sigBytes = keySize * 4;\n\n // Return params\n return CipherParams.create({ key, iv, salt: _salt });\n }\n};\n\n/**\n * A serializable cipher wrapper that derives the key from a password.\n * Returns ciphertext as a serializable cipher params object.\n */\nexport class PasswordBasedCipher extends SerializableCipher {\n /** Configuration options */\n static cfg = Object.assign({}, SerializableCipher.cfg, { kdf: OpenSSLKdf });\n\n /**\n * Encrypts a message using a password.\n * \n * @param cipher - The cipher algorithm to use\n * @param message - The message to encrypt\n * @param password - The password\n * @param cfg - Configuration options to use for this operation\n * @returns A cipher params object\n * @static\n * @example\n * ```javascript\n * const ciphertextParams = PasswordBasedCipher.encrypt(AESAlgo, message, 'password');\n * ```\n */\n static encrypt(\n cipher: typeof Cipher,\n message: WordArray | string,\n password: string,\n cfg?: CipherCfg\n ): CipherParams {\n // Apply config defaults\n const _cfg = Object.assign({}, this.cfg, cfg);\n\n // Derive key and other params\n if (!_cfg.kdf) {\n throw new Error('KDF required for password-based encryption');\n }\n \n const derivedParams = _cfg.kdf.execute(\n password,\n (cipher as any).keySize || cipher.keySize,\n (cipher as any).ivSize || cipher.ivSize,\n _cfg.salt,\n _cfg.hasher\n );\n\n // Add IV to config\n _cfg.iv = derivedParams.iv;\n\n // Encrypt\n const ciphertext = SerializableCipher.encrypt.call(\n this,\n cipher,\n message,\n derivedParams.key!,\n _cfg\n );\n\n // Mix in derived params (only salt, not the whole object to avoid overwriting ciphertext)\n ciphertext.salt = derivedParams.salt;\n\n return ciphertext;\n }\n\n /**\n * Decrypts serialized ciphertext using a password.\n * \n * @param cipher - The cipher algorithm to use\n * @param ciphertext - The ciphertext to decrypt\n * @param password - The password\n * @param cfg - Configuration options to use for this operation\n * @returns The plaintext\n * @static\n * @example\n * ```javascript\n * const plaintext = PasswordBasedCipher.decrypt(AESAlgo, formattedCiphertext, 'password');\n * ```\n */\n static decrypt(\n cipher: typeof Cipher,\n ciphertext: CipherParams | CipherParamsCfg | string,\n password: string,\n cfg?: CipherCfg\n ): WordArray {\n // Apply config defaults\n const _cfg = Object.assign({}, this.cfg, cfg);\n\n // Convert string to CipherParams\n const _ciphertext = this._parse(ciphertext, _cfg.format);\n\n // Derive key and other params\n if (!_cfg.kdf) {\n throw new Error('KDF required for password-based decryption');\n }\n \n const derivedParams = _cfg.kdf.execute(\n password,\n (cipher as any).keySize || cipher.keySize,\n (cipher as any).ivSize || cipher.ivSize,\n _ciphertext.salt,\n _cfg.hasher\n );\n\n // Add IV to config\n _cfg.iv = derivedParams.iv;\n\n // Decrypt\n const plaintext = SerializableCipher.decrypt.call(\n this,\n cipher,\n _ciphertext,\n derivedParams.key!,\n _cfg\n );\n\n return plaintext;\n }\n}"],"mappings":"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"}