core.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /* eslint-disable no-use-before-define */
  2. /**
  3. * Base class for inheritance.
  4. */
  5. export class Base {
  6. /**
  7. * Extends this object and runs the init method.
  8. * Arguments to create() will be passed to init().
  9. *
  10. * @return {Object} The new object.
  11. *
  12. * @static
  13. *
  14. * @example
  15. *
  16. * var instance = MyType.create();
  17. */
  18. static create(...args) {
  19. return new this(...args);
  20. }
  21. /**
  22. * Copies properties into this object.
  23. *
  24. * @param {Object} properties The properties to mix in.
  25. *
  26. * @example
  27. *
  28. * MyType.mixIn({
  29. * field: 'value'
  30. * });
  31. */
  32. mixIn(properties) {
  33. return Object.assign(this, properties);
  34. }
  35. /**
  36. * Creates a copy of this object.
  37. *
  38. * @return {Object} The clone.
  39. *
  40. * @example
  41. *
  42. * var clone = instance.clone();
  43. */
  44. clone() {
  45. const clone = new this.constructor();
  46. Object.assign(clone, this);
  47. return clone;
  48. }
  49. }
  50. /**
  51. * An array of 32-bit words.
  52. *
  53. * @property {Array} words The array of 32-bit words.
  54. * @property {number} sigBytes The number of significant bytes in this word array.
  55. */
  56. export class WordArray extends Base {
  57. /**
  58. * Initializes a newly created word array.
  59. *
  60. * @param {Array} words (Optional) An array of 32-bit words.
  61. * @param {number} sigBytes (Optional) The number of significant bytes in the words.
  62. *
  63. * @example
  64. *
  65. * var wordArray = CryptoJS.lib.WordArray.create();
  66. * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
  67. * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
  68. */
  69. constructor(words = [], sigBytes = words.length * 4) {
  70. super();
  71. let typedArray = words;
  72. // Convert buffers to uint8
  73. if (typedArray instanceof ArrayBuffer) {
  74. typedArray = new Uint8Array(typedArray);
  75. }
  76. // Convert other array views to uint8
  77. if (
  78. typedArray instanceof Int8Array
  79. || typedArray instanceof Uint8ClampedArray
  80. || typedArray instanceof Int16Array
  81. || typedArray instanceof Uint16Array
  82. || typedArray instanceof Int32Array
  83. || typedArray instanceof Uint32Array
  84. || typedArray instanceof Float32Array
  85. || typedArray instanceof Float64Array
  86. ) {
  87. typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
  88. }
  89. // Handle Uint8Array
  90. if (typedArray instanceof Uint8Array) {
  91. // Shortcut
  92. const typedArrayByteLength = typedArray.byteLength;
  93. // Extract bytes
  94. const _words = [];
  95. for (let i = 0; i < typedArrayByteLength; i += 1) {
  96. _words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);
  97. }
  98. // Initialize this word array
  99. this.words = _words;
  100. this.sigBytes = typedArrayByteLength;
  101. } else {
  102. // Else call normal init
  103. this.words = words;
  104. this.sigBytes = sigBytes;
  105. }
  106. }
  107. /**
  108. * Creates a word array filled with random bytes.
  109. *
  110. * @param {number} nBytes The number of random bytes to generate.
  111. *
  112. * @return {WordArray} The random word array.
  113. *
  114. * @static
  115. *
  116. * @example
  117. *
  118. * var wordArray = CryptoJS.lib.WordArray.random(16);
  119. */
  120. static random(nBytes) {
  121. const words = [];
  122. const r = (m_w) => {
  123. let _m_w = m_w;
  124. let _m_z = 0x3ade68b1;
  125. const mask = 0xffffffff;
  126. return () => {
  127. _m_z = (0x9069 * (_m_z & 0xFFFF) + (_m_z >> 0x10)) & mask;
  128. _m_w = (0x4650 * (_m_w & 0xFFFF) + (_m_w >> 0x10)) & mask;
  129. let result = ((_m_z << 0x10) + _m_w) & mask;
  130. result /= 0x100000000;
  131. result += 0.5;
  132. return result * (Math.random() > 0.5 ? 1 : -1);
  133. };
  134. };
  135. for (let i = 0, rcache; i < nBytes; i += 4) {
  136. const _r = r((rcache || Math.random()) * 0x100000000);
  137. rcache = _r() * 0x3ade67b7;
  138. words.push((_r() * 0x100000000) | 0);
  139. }
  140. return new WordArray(words, nBytes);
  141. }
  142. /**
  143. * Converts this word array to a string.
  144. *
  145. * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
  146. *
  147. * @return {string} The stringified word array.
  148. *
  149. * @example
  150. *
  151. * var string = wordArray + '';
  152. * var string = wordArray.toString();
  153. * var string = wordArray.toString(CryptoJS.enc.Utf8);
  154. */
  155. toString(encoder = Hex) {
  156. return encoder.stringify(this);
  157. }
  158. /**
  159. * Concatenates a word array to this word array.
  160. *
  161. * @param {WordArray} wordArray The word array to append.
  162. *
  163. * @return {WordArray} This word array.
  164. *
  165. * @example
  166. *
  167. * wordArray1.concat(wordArray2);
  168. */
  169. concat(wordArray) {
  170. // Shortcuts
  171. const thisWords = this.words;
  172. const thatWords = wordArray.words;
  173. const thisSigBytes = this.sigBytes;
  174. const thatSigBytes = wordArray.sigBytes;
  175. // Clamp excess bits
  176. this.clamp();
  177. // Concat
  178. if (thisSigBytes % 4) {
  179. // Copy one byte at a time
  180. for (let i = 0; i < thatSigBytes; i += 1) {
  181. const thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
  182. thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
  183. }
  184. } else {
  185. // Copy one word at a time
  186. for (let i = 0; i < thatSigBytes; i += 4) {
  187. thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
  188. }
  189. }
  190. this.sigBytes += thatSigBytes;
  191. // Chainable
  192. return this;
  193. }
  194. /**
  195. * Removes insignificant bits.
  196. *
  197. * @example
  198. *
  199. * wordArray.clamp();
  200. */
  201. clamp() {
  202. // Shortcuts
  203. const { words, sigBytes } = this;
  204. // Clamp
  205. words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
  206. words.length = Math.ceil(sigBytes / 4);
  207. }
  208. /**
  209. * Creates a copy of this word array.
  210. *
  211. * @return {WordArray} The clone.
  212. *
  213. * @example
  214. *
  215. * var clone = wordArray.clone();
  216. */
  217. clone() {
  218. const clone = super.clone.call(this);
  219. clone.words = this.words.slice(0);
  220. return clone;
  221. }
  222. }
  223. /**
  224. * Hex encoding strategy.
  225. */
  226. export const Hex = {
  227. /**
  228. * Converts a word array to a hex string.
  229. *
  230. * @param {WordArray} wordArray The word array.
  231. *
  232. * @return {string} The hex string.
  233. *
  234. * @static
  235. *
  236. * @example
  237. *
  238. * var hexString = CryptoJS.enc.Hex.stringify(wordArray);
  239. */
  240. stringify(wordArray) {
  241. // Shortcuts
  242. const { words, sigBytes } = wordArray;
  243. // Convert
  244. const hexChars = [];
  245. for (let i = 0; i < sigBytes; i += 1) {
  246. const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
  247. hexChars.push((bite >>> 4).toString(16));
  248. hexChars.push((bite & 0x0f).toString(16));
  249. }
  250. return hexChars.join('');
  251. },
  252. /**
  253. * Converts a hex string to a word array.
  254. *
  255. * @param {string} hexStr The hex string.
  256. *
  257. * @return {WordArray} The word array.
  258. *
  259. * @static
  260. *
  261. * @example
  262. *
  263. * var wordArray = CryptoJS.enc.Hex.parse(hexString);
  264. */
  265. parse(hexStr) {
  266. // Shortcut
  267. const hexStrLength = hexStr.length;
  268. // Convert
  269. const words = [];
  270. for (let i = 0; i < hexStrLength; i += 2) {
  271. words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
  272. }
  273. return new WordArray(words, hexStrLength / 2);
  274. },
  275. };
  276. /**
  277. * Latin1 encoding strategy.
  278. */
  279. export const Latin1 = {
  280. /**
  281. * Converts a word array to a Latin1 string.
  282. *
  283. * @param {WordArray} wordArray The word array.
  284. *
  285. * @return {string} The Latin1 string.
  286. *
  287. * @static
  288. *
  289. * @example
  290. *
  291. * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
  292. */
  293. stringify(wordArray) {
  294. // Shortcuts
  295. const { words, sigBytes } = wordArray;
  296. // Convert
  297. const latin1Chars = [];
  298. for (let i = 0; i < sigBytes; i += 1) {
  299. const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
  300. latin1Chars.push(String.fromCharCode(bite));
  301. }
  302. return latin1Chars.join('');
  303. },
  304. /**
  305. * Converts a Latin1 string to a word array.
  306. *
  307. * @param {string} latin1Str The Latin1 string.
  308. *
  309. * @return {WordArray} The word array.
  310. *
  311. * @static
  312. *
  313. * @example
  314. *
  315. * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
  316. */
  317. parse(latin1Str) {
  318. // Shortcut
  319. const latin1StrLength = latin1Str.length;
  320. // Convert
  321. const words = [];
  322. for (let i = 0; i < latin1StrLength; i += 1) {
  323. words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
  324. }
  325. return new WordArray(words, latin1StrLength);
  326. },
  327. };
  328. /**
  329. * UTF-8 encoding strategy.
  330. */
  331. export const Utf8 = {
  332. /**
  333. * Converts a word array to a UTF-8 string.
  334. *
  335. * @param {WordArray} wordArray The word array.
  336. *
  337. * @return {string} The UTF-8 string.
  338. *
  339. * @static
  340. *
  341. * @example
  342. *
  343. * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
  344. */
  345. stringify(wordArray) {
  346. try {
  347. return decodeURIComponent(escape(Latin1.stringify(wordArray)));
  348. } catch (e) {
  349. throw new Error('Malformed UTF-8 data');
  350. }
  351. },
  352. /**
  353. * Converts a UTF-8 string to a word array.
  354. *
  355. * @param {string} utf8Str The UTF-8 string.
  356. *
  357. * @return {WordArray} The word array.
  358. *
  359. * @static
  360. *
  361. * @example
  362. *
  363. * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
  364. */
  365. parse(utf8Str) {
  366. return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
  367. },
  368. };
  369. /**
  370. * Abstract buffered block algorithm template.
  371. *
  372. * The property blockSize must be implemented in a concrete subtype.
  373. *
  374. * @property {number} _minBufferSize
  375. *
  376. * The number of blocks that should be kept unprocessed in the buffer. Default: 0
  377. */
  378. export class BufferedBlockAlgorithm extends Base {
  379. constructor() {
  380. super();
  381. this._minBufferSize = 0;
  382. }
  383. /**
  384. * Resets this block algorithm's data buffer to its initial state.
  385. *
  386. * @example
  387. *
  388. * bufferedBlockAlgorithm.reset();
  389. */
  390. reset() {
  391. // Initial values
  392. this._data = new WordArray();
  393. this._nDataBytes = 0;
  394. }
  395. /**
  396. * Adds new data to this block algorithm's buffer.
  397. *
  398. * @param {WordArray|string} data
  399. *
  400. * The data to append. Strings are converted to a WordArray using UTF-8.
  401. *
  402. * @example
  403. *
  404. * bufferedBlockAlgorithm._append('data');
  405. * bufferedBlockAlgorithm._append(wordArray);
  406. */
  407. _append(data) {
  408. let m_data = data;
  409. // Convert string to WordArray, else assume WordArray already
  410. if (typeof m_data === 'string') {
  411. m_data = Utf8.parse(m_data);
  412. }
  413. // Append
  414. this._data.concat(m_data);
  415. this._nDataBytes += m_data.sigBytes;
  416. }
  417. /**
  418. * Processes available data blocks.
  419. *
  420. * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
  421. *
  422. * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
  423. *
  424. * @return {WordArray} The processed data.
  425. *
  426. * @example
  427. *
  428. * var processedData = bufferedBlockAlgorithm._process();
  429. * var processedData = bufferedBlockAlgorithm._process(!!'flush');
  430. */
  431. _process(doFlush) {
  432. let processedWords;
  433. // Shortcuts
  434. const { _data: data, blockSize } = this;
  435. const dataWords = data.words;
  436. const dataSigBytes = data.sigBytes;
  437. const blockSizeBytes = blockSize * 4;
  438. // Count blocks ready
  439. let nBlocksReady = dataSigBytes / blockSizeBytes;
  440. if (doFlush) {
  441. // Round up to include partial blocks
  442. nBlocksReady = Math.ceil(nBlocksReady);
  443. } else {
  444. // Round down to include only full blocks,
  445. // less the number of blocks that must remain in the buffer
  446. nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
  447. }
  448. // Count words ready
  449. const nWordsReady = nBlocksReady * blockSize;
  450. // Count bytes ready
  451. const nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
  452. // Process blocks
  453. if (nWordsReady) {
  454. for (let offset = 0; offset < nWordsReady; offset += blockSize) {
  455. // Perform concrete-algorithm logic
  456. this._doProcessBlock(dataWords, offset);
  457. }
  458. // Remove processed words
  459. processedWords = dataWords.splice(0, nWordsReady);
  460. data.sigBytes -= nBytesReady;
  461. }
  462. // Return processed words
  463. return new WordArray(processedWords, nBytesReady);
  464. }
  465. /**
  466. * Creates a copy of this object.
  467. *
  468. * @return {Object} The clone.
  469. *
  470. * @example
  471. *
  472. * var clone = bufferedBlockAlgorithm.clone();
  473. */
  474. clone() {
  475. const clone = super.clone.call(this);
  476. clone._data = this._data.clone();
  477. return clone;
  478. }
  479. }
  480. /**
  481. * Abstract hasher template.
  482. *
  483. * @property {number} blockSize
  484. *
  485. * The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
  486. */
  487. export class Hasher extends BufferedBlockAlgorithm {
  488. constructor(cfg) {
  489. super();
  490. this.blockSize = 512 / 32;
  491. /**
  492. * Configuration options.
  493. */
  494. this.cfg = Object.assign(new Base(), cfg);
  495. // Set initial values
  496. this.reset();
  497. }
  498. /**
  499. * Creates a shortcut function to a hasher's object interface.
  500. *
  501. * @param {Hasher} SubHasher The hasher to create a helper for.
  502. *
  503. * @return {Function} The shortcut function.
  504. *
  505. * @static
  506. *
  507. * @example
  508. *
  509. * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
  510. */
  511. static _createHelper(SubHasher) {
  512. return (message, cfg) => new SubHasher(cfg).finalize(message);
  513. }
  514. /**
  515. * Creates a shortcut function to the HMAC's object interface.
  516. *
  517. * @param {Hasher} SubHasher The hasher to use in this HMAC helper.
  518. *
  519. * @return {Function} The shortcut function.
  520. *
  521. * @static
  522. *
  523. * @example
  524. *
  525. * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
  526. */
  527. static _createHmacHelper(SubHasher) {
  528. return (message, key) => new HMAC(SubHasher, key).finalize(message);
  529. }
  530. /**
  531. * Resets this hasher to its initial state.
  532. *
  533. * @example
  534. *
  535. * hasher.reset();
  536. */
  537. reset() {
  538. // Reset data buffer
  539. super.reset.call(this);
  540. // Perform concrete-hasher logic
  541. this._doReset();
  542. }
  543. /**
  544. * Updates this hasher with a message.
  545. *
  546. * @param {WordArray|string} messageUpdate The message to append.
  547. *
  548. * @return {Hasher} This hasher.
  549. *
  550. * @example
  551. *
  552. * hasher.update('message');
  553. * hasher.update(wordArray);
  554. */
  555. update(messageUpdate) {
  556. // Append
  557. this._append(messageUpdate);
  558. // Update the hash
  559. this._process();
  560. // Chainable
  561. return this;
  562. }
  563. /**
  564. * Finalizes the hash computation.
  565. * Note that the finalize operation is effectively a destructive, read-once operation.
  566. *
  567. * @param {WordArray|string} messageUpdate (Optional) A final message update.
  568. *
  569. * @return {WordArray} The hash.
  570. *
  571. * @example
  572. *
  573. * var hash = hasher.finalize();
  574. * var hash = hasher.finalize('message');
  575. * var hash = hasher.finalize(wordArray);
  576. */
  577. finalize(messageUpdate) {
  578. // Final message update
  579. if (messageUpdate) {
  580. this._append(messageUpdate);
  581. }
  582. // Perform concrete-hasher logic
  583. const hash = this._doFinalize();
  584. return hash;
  585. }
  586. }
  587. /**
  588. * HMAC algorithm.
  589. */
  590. export class HMAC extends Base {
  591. /**
  592. * Initializes a newly created HMAC.
  593. *
  594. * @param {Hasher} SubHasher The hash algorithm to use.
  595. * @param {WordArray|string} key The secret key.
  596. *
  597. * @example
  598. *
  599. * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
  600. */
  601. constructor(SubHasher, key) {
  602. super();
  603. const hasher = new SubHasher();
  604. this._hasher = hasher;
  605. // Convert string to WordArray, else assume WordArray already
  606. let _key = key;
  607. if (typeof _key === 'string') {
  608. _key = Utf8.parse(_key);
  609. }
  610. // Shortcuts
  611. const hasherBlockSize = hasher.blockSize;
  612. const hasherBlockSizeBytes = hasherBlockSize * 4;
  613. // Allow arbitrary length keys
  614. if (_key.sigBytes > hasherBlockSizeBytes) {
  615. _key = hasher.finalize(key);
  616. }
  617. // Clamp excess bits
  618. _key.clamp();
  619. // Clone key for inner and outer pads
  620. const oKey = _key.clone();
  621. this._oKey = oKey;
  622. const iKey = _key.clone();
  623. this._iKey = iKey;
  624. // Shortcuts
  625. const oKeyWords = oKey.words;
  626. const iKeyWords = iKey.words;
  627. // XOR keys with pad constants
  628. for (let i = 0; i < hasherBlockSize; i += 1) {
  629. oKeyWords[i] ^= 0x5c5c5c5c;
  630. iKeyWords[i] ^= 0x36363636;
  631. }
  632. oKey.sigBytes = hasherBlockSizeBytes;
  633. iKey.sigBytes = hasherBlockSizeBytes;
  634. // Set initial values
  635. this.reset();
  636. }
  637. /**
  638. * Resets this HMAC to its initial state.
  639. *
  640. * @example
  641. *
  642. * hmacHasher.reset();
  643. */
  644. reset() {
  645. // Shortcut
  646. const hasher = this._hasher;
  647. // Reset
  648. hasher.reset();
  649. hasher.update(this._iKey);
  650. }
  651. /**
  652. * Updates this HMAC with a message.
  653. *
  654. * @param {WordArray|string} messageUpdate The message to append.
  655. *
  656. * @return {HMAC} This HMAC instance.
  657. *
  658. * @example
  659. *
  660. * hmacHasher.update('message');
  661. * hmacHasher.update(wordArray);
  662. */
  663. update(messageUpdate) {
  664. this._hasher.update(messageUpdate);
  665. // Chainable
  666. return this;
  667. }
  668. /**
  669. * Finalizes the HMAC computation.
  670. * Note that the finalize operation is effectively a destructive, read-once operation.
  671. *
  672. * @param {WordArray|string} messageUpdate (Optional) A final message update.
  673. *
  674. * @return {WordArray} The HMAC.
  675. *
  676. * @example
  677. *
  678. * var hmac = hmacHasher.finalize();
  679. * var hmac = hmacHasher.finalize('message');
  680. * var hmac = hmacHasher.finalize(wordArray);
  681. */
  682. finalize(messageUpdate) {
  683. // Shortcut
  684. const hasher = this._hasher;
  685. // Compute HMAC
  686. const innerHash = hasher.finalize(messageUpdate);
  687. hasher.reset();
  688. const hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
  689. return hmac;
  690. }
  691. }