cipher-core.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. /* eslint-disable no-use-before-define */
  2. import {
  3. Base,
  4. WordArray,
  5. BufferedBlockAlgorithm,
  6. } from './core.js';
  7. import { Base64 } from './enc-base64.js';
  8. import { EvpKDFAlgo } from './evpkdf.js';
  9. /**
  10. * Abstract base cipher template.
  11. *
  12. * @property {number} keySize This cipher's key size. Default: 4 (128 bits)
  13. * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
  14. * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
  15. * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
  16. */
  17. export class Cipher extends BufferedBlockAlgorithm {
  18. /**
  19. * Initializes a newly created cipher.
  20. *
  21. * @param {number} xformMode Either the encryption or decryption transormation mode constant.
  22. * @param {WordArray} key The key.
  23. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  24. *
  25. * @example
  26. *
  27. * const cipher = CryptoJS.algo.AES.create(
  28. * CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }
  29. * );
  30. */
  31. constructor(xformMode, key, cfg) {
  32. super();
  33. /**
  34. * Configuration options.
  35. *
  36. * @property {WordArray} iv The IV to use for this operation.
  37. */
  38. this.cfg = Object.assign(new Base(), cfg);
  39. // Store transform mode and key
  40. this._xformMode = xformMode;
  41. this._key = key;
  42. // Set initial values
  43. this.reset();
  44. }
  45. /**
  46. * Creates this cipher in encryption mode.
  47. *
  48. * @param {WordArray} key The key.
  49. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  50. *
  51. * @return {Cipher} A cipher instance.
  52. *
  53. * @static
  54. *
  55. * @example
  56. *
  57. * const cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
  58. */
  59. static createEncryptor(key, cfg) {
  60. return this.create(this._ENC_XFORM_MODE, key, cfg);
  61. }
  62. /**
  63. * Creates this cipher in decryption mode.
  64. *
  65. * @param {WordArray} key The key.
  66. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  67. *
  68. * @return {Cipher} A cipher instance.
  69. *
  70. * @static
  71. *
  72. * @example
  73. *
  74. * const cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
  75. */
  76. static createDecryptor(key, cfg) {
  77. return this.create(this._DEC_XFORM_MODE, key, cfg);
  78. }
  79. /**
  80. * Creates shortcut functions to a cipher's object interface.
  81. *
  82. * @param {Cipher} cipher The cipher to create a helper for.
  83. *
  84. * @return {Object} An object with encrypt and decrypt shortcut functions.
  85. *
  86. * @static
  87. *
  88. * @example
  89. *
  90. * const AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
  91. */
  92. static _createHelper(SubCipher) {
  93. const selectCipherStrategy = (key) => {
  94. if (typeof key === 'string') {
  95. return PasswordBasedCipher;
  96. }
  97. return SerializableCipher;
  98. };
  99. return {
  100. encrypt(message, key, cfg) {
  101. return selectCipherStrategy(key).encrypt(SubCipher, message, key, cfg);
  102. },
  103. decrypt(ciphertext, key, cfg) {
  104. return selectCipherStrategy(key).decrypt(SubCipher, ciphertext, key, cfg);
  105. },
  106. };
  107. }
  108. /**
  109. * Resets this cipher to its initial state.
  110. *
  111. * @example
  112. *
  113. * cipher.reset();
  114. */
  115. reset() {
  116. // Reset data buffer
  117. super.reset.call(this);
  118. // Perform concrete-cipher logic
  119. this._doReset();
  120. }
  121. /**
  122. * Adds data to be encrypted or decrypted.
  123. *
  124. * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
  125. *
  126. * @return {WordArray} The data after processing.
  127. *
  128. * @example
  129. *
  130. * const encrypted = cipher.process('data');
  131. * const encrypted = cipher.process(wordArray);
  132. */
  133. process(dataUpdate) {
  134. // Append
  135. this._append(dataUpdate);
  136. // Process available blocks
  137. return this._process();
  138. }
  139. /**
  140. * Finalizes the encryption or decryption process.
  141. * Note that the finalize operation is effectively a destructive, read-once operation.
  142. *
  143. * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
  144. *
  145. * @return {WordArray} The data after final processing.
  146. *
  147. * @example
  148. *
  149. * const encrypted = cipher.finalize();
  150. * const encrypted = cipher.finalize('data');
  151. * const encrypted = cipher.finalize(wordArray);
  152. */
  153. finalize(dataUpdate) {
  154. // Final data update
  155. if (dataUpdate) {
  156. this._append(dataUpdate);
  157. }
  158. // Perform concrete-cipher logic
  159. const finalProcessedData = this._doFinalize();
  160. return finalProcessedData;
  161. }
  162. }
  163. Cipher._ENC_XFORM_MODE = 1;
  164. Cipher._DEC_XFORM_MODE = 2;
  165. Cipher.keySize = 128 / 32;
  166. Cipher.ivSize = 128 / 32;
  167. /**
  168. * Abstract base stream cipher template.
  169. *
  170. * @property {number} blockSize
  171. *
  172. * The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
  173. */
  174. export class StreamCipher extends Cipher {
  175. constructor(...args) {
  176. super(...args);
  177. this.blockSize = 1;
  178. }
  179. _doFinalize() {
  180. // Process partial blocks
  181. const finalProcessedBlocks = this._process(!!'flush');
  182. return finalProcessedBlocks;
  183. }
  184. }
  185. /**
  186. * Abstract base block cipher mode template.
  187. */
  188. export class BlockCipherMode extends Base {
  189. /**
  190. * Initializes a newly created mode.
  191. *
  192. * @param {Cipher} cipher A block cipher instance.
  193. * @param {Array} iv The IV words.
  194. *
  195. * @example
  196. *
  197. * const mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
  198. */
  199. constructor(cipher, iv) {
  200. super();
  201. this._cipher = cipher;
  202. this._iv = iv;
  203. }
  204. /**
  205. * Creates this mode for encryption.
  206. *
  207. * @param {Cipher} cipher A block cipher instance.
  208. * @param {Array} iv The IV words.
  209. *
  210. * @static
  211. *
  212. * @example
  213. *
  214. * const mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
  215. */
  216. static createEncryptor(cipher, iv) {
  217. return this.Encryptor.create(cipher, iv);
  218. }
  219. /**
  220. * Creates this mode for decryption.
  221. *
  222. * @param {Cipher} cipher A block cipher instance.
  223. * @param {Array} iv The IV words.
  224. *
  225. * @static
  226. *
  227. * @example
  228. *
  229. * const mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
  230. */
  231. static createDecryptor(cipher, iv) {
  232. return this.Decryptor.create(cipher, iv);
  233. }
  234. }
  235. function xorBlock(words, offset, blockSize) {
  236. const _words = words;
  237. let block;
  238. // Shortcut
  239. const iv = this._iv;
  240. // Choose mixing block
  241. if (iv) {
  242. block = iv;
  243. // Remove IV for subsequent blocks
  244. this._iv = undefined;
  245. } else {
  246. block = this._prevBlock;
  247. }
  248. // XOR blocks
  249. for (let i = 0; i < blockSize; i += 1) {
  250. _words[offset + i] ^= block[i];
  251. }
  252. }
  253. /**
  254. * Cipher Block Chaining mode.
  255. */
  256. /**
  257. * Abstract base CBC mode.
  258. */
  259. export class CBC extends BlockCipherMode {
  260. }
  261. /**
  262. * CBC encryptor.
  263. */
  264. CBC.Encryptor = class extends CBC {
  265. /**
  266. * Processes the data block at offset.
  267. *
  268. * @param {Array} words The data words to operate on.
  269. * @param {number} offset The offset where the block starts.
  270. *
  271. * @example
  272. *
  273. * mode.processBlock(data.words, offset);
  274. */
  275. processBlock(words, offset) {
  276. // Shortcuts
  277. const cipher = this._cipher;
  278. const { blockSize } = cipher;
  279. // XOR and encrypt
  280. xorBlock.call(this, words, offset, blockSize);
  281. cipher.encryptBlock(words, offset);
  282. // Remember this block to use with next block
  283. this._prevBlock = words.slice(offset, offset + blockSize);
  284. }
  285. };
  286. /**
  287. * CBC decryptor.
  288. */
  289. CBC.Decryptor = class extends CBC {
  290. /**
  291. * Processes the data block at offset.
  292. *
  293. * @param {Array} words The data words to operate on.
  294. * @param {number} offset The offset where the block starts.
  295. *
  296. * @example
  297. *
  298. * mode.processBlock(data.words, offset);
  299. */
  300. processBlock(words, offset) {
  301. // Shortcuts
  302. const cipher = this._cipher;
  303. const { blockSize } = cipher;
  304. // Remember this block to use with next block
  305. const thisBlock = words.slice(offset, offset + blockSize);
  306. // Decrypt and XOR
  307. cipher.decryptBlock(words, offset);
  308. xorBlock.call(this, words, offset, blockSize);
  309. // This block becomes the previous block
  310. this._prevBlock = thisBlock;
  311. }
  312. };
  313. /**
  314. * PKCS #5/7 padding strategy.
  315. */
  316. export const Pkcs7 = {
  317. /**
  318. * Pads data using the algorithm defined in PKCS #5/7.
  319. *
  320. * @param {WordArray} data The data to pad.
  321. * @param {number} blockSize The multiple that the data should be padded to.
  322. *
  323. * @static
  324. *
  325. * @example
  326. *
  327. * CryptoJS.pad.Pkcs7.pad(wordArray, 4);
  328. */
  329. pad(data, blockSize) {
  330. // Shortcut
  331. const blockSizeBytes = blockSize * 4;
  332. // Count padding bytes
  333. const nPaddingBytes = blockSizeBytes - (data.sigBytes % blockSizeBytes);
  334. // Create padding word
  335. const paddingWord = (nPaddingBytes << 24)
  336. | (nPaddingBytes << 16)
  337. | (nPaddingBytes << 8)
  338. | nPaddingBytes;
  339. // Create padding
  340. const paddingWords = [];
  341. for (let i = 0; i < nPaddingBytes; i += 4) {
  342. paddingWords.push(paddingWord);
  343. }
  344. const padding = WordArray.create(paddingWords, nPaddingBytes);
  345. // Add padding
  346. data.concat(padding);
  347. },
  348. /**
  349. * Unpads data that had been padded using the algorithm defined in PKCS #5/7.
  350. *
  351. * @param {WordArray} data The data to unpad.
  352. *
  353. * @static
  354. *
  355. * @example
  356. *
  357. * CryptoJS.pad.Pkcs7.unpad(wordArray);
  358. */
  359. unpad(data) {
  360. const _data = data;
  361. // Get number of padding bytes from last byte
  362. const nPaddingBytes = _data.words[(_data.sigBytes - 1) >>> 2] & 0xff;
  363. // Remove padding
  364. _data.sigBytes -= nPaddingBytes;
  365. },
  366. };
  367. /**
  368. * Abstract base block cipher template.
  369. *
  370. * @property {number} blockSize
  371. *
  372. * The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
  373. */
  374. export class BlockCipher extends Cipher {
  375. constructor(xformMode, key, cfg) {
  376. /**
  377. * Configuration options.
  378. *
  379. * @property {Mode} mode The block mode to use. Default: CBC
  380. * @property {Padding} padding The padding strategy to use. Default: Pkcs7
  381. */
  382. super(xformMode, key, Object.assign(
  383. {
  384. mode: CBC,
  385. padding: Pkcs7,
  386. },
  387. cfg,
  388. ));
  389. this.blockSize = 128 / 32;
  390. }
  391. reset() {
  392. let modeCreator;
  393. // Reset cipher
  394. super.reset.call(this);
  395. // Shortcuts
  396. const { cfg } = this;
  397. const { iv, mode } = cfg;
  398. // Reset block mode
  399. if (this._xformMode === this.constructor._ENC_XFORM_MODE) {
  400. modeCreator = mode.createEncryptor;
  401. } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
  402. modeCreator = mode.createDecryptor;
  403. // Keep at least one block in the buffer for unpadding
  404. this._minBufferSize = 1;
  405. }
  406. this._mode = modeCreator.call(mode, this, iv && iv.words);
  407. this._mode.__creator = modeCreator;
  408. }
  409. _doProcessBlock(words, offset) {
  410. this._mode.processBlock(words, offset);
  411. }
  412. _doFinalize() {
  413. let finalProcessedBlocks;
  414. // Shortcut
  415. const { padding } = this.cfg;
  416. // Finalize
  417. if (this._xformMode === this.constructor._ENC_XFORM_MODE) {
  418. // Pad data
  419. padding.pad(this._data, this.blockSize);
  420. // Process final blocks
  421. finalProcessedBlocks = this._process(!!'flush');
  422. } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
  423. // Process final blocks
  424. finalProcessedBlocks = this._process(!!'flush');
  425. // Unpad data
  426. padding.unpad(finalProcessedBlocks);
  427. }
  428. return finalProcessedBlocks;
  429. }
  430. }
  431. /**
  432. * A collection of cipher parameters.
  433. *
  434. * @property {WordArray} ciphertext The raw ciphertext.
  435. * @property {WordArray} key The key to this ciphertext.
  436. * @property {WordArray} iv The IV used in the ciphering operation.
  437. * @property {WordArray} salt The salt used with a key derivation function.
  438. * @property {Cipher} algorithm The cipher algorithm.
  439. * @property {Mode} mode The block mode used in the ciphering operation.
  440. * @property {Padding} padding The padding scheme used in the ciphering operation.
  441. * @property {number} blockSize The block size of the cipher.
  442. * @property {Format} formatter
  443. * The default formatting strategy to convert this cipher params object to a string.
  444. */
  445. export class CipherParams extends Base {
  446. /**
  447. * Initializes a newly created cipher params object.
  448. *
  449. * @param {Object} cipherParams An object with any of the possible cipher parameters.
  450. *
  451. * @example
  452. *
  453. * var cipherParams = CryptoJS.lib.CipherParams.create({
  454. * ciphertext: ciphertextWordArray,
  455. * key: keyWordArray,
  456. * iv: ivWordArray,
  457. * salt: saltWordArray,
  458. * algorithm: CryptoJS.algo.AES,
  459. * mode: CryptoJS.mode.CBC,
  460. * padding: CryptoJS.pad.PKCS7,
  461. * blockSize: 4,
  462. * formatter: CryptoJS.format.OpenSSL
  463. * });
  464. */
  465. constructor(cipherParams) {
  466. super();
  467. this.mixIn(cipherParams);
  468. }
  469. /**
  470. * Converts this cipher params object to a string.
  471. *
  472. * @param {Format} formatter (Optional) The formatting strategy to use.
  473. *
  474. * @return {string} The stringified cipher params.
  475. *
  476. * @throws Error If neither the formatter nor the default formatter is set.
  477. *
  478. * @example
  479. *
  480. * var string = cipherParams + '';
  481. * var string = cipherParams.toString();
  482. * var string = cipherParams.toString(CryptoJS.format.OpenSSL);
  483. */
  484. toString(formatter) {
  485. return (formatter || this.formatter).stringify(this);
  486. }
  487. }
  488. /**
  489. * OpenSSL formatting strategy.
  490. */
  491. export const OpenSSLFormatter = {
  492. /**
  493. * Converts a cipher params object to an OpenSSL-compatible string.
  494. *
  495. * @param {CipherParams} cipherParams The cipher params object.
  496. *
  497. * @return {string} The OpenSSL-compatible string.
  498. *
  499. * @static
  500. *
  501. * @example
  502. *
  503. * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
  504. */
  505. stringify(cipherParams) {
  506. let wordArray;
  507. // Shortcuts
  508. const { ciphertext, salt } = cipherParams;
  509. // Format
  510. if (salt) {
  511. wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
  512. } else {
  513. wordArray = ciphertext;
  514. }
  515. return wordArray.toString(Base64);
  516. },
  517. /**
  518. * Converts an OpenSSL-compatible string to a cipher params object.
  519. *
  520. * @param {string} openSSLStr The OpenSSL-compatible string.
  521. *
  522. * @return {CipherParams} The cipher params object.
  523. *
  524. * @static
  525. *
  526. * @example
  527. *
  528. * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
  529. */
  530. parse(openSSLStr) {
  531. let salt;
  532. // Parse base64
  533. const ciphertext = Base64.parse(openSSLStr);
  534. // Shortcut
  535. const ciphertextWords = ciphertext.words;
  536. // Test for salt
  537. if (ciphertextWords[0] === 0x53616c74 && ciphertextWords[1] === 0x65645f5f) {
  538. // Extract salt
  539. salt = WordArray.create(ciphertextWords.slice(2, 4));
  540. // Remove salt from ciphertext
  541. ciphertextWords.splice(0, 4);
  542. ciphertext.sigBytes -= 16;
  543. }
  544. return CipherParams.create({ ciphertext, salt });
  545. },
  546. };
  547. /**
  548. * A cipher wrapper that returns ciphertext as a serializable cipher params object.
  549. */
  550. export class SerializableCipher extends Base {
  551. /**
  552. * Encrypts a message.
  553. *
  554. * @param {Cipher} cipher The cipher algorithm to use.
  555. * @param {WordArray|string} message The message to encrypt.
  556. * @param {WordArray} key The key.
  557. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  558. *
  559. * @return {CipherParams} A cipher params object.
  560. *
  561. * @static
  562. *
  563. * @example
  564. *
  565. * var ciphertextParams = CryptoJS.lib.SerializableCipher
  566. * .encrypt(CryptoJS.algo.AES, message, key);
  567. * var ciphertextParams = CryptoJS.lib.SerializableCipher
  568. * .encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
  569. * var ciphertextParams = CryptoJS.lib.SerializableCipher
  570. * .encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
  571. */
  572. static encrypt(cipher, message, key, cfg) {
  573. // Apply config defaults
  574. const _cfg = Object.assign(new Base(), this.cfg, cfg);
  575. // Encrypt
  576. const encryptor = cipher.createEncryptor(key, _cfg);
  577. const ciphertext = encryptor.finalize(message);
  578. // Shortcut
  579. const cipherCfg = encryptor.cfg;
  580. // Create and return serializable cipher params
  581. return CipherParams.create({
  582. ciphertext,
  583. key,
  584. iv: cipherCfg.iv,
  585. algorithm: cipher,
  586. mode: cipherCfg.mode,
  587. padding: cipherCfg.padding,
  588. blockSize: encryptor.blockSize,
  589. formatter: _cfg.format,
  590. });
  591. }
  592. /**
  593. * Decrypts serialized ciphertext.
  594. *
  595. * @param {Cipher} cipher The cipher algorithm to use.
  596. * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
  597. * @param {WordArray} key The key.
  598. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  599. *
  600. * @return {WordArray} The plaintext.
  601. *
  602. * @static
  603. *
  604. * @example
  605. *
  606. * var plaintext = CryptoJS.lib.SerializableCipher
  607. * .decrypt(CryptoJS.algo.AES, formattedCiphertext, key,
  608. * { iv: iv, format: CryptoJS.format.OpenSSL });
  609. * var plaintext = CryptoJS.lib.SerializableCipher
  610. * .decrypt(CryptoJS.algo.AES, ciphertextParams, key,
  611. * { iv: iv, format: CryptoJS.format.OpenSSL });
  612. */
  613. static decrypt(cipher, ciphertext, key, cfg) {
  614. let _ciphertext = ciphertext;
  615. // Apply config defaults
  616. const _cfg = Object.assign(new Base(), this.cfg, cfg);
  617. // Convert string to CipherParams
  618. _ciphertext = this._parse(_ciphertext, _cfg.format);
  619. // Decrypt
  620. const plaintext = cipher.createDecryptor(key, _cfg).finalize(_ciphertext.ciphertext);
  621. return plaintext;
  622. }
  623. /**
  624. * Converts serialized ciphertext to CipherParams,
  625. * else assumed CipherParams already and returns ciphertext unchanged.
  626. *
  627. * @param {CipherParams|string} ciphertext The ciphertext.
  628. * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
  629. *
  630. * @return {CipherParams} The unserialized ciphertext.
  631. *
  632. * @static
  633. *
  634. * @example
  635. *
  636. * var ciphertextParams = CryptoJS.lib.SerializableCipher
  637. * ._parse(ciphertextStringOrParams, format);
  638. */
  639. static _parse(ciphertext, format) {
  640. if (typeof ciphertext === 'string') {
  641. return format.parse(ciphertext, this);
  642. }
  643. return ciphertext;
  644. }
  645. }
  646. /**
  647. * Configuration options.
  648. *
  649. * @property {Formatter} format
  650. *
  651. * The formatting strategy to convert cipher param objects to and from a string.
  652. * Default: OpenSSL
  653. */
  654. SerializableCipher.cfg = Object.assign(
  655. new Base(),
  656. { format: OpenSSLFormatter },
  657. );
  658. /**
  659. * OpenSSL key derivation function.
  660. */
  661. export const OpenSSLKdf = {
  662. /**
  663. * Derives a key and IV from a password.
  664. *
  665. * @param {string} password The password to derive from.
  666. * @param {number} keySize The size in words of the key to generate.
  667. * @param {number} ivSize The size in words of the IV to generate.
  668. * @param {WordArray|string} salt
  669. * (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
  670. *
  671. * @return {CipherParams} A cipher params object with the key, IV, and salt.
  672. *
  673. * @static
  674. *
  675. * @example
  676. *
  677. * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
  678. * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
  679. */
  680. execute(password, keySize, ivSize, salt) {
  681. let _salt = salt;
  682. // Generate random salt
  683. if (!_salt) {
  684. _salt = WordArray.random(64 / 8);
  685. }
  686. // Derive key and IV
  687. const key = EvpKDFAlgo.create({ keySize: keySize + ivSize }).compute(password, _salt);
  688. // Separate key and IV
  689. const iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
  690. key.sigBytes = keySize * 4;
  691. // Return params
  692. return CipherParams.create({ key, iv, salt: _salt });
  693. },
  694. };
  695. /**
  696. * A serializable cipher wrapper that derives the key from a password,
  697. * and returns ciphertext as a serializable cipher params object.
  698. */
  699. export class PasswordBasedCipher extends SerializableCipher {
  700. /**
  701. * Encrypts a message using a password.
  702. *
  703. * @param {Cipher} cipher The cipher algorithm to use.
  704. * @param {WordArray|string} message The message to encrypt.
  705. * @param {string} password The password.
  706. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  707. *
  708. * @return {CipherParams} A cipher params object.
  709. *
  710. * @static
  711. *
  712. * @example
  713. *
  714. * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher
  715. * .encrypt(CryptoJS.algo.AES, message, 'password');
  716. * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher
  717. * .encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
  718. */
  719. static encrypt(cipher, message, password, cfg) {
  720. // Apply config defaults
  721. const _cfg = Object.assign(new Base(), this.cfg, cfg);
  722. // Derive key and other params
  723. const derivedParams = _cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);
  724. // Add IV to config
  725. _cfg.iv = derivedParams.iv;
  726. // Encrypt
  727. const ciphertext = SerializableCipher.encrypt
  728. .call(this, cipher, message, derivedParams.key, _cfg);
  729. // Mix in derived params
  730. ciphertext.mixIn(derivedParams);
  731. return ciphertext;
  732. }
  733. /**
  734. * Decrypts serialized ciphertext using a password.
  735. *
  736. * @param {Cipher} cipher The cipher algorithm to use.
  737. * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
  738. * @param {string} password The password.
  739. * @param {Object} cfg (Optional) The configuration options to use for this operation.
  740. *
  741. * @return {WordArray} The plaintext.
  742. *
  743. * @static
  744. *
  745. * @example
  746. *
  747. * var plaintext = CryptoJS.lib.PasswordBasedCipher
  748. * .decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password',
  749. * { format: CryptoJS.format.OpenSSL });
  750. * var plaintext = CryptoJS.lib.PasswordBasedCipher
  751. * .decrypt(CryptoJS.algo.AES, ciphertextParams, 'password',
  752. * { format: CryptoJS.format.OpenSSL });
  753. */
  754. static decrypt(cipher, ciphertext, password, cfg) {
  755. let _ciphertext = ciphertext;
  756. // Apply config defaults
  757. const _cfg = Object.assign(new Base(), this.cfg, cfg);
  758. // Convert string to CipherParams
  759. _ciphertext = this._parse(_ciphertext, _cfg.format);
  760. // Derive key and other params
  761. const derivedParams = _cfg.kdf
  762. .execute(password, cipher.keySize, cipher.ivSize, _ciphertext.salt);
  763. // Add IV to config
  764. _cfg.iv = derivedParams.iv;
  765. // Decrypt
  766. const plaintext = SerializableCipher.decrypt
  767. .call(this, cipher, _ciphertext, derivedParams.key, _cfg);
  768. return plaintext;
  769. }
  770. }
  771. /**
  772. * Configuration options.
  773. *
  774. * @property {KDF} kdf
  775. * The key derivation function to use to generate a key and IV from a password.
  776. * Default: OpenSSL
  777. */
  778. PasswordBasedCipher.cfg = Object.assign(SerializableCipher.cfg, { kdf: OpenSSLKdf });