Cipher.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. import Utils from "../Utils.js";
  2. import CryptoJS from "crypto-js";
  3. import {blowfish as Blowfish} from "sladex-blowfish";
  4. /**
  5. * Cipher operations.
  6. *
  7. * @author n1474335 [n1474335@gmail.com]
  8. * @copyright Crown Copyright 2016
  9. * @license Apache-2.0
  10. *
  11. * @namespace
  12. */
  13. const Cipher = {
  14. /**
  15. * @constant
  16. * @default
  17. */
  18. IO_FORMAT1: ["Hex", "Base64", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
  19. /**
  20. * @constant
  21. * @default
  22. */
  23. IO_FORMAT2: ["UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1", "Hex", "Base64"],
  24. /**
  25. * @constant
  26. * @default
  27. */
  28. IO_FORMAT3: ["Hex", "Base64", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
  29. /**
  30. * @constant
  31. * @default
  32. */
  33. IO_FORMAT4: ["Latin1", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Hex", "Base64"],
  34. /**
  35. * @constant
  36. * @default
  37. */
  38. MODES: ["CBC", "CFB", "CTR", "OFB", "ECB"],
  39. /**
  40. * @constant
  41. * @default
  42. */
  43. PADDING: ["Pkcs7", "Iso97971", "AnsiX923", "Iso10126", "ZeroPadding", "NoPadding"],
  44. /**
  45. * @constant
  46. * @default
  47. */
  48. RESULT_TYPE: ["Show all", "Ciphertext", "Key", "IV", "Salt"],
  49. /**
  50. * Runs encryption operations using the CryptoJS framework.
  51. *
  52. * @private
  53. * @param {function} algo - The CryptoJS algorithm to use
  54. * @param {byteArray} input
  55. * @param {function} args
  56. * @returns {string}
  57. */
  58. _enc: function (algo, input, args) {
  59. let key = Utils.format[args[0].option].parse(args[0].string || ""),
  60. iv = Utils.format[args[1].option].parse(args[1].string || ""),
  61. salt = Utils.format[args[2].option].parse(args[2].string || ""),
  62. mode = CryptoJS.mode[args[3]],
  63. padding = CryptoJS.pad[args[4]],
  64. resultOption = args[5].toLowerCase(),
  65. outputFormat = args[6];
  66. if (iv.sigBytes === 0) {
  67. // Use passphrase rather than key. Need to convert it to a string.
  68. key = key.toString(CryptoJS.enc.Latin1);
  69. }
  70. const encrypted = algo.encrypt(input, key, {
  71. salt: salt.sigBytes > 0 ? salt : false,
  72. iv: iv.sigBytes > 0 ? iv : null,
  73. mode: mode,
  74. padding: padding
  75. });
  76. let result = "";
  77. if (resultOption === "show all") {
  78. result += "Key: " + encrypted.key.toString(Utils.format[outputFormat]);
  79. result += "\nIV: " + encrypted.iv.toString(Utils.format[outputFormat]);
  80. if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[outputFormat]);
  81. result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[outputFormat]);
  82. } else {
  83. result = encrypted[resultOption].toString(Utils.format[outputFormat]);
  84. }
  85. return result;
  86. },
  87. /**
  88. * Runs decryption operations using the CryptoJS framework.
  89. *
  90. * @private
  91. * @param {function} algo - The CryptoJS algorithm to use
  92. * @param {byteArray} input
  93. * @param {function} args
  94. * @returns {string}
  95. */
  96. _dec: function (algo, input, args) {
  97. let key = Utils.format[args[0].option].parse(args[0].string || ""),
  98. iv = Utils.format[args[1].option].parse(args[1].string || ""),
  99. salt = Utils.format[args[2].option].parse(args[2].string || ""),
  100. mode = CryptoJS.mode[args[3]],
  101. padding = CryptoJS.pad[args[4]],
  102. inputFormat = args[5],
  103. outputFormat = args[6];
  104. // The ZeroPadding option causes a crash when the input length is 0
  105. if (!input.length) {
  106. return "No input";
  107. }
  108. const ciphertext = Utils.format[inputFormat].parse(input);
  109. if (iv.sigBytes === 0) {
  110. // Use passphrase rather than key. Need to convert it to a string.
  111. key = key.toString(CryptoJS.enc.Latin1);
  112. }
  113. const decrypted = algo.decrypt({
  114. ciphertext: ciphertext,
  115. salt: salt.sigBytes > 0 ? salt : false
  116. }, key, {
  117. iv: iv.sigBytes > 0 ? iv : null,
  118. mode: mode,
  119. padding: padding
  120. });
  121. let result;
  122. try {
  123. result = decrypted.toString(Utils.format[outputFormat]);
  124. } catch (err) {
  125. result = "Decrypt error: " + err.message;
  126. }
  127. return result;
  128. },
  129. /**
  130. * AES Encrypt operation.
  131. *
  132. * @param {string} input
  133. * @param {Object[]} args
  134. * @returns {string}
  135. */
  136. runAesEnc: function (input, args) {
  137. return Cipher._enc(CryptoJS.AES, input, args);
  138. },
  139. /**
  140. * AES Decrypt operation.
  141. *
  142. * @param {string} input
  143. * @param {Object[]} args
  144. * @returns {string}
  145. */
  146. runAesDec: function (input, args) {
  147. return Cipher._dec(CryptoJS.AES, input, args);
  148. },
  149. /**
  150. * DES Encrypt operation.
  151. *
  152. * @param {string} input
  153. * @param {Object[]} args
  154. * @returns {string}
  155. */
  156. runDesEnc: function (input, args) {
  157. return Cipher._enc(CryptoJS.DES, input, args);
  158. },
  159. /**
  160. * DES Decrypt operation.
  161. *
  162. * @param {string} input
  163. * @param {Object[]} args
  164. * @returns {string}
  165. */
  166. runDesDec: function (input, args) {
  167. return Cipher._dec(CryptoJS.DES, input, args);
  168. },
  169. /**
  170. * Triple DES Encrypt operation.
  171. *
  172. * @param {string} input
  173. * @param {Object[]} args
  174. * @returns {string}
  175. */
  176. runTripleDesEnc: function (input, args) {
  177. return Cipher._enc(CryptoJS.TripleDES, input, args);
  178. },
  179. /**
  180. * Triple DES Decrypt operation.
  181. *
  182. * @param {string} input
  183. * @param {Object[]} args
  184. * @returns {string}
  185. */
  186. runTripleDesDec: function (input, args) {
  187. return Cipher._dec(CryptoJS.TripleDES, input, args);
  188. },
  189. /**
  190. * Rabbit Encrypt operation.
  191. *
  192. * @param {string} input
  193. * @param {Object[]} args
  194. * @returns {string}
  195. */
  196. runRabbitEnc: function (input, args) {
  197. return Cipher._enc(CryptoJS.Rabbit, input, args);
  198. },
  199. /**
  200. * Rabbit Decrypt operation.
  201. *
  202. * @param {string} input
  203. * @param {Object[]} args
  204. * @returns {string}
  205. */
  206. runRabbitDec: function (input, args) {
  207. return Cipher._dec(CryptoJS.Rabbit, input, args);
  208. },
  209. /**
  210. * @constant
  211. * @default
  212. */
  213. BLOWFISH_MODES: ["ECB", "CBC", "PCBC", "CFB", "OFB", "CTR"],
  214. /**
  215. * @constant
  216. * @default
  217. */
  218. BLOWFISH_OUTPUT_TYPES: ["Base64", "Hex", "String", "Raw"],
  219. /**
  220. * Blowfish Encrypt operation.
  221. *
  222. * @param {string} input
  223. * @param {Object[]} args
  224. * @returns {string}
  225. */
  226. runBlowfishEnc: function (input, args) {
  227. let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
  228. mode = args[1],
  229. outputFormat = args[2];
  230. if (key.length === 0) return "Enter a key";
  231. let encHex = Blowfish.encrypt(input, key, {
  232. outputType: 1,
  233. cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
  234. }),
  235. enc = CryptoJS.enc.Hex.parse(encHex);
  236. return enc.toString(Utils.format[outputFormat]);
  237. },
  238. /**
  239. * Blowfish Decrypt operation.
  240. *
  241. * @param {string} input
  242. * @param {Object[]} args
  243. * @returns {string}
  244. */
  245. runBlowfishDec: function (input, args) {
  246. let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
  247. mode = args[1],
  248. inputFormat = args[2];
  249. if (key.length === 0) return "Enter a key";
  250. input = Utils.format[inputFormat].parse(input);
  251. return Blowfish.decrypt(input.toString(CryptoJS.enc.Base64), key, {
  252. outputType: 0, // This actually means inputType. The library is weird.
  253. cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
  254. });
  255. },
  256. /**
  257. * @constant
  258. * @default
  259. */
  260. KDF_KEY_SIZE: 256,
  261. /**
  262. * @constant
  263. * @default
  264. */
  265. KDF_ITERATIONS: 1,
  266. /**
  267. * @constant
  268. * @default
  269. */
  270. HASHERS: ["MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "RIPEMD160"],
  271. /**
  272. * Derive PBKDF2 key operation.
  273. *
  274. * @param {string} input
  275. * @param {Object[]} args
  276. * @returns {string}
  277. */
  278. runPbkdf2: function (input, args) {
  279. let keySize = args[0] / 32,
  280. iterations = args[1],
  281. hasher = args[2],
  282. salt = CryptoJS.enc.Hex.parse(args[3] || ""),
  283. inputFormat = args[4],
  284. outputFormat = args[5],
  285. passphrase = Utils.format[inputFormat].parse(input),
  286. key = CryptoJS.PBKDF2(passphrase, salt, {
  287. keySize: keySize,
  288. hasher: CryptoJS.algo[hasher],
  289. iterations: iterations,
  290. });
  291. return key.toString(Utils.format[outputFormat]);
  292. },
  293. /**
  294. * Derive EVP key operation.
  295. *
  296. * @param {string} input
  297. * @param {Object[]} args
  298. * @returns {string}
  299. */
  300. runEvpkdf: function (input, args) {
  301. let keySize = args[0] / 32,
  302. iterations = args[1],
  303. hasher = args[2],
  304. salt = CryptoJS.enc.Hex.parse(args[3] || ""),
  305. inputFormat = args[4],
  306. outputFormat = args[5],
  307. passphrase = Utils.format[inputFormat].parse(input),
  308. key = CryptoJS.EvpKDF(passphrase, salt, {
  309. keySize: keySize,
  310. hasher: CryptoJS.algo[hasher],
  311. iterations: iterations,
  312. });
  313. return key.toString(Utils.format[outputFormat]);
  314. },
  315. /**
  316. * RC4 operation.
  317. *
  318. * @param {string} input
  319. * @param {Object[]} args
  320. * @returns {string}
  321. */
  322. runRc4: function (input, args) {
  323. let message = Utils.format[args[1]].parse(input),
  324. passphrase = Utils.format[args[0].option].parse(args[0].string),
  325. encrypted = CryptoJS.RC4.encrypt(message, passphrase);
  326. return encrypted.ciphertext.toString(Utils.format[args[2]]);
  327. },
  328. /**
  329. * @constant
  330. * @default
  331. */
  332. RC4DROP_BYTES: 768,
  333. /**
  334. * RC4 Drop operation.
  335. *
  336. * @param {string} input
  337. * @param {Object[]} args
  338. * @returns {string}
  339. */
  340. runRc4drop: function (input, args) {
  341. let message = Utils.format[args[1]].parse(input),
  342. passphrase = Utils.format[args[0].option].parse(args[0].string),
  343. drop = args[3],
  344. encrypted = CryptoJS.RC4Drop.encrypt(message, passphrase, { drop: drop });
  345. return encrypted.ciphertext.toString(Utils.format[args[2]]);
  346. },
  347. /**
  348. * Vigenère Encode operation.
  349. *
  350. * @author Matt C [matt@artemisbot.uk]
  351. * @param {string} input
  352. * @param {Object[]} args
  353. * @returns {string}
  354. */
  355. runVigenereEnc: function (input, args) {
  356. let alphabet = "abcdefghijklmnopqrstuvwxyz",
  357. key = args[0].toLowerCase(),
  358. output = "",
  359. fail = 0,
  360. keyIndex,
  361. msgIndex,
  362. chr;
  363. if (!key) return "No key entered";
  364. if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
  365. for (let i = 0; i < input.length; i++) {
  366. if (alphabet.indexOf(input[i]) >= 0) {
  367. // Get the corresponding character of key for the current letter, accounting
  368. // for chars not in alphabet
  369. chr = key[(i - fail) % key.length];
  370. // Get the location in the vigenere square of the key char
  371. keyIndex = alphabet.indexOf(chr);
  372. // Get the location in the vigenere square of the message char
  373. msgIndex = alphabet.indexOf(input[i]);
  374. // Get the encoded letter by finding the sum of indexes modulo 26 and finding
  375. // the letter corresponding to that
  376. output += alphabet[(keyIndex + msgIndex) % 26];
  377. } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
  378. chr = key[(i - fail) % key.length].toLowerCase();
  379. keyIndex = alphabet.indexOf(chr);
  380. msgIndex = alphabet.indexOf(input[i].toLowerCase());
  381. output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
  382. } else {
  383. output += input[i];
  384. fail++;
  385. }
  386. }
  387. return output;
  388. },
  389. /**
  390. * Vigenère Decode operation.
  391. *
  392. * @author Matt C [matt@artemisbot.uk]
  393. * @param {string} input
  394. * @param {Object[]} args
  395. * @returns {string}
  396. */
  397. runVigenereDec: function (input, args) {
  398. let alphabet = "abcdefghijklmnopqrstuvwxyz",
  399. key = args[0].toLowerCase(),
  400. output = "",
  401. fail = 0,
  402. keyIndex,
  403. msgIndex,
  404. chr;
  405. if (!key) return "No key entered";
  406. if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
  407. for (let i = 0; i < input.length; i++) {
  408. if (alphabet.indexOf(input[i]) >= 0) {
  409. chr = key[(i - fail) % key.length];
  410. keyIndex = alphabet.indexOf(chr);
  411. msgIndex = alphabet.indexOf(input[i]);
  412. // Subtract indexes from each other, add 26 just in case the value is negative,
  413. // modulo to remove if neccessary
  414. output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
  415. } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
  416. chr = key[(i - fail) % key.length].toLowerCase();
  417. keyIndex = alphabet.indexOf(chr);
  418. msgIndex = alphabet.indexOf(input[i].toLowerCase());
  419. output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
  420. } else {
  421. output += input[i];
  422. fail++;
  423. }
  424. }
  425. return output;
  426. },
  427. /**
  428. * @constant
  429. * @default
  430. */
  431. AFFINE_A: 1,
  432. /**
  433. * @constant
  434. * @default
  435. */
  436. AFFINE_B: 0,
  437. /**
  438. * Affine Cipher Encode operation.
  439. *
  440. * @author Matt C [matt@artemisbot.uk]
  441. * @param {string} input
  442. * @param {Object[]} args
  443. * @returns {string}
  444. */
  445. runAffineEnc: function (input, args) {
  446. let alphabet = "abcdefghijklmnopqrstuvwxyz",
  447. a = args[0],
  448. b = args[1],
  449. output = "";
  450. if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
  451. return "The values of a and b can only be integers.";
  452. }
  453. for (let i = 0; i < input.length; i++) {
  454. if (alphabet.indexOf(input[i]) >= 0) {
  455. // Uses the affine function ax+b % m = y (where m is length of the alphabet)
  456. output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
  457. } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
  458. // Same as above, accounting for uppercase
  459. output += alphabet[((a * alphabet.indexOf(input[i].toLowerCase())) + b) % 26].toUpperCase();
  460. } else {
  461. // Non-alphabetic characters
  462. output += input[i];
  463. }
  464. }
  465. return output;
  466. },
  467. /**
  468. * Affine Cipher Decode operation.
  469. *
  470. * @author Matt C [matt@artemisbot.uk]
  471. * @param {string} input
  472. * @param {Object[]} args
  473. * @returns {string}
  474. */
  475. runAffineDec: function (input, args) {
  476. let alphabet = "abcdefghijklmnopqrstuvwxyz",
  477. a = args[0],
  478. b = args[1],
  479. output = "",
  480. aModInv;
  481. if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
  482. return "The values of a and b can only be integers.";
  483. }
  484. if (Utils.gcd(a, 26) !== 1) {
  485. return "The value of a must be coprime to 26.";
  486. }
  487. // Calculates modular inverse of a
  488. aModInv = Utils.modInv(a, 26);
  489. for (let i = 0; i < input.length; i++) {
  490. if (alphabet.indexOf(input[i]) >= 0) {
  491. // Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
  492. output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
  493. } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
  494. // Same as above, accounting for uppercase
  495. output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
  496. } else {
  497. // Non-alphabetic characters
  498. output += input[i];
  499. }
  500. }
  501. return output;
  502. },
  503. /**
  504. * Atbash Cipher Encode operation.
  505. *
  506. * @author Matt C [matt@artemisbot.uk]
  507. * @param {string} input
  508. * @param {Object[]} args
  509. * @returns {string}
  510. */
  511. runAtbash: function (input, args) {
  512. return Cipher.runAffineEnc(input, [25, 25]);
  513. },
  514. /**
  515. * Generates a polybius square for the given keyword
  516. *
  517. * @private
  518. * @author Matt C [matt@artemisbot.uk]
  519. * @param {string} keyword - Must be upper case
  520. * @returns {string}
  521. */
  522. _genPolybiusSquare: function (keyword) {
  523. const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
  524. const polArray = `${keyword}${alpha}`.split("").unique();
  525. let polybius = [];
  526. for (let i = 0; i < 5; i++) {
  527. polybius[i] = polArray.slice(i*5, i*5 + 5);
  528. }
  529. return polybius;
  530. },
  531. /**
  532. * Bifid Cipher Encode operation
  533. *
  534. * @author Matt C [matt@artemisbot.uk]
  535. * @param {string} input
  536. * @param {Object[]} args
  537. * @returns {string}
  538. */
  539. runBifidEnc: function (input, args) {
  540. const keywordStr = args[0].toUpperCase().replace("J", "I"),
  541. keyword = keywordStr.split("").unique(),
  542. alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
  543. let output = "",
  544. xCo = [],
  545. yCo = [],
  546. structure = [],
  547. count = 0;
  548. if (keyword.length > 25)
  549. return "The alphabet keyword must be less than 25 characters.";
  550. if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
  551. return "The key must consist only of letters";
  552. const polybius = Cipher._genPolybiusSquare(keywordStr);
  553. input.replace("J", "I").split("").forEach(letter => {
  554. let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
  555. polInd;
  556. if (alpInd) {
  557. for (let i = 0; i < 5; i++) {
  558. polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
  559. if (polInd >= 0) {
  560. xCo.push(polInd);
  561. yCo.push(i);
  562. }
  563. }
  564. if (alpha.split("").indexOf(letter) >= 0) {
  565. structure.push(true);
  566. } else if (alpInd) {
  567. structure.push(false);
  568. }
  569. } else {
  570. structure.push(letter);
  571. }
  572. });
  573. const trans = `${yCo.join("")}${xCo.join("")}`;
  574. structure.forEach(pos => {
  575. if (typeof pos === "boolean") {
  576. let coords = trans.substr(2*count, 2).split("");
  577. output += pos ?
  578. polybius[coords[0]][coords[1]] :
  579. polybius[coords[0]][coords[1]].toLocaleLowerCase();
  580. count++;
  581. } else {
  582. output += pos;
  583. }
  584. });
  585. return output;
  586. },
  587. /**
  588. * Bifid Cipher Decode operation
  589. *
  590. * @author Matt C [matt@artemisbot.uk]
  591. * @param {string} input
  592. * @param {Object[]} args
  593. * @returns {string}
  594. */
  595. runBifidDec: function (input, args) {
  596. const keywordStr = args[0].toUpperCase().replace("J", "I"),
  597. keyword = keywordStr.split("").unique(),
  598. alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
  599. let output = "",
  600. structure = [],
  601. count = 0,
  602. trans = "";
  603. if (keyword.length > 25)
  604. return "The alphabet keyword must be less than 25 characters.";
  605. if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
  606. return "The key must consist only of letters";
  607. const polybius = Cipher._genPolybiusSquare(keywordStr);
  608. input.replace("J", "I").split("").forEach((letter) => {
  609. let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
  610. polInd;
  611. if (alpInd) {
  612. for (let i = 0; i < 5; i++) {
  613. polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
  614. if (polInd >= 0) {
  615. trans += `${i}${polInd}`;
  616. }
  617. }
  618. if (alpha.split("").indexOf(letter) >= 0) {
  619. structure.push(true);
  620. } else if (alpInd) {
  621. structure.push(false);
  622. }
  623. } else {
  624. structure.push(letter);
  625. }
  626. });
  627. structure.forEach(pos => {
  628. if (typeof pos === "boolean") {
  629. let coords = [trans[count], trans[count+trans.length/2]];
  630. output += pos ?
  631. polybius[coords[0]][coords[1]] :
  632. polybius[coords[0]][coords[1]].toLocaleLowerCase();
  633. count++;
  634. } else {
  635. output += pos;
  636. }
  637. });
  638. return output;
  639. },
  640. /**
  641. * @constant
  642. * @default
  643. */
  644. SUBS_PLAINTEXT: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  645. /**
  646. * @constant
  647. * @default
  648. */
  649. SUBS_CIPHERTEXT: "XYZABCDEFGHIJKLMNOPQRSTUVW",
  650. /**
  651. * Substitute operation.
  652. *
  653. * @param {string} input
  654. * @param {Object[]} args
  655. * @returns {string}
  656. */
  657. runSubstitute: function (input, args) {
  658. let plaintext = Utils.expandAlphRange(args[0]).join(""),
  659. ciphertext = Utils.expandAlphRange(args[1]).join(""),
  660. output = "",
  661. index = -1;
  662. if (plaintext.length !== ciphertext.length) {
  663. output = "Warning: Plaintext and Ciphertext lengths differ\n\n";
  664. }
  665. for (let i = 0; i < input.length; i++) {
  666. index = plaintext.indexOf(input[i]);
  667. output += index > -1 && index < ciphertext.length ? ciphertext[index] : input[i];
  668. }
  669. return output;
  670. },
  671. };
  672. export default Cipher;
  673. /**
  674. * Overwriting the CryptoJS OpenSSL key derivation function so that it is possible to not pass a
  675. * salt in.
  676. * @param {string} password - The password to derive from.
  677. * @param {number} keySize - The size in words of the key to generate.
  678. * @param {number} ivSize - The size in words of the IV to generate.
  679. * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be
  680. * generated randomly. If set to false, no salt will be added.
  681. *
  682. * @returns {CipherParams} A cipher params object with the key, IV, and salt.
  683. *
  684. * @static
  685. *
  686. * @example
  687. * // Randomly generates a salt
  688. * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
  689. * // Uses the salt 'saltsalt'
  690. * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
  691. * // Does not use a salt
  692. * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, false);
  693. */
  694. CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
  695. // Generate random salt if no salt specified and not set to false
  696. // This line changed from `if (!salt) {` to the following
  697. if (salt === undefined || salt === null) {
  698. salt = CryptoJS.lib.WordArray.random(64/8);
  699. }
  700. // Derive key and IV
  701. const key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
  702. // Separate key and IV
  703. const iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
  704. key.sigBytes = keySize * 4;
  705. // Return params
  706. return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt });
  707. };