Hash.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. import Utils from "../Utils.js";
  2. import CryptoApi from "babel-loader!crypto-api";
  3. import MD6 from "node-md6";
  4. import * as SHA3 from "js-sha3";
  5. import Checksum from "./Checksum.js";
  6. import ctph from "ctph.js";
  7. import ssdeep from "ssdeep.js";
  8. import bcrypt from "bcryptjs";
  9. import scrypt from "scryptsy";
  10. /**
  11. * Hashing operations.
  12. *
  13. * @author n1474335 [n1474335@gmail.com]
  14. * @copyright Crown Copyright 2016
  15. * @license Apache-2.0
  16. *
  17. * @namespace
  18. */
  19. const Hash = {
  20. /**
  21. * Generic hash function.
  22. *
  23. * @param {string} name
  24. * @param {ArrayBuffer} input
  25. * @param {Object} [options={}]
  26. * @returns {string}
  27. */
  28. runHash: function(name, input, options={}) {
  29. const msg = Utils.arrayBufferToStr(input, false),
  30. hasher = CryptoApi.getHasher(name, options);
  31. hasher.update(msg);
  32. return CryptoApi.encoder.toHex(hasher.finalize());
  33. },
  34. /**
  35. * MD2 operation.
  36. *
  37. * @param {ArrayBuffer} input
  38. * @param {Object[]} args
  39. * @returns {string}
  40. */
  41. runMD2: function (input, args) {
  42. return Hash.runHash("md2", input);
  43. },
  44. /**
  45. * MD4 operation.
  46. *
  47. * @param {ArrayBuffer} input
  48. * @param {Object[]} args
  49. * @returns {string}
  50. */
  51. runMD4: function (input, args) {
  52. return Hash.runHash("md4", input);
  53. },
  54. /**
  55. * MD5 operation.
  56. *
  57. * @param {ArrayBuffer} input
  58. * @param {Object[]} args
  59. * @returns {string}
  60. */
  61. runMD5: function (input, args) {
  62. return Hash.runHash("md5", input);
  63. },
  64. /**
  65. * @constant
  66. * @default
  67. */
  68. MD6_SIZE: 256,
  69. /**
  70. * @constant
  71. * @default
  72. */
  73. MD6_LEVELS: 64,
  74. /**
  75. * MD6 operation.
  76. *
  77. * @param {string} input
  78. * @param {Object[]} args
  79. * @returns {string}
  80. */
  81. runMD6: function (input, args) {
  82. const size = args[0],
  83. levels = args[1],
  84. key = args[2];
  85. if (size < 0 || size > 512)
  86. return "Size must be between 0 and 512";
  87. if (levels < 0)
  88. return "Levels must be greater than 0";
  89. return MD6.getHashOfText(input, size, key, levels);
  90. },
  91. /**
  92. * SHA0 operation.
  93. *
  94. * @param {ArrayBuffer} input
  95. * @param {Object[]} args
  96. * @returns {string}
  97. */
  98. runSHA0: function (input, args) {
  99. return Hash.runHash("sha0", input);
  100. },
  101. /**
  102. * SHA1 operation.
  103. *
  104. * @param {ArrayBuffer} input
  105. * @param {Object[]} args
  106. * @returns {string}
  107. */
  108. runSHA1: function (input, args) {
  109. return Hash.runHash("sha1", input);
  110. },
  111. /**
  112. * @constant
  113. * @default
  114. */
  115. SHA2_SIZE: ["512", "256", "384", "224", "512/256", "512/224"],
  116. /**
  117. * SHA2 operation.
  118. *
  119. * @param {ArrayBuffer} input
  120. * @param {Object[]} args
  121. * @returns {string}
  122. */
  123. runSHA2: function (input, args) {
  124. const size = args[0];
  125. return Hash.runHash("sha" + size, input);
  126. },
  127. /**
  128. * @constant
  129. * @default
  130. */
  131. SHA3_SIZE: ["512", "384", "256", "224"],
  132. /**
  133. * SHA3 operation.
  134. *
  135. * @param {ArrayBuffer} input
  136. * @param {Object[]} args
  137. * @returns {string}
  138. */
  139. runSHA3: function (input, args) {
  140. const size = parseInt(args[0], 10);
  141. let algo;
  142. switch (size) {
  143. case 224:
  144. algo = SHA3.sha3_224;
  145. break;
  146. case 384:
  147. algo = SHA3.sha3_384;
  148. break;
  149. case 256:
  150. algo = SHA3.sha3_256;
  151. break;
  152. case 512:
  153. algo = SHA3.sha3_512;
  154. break;
  155. default:
  156. return "Invalid size";
  157. }
  158. return algo(input);
  159. },
  160. /**
  161. * @constant
  162. * @default
  163. */
  164. KECCAK_SIZE: ["512", "384", "256", "224"],
  165. /**
  166. * Keccak operation.
  167. *
  168. * @param {ArrayBuffer} input
  169. * @param {Object[]} args
  170. * @returns {string}
  171. */
  172. runKeccak: function (input, args) {
  173. const size = parseInt(args[0], 10);
  174. let algo;
  175. switch (size) {
  176. case 224:
  177. algo = SHA3.keccak224;
  178. break;
  179. case 384:
  180. algo = SHA3.keccak384;
  181. break;
  182. case 256:
  183. algo = SHA3.keccak256;
  184. break;
  185. case 512:
  186. algo = SHA3.keccak512;
  187. break;
  188. default:
  189. return "Invalid size";
  190. }
  191. return algo(input);
  192. },
  193. /**
  194. * @constant
  195. * @default
  196. */
  197. SHAKE_CAPACITY: ["256", "128"],
  198. /**
  199. * @constant
  200. * @default
  201. */
  202. SHAKE_SIZE: 512,
  203. /**
  204. * Shake operation.
  205. *
  206. * @param {ArrayBuffer} input
  207. * @param {Object[]} args
  208. * @returns {string}
  209. */
  210. runShake: function (input, args) {
  211. const capacity = parseInt(args[0], 10),
  212. size = args[1];
  213. let algo;
  214. if (size < 0)
  215. return "Size must be greater than 0";
  216. switch (capacity) {
  217. case 128:
  218. algo = SHA3.shake128;
  219. break;
  220. case 256:
  221. algo = SHA3.shake256;
  222. break;
  223. default:
  224. return "Invalid size";
  225. }
  226. return algo(input, size);
  227. },
  228. /**
  229. * @constant
  230. * @default
  231. */
  232. RIPEMD_SIZE: ["320", "256", "160", "128"],
  233. /**
  234. * RIPEMD operation.
  235. *
  236. * @param {ArrayBuffer} input
  237. * @param {Object[]} args
  238. * @returns {string}
  239. */
  240. runRIPEMD: function (input, args) {
  241. const size = args[0];
  242. return Hash.runHash("ripemd" + size, input);
  243. },
  244. /**
  245. * HAS-160 operation.
  246. *
  247. * @param {ArrayBuffer} input
  248. * @param {Object[]} args
  249. * @returns {string}
  250. */
  251. runHAS: function (input, args) {
  252. return Hash.runHash("has160", input);
  253. },
  254. /**
  255. * @constant
  256. * @default
  257. */
  258. WHIRLPOOL_VARIANT: ["Whirlpool", "Whirlpool-T", "Whirlpool-0"],
  259. /**
  260. * Whirlpool operation.
  261. *
  262. * @param {ArrayBuffer} input
  263. * @param {Object[]} args
  264. * @returns {string}
  265. */
  266. runWhirlpool: function (input, args) {
  267. const variant = args[0].toLowerCase();
  268. return Hash.runHash(variant, input);
  269. },
  270. /**
  271. * @constant
  272. * @default
  273. */
  274. SNEFRU_ROUNDS: ["8", "4", "2"],
  275. /**
  276. * @constant
  277. * @default
  278. */
  279. SNEFRU_SIZE: ["256", "128"],
  280. /**
  281. * Snefru operation.
  282. *
  283. * @param {ArrayBuffer} input
  284. * @param {Object[]} args
  285. * @returns {string}
  286. */
  287. runSnefru: function (input, args) {
  288. return Hash.runHash("snefru", input, {
  289. rounds: args[0],
  290. length: args[1]
  291. });
  292. },
  293. /**
  294. * CTPH operation.
  295. *
  296. * @param {string} input
  297. * @param {Object[]} args
  298. * @returns {string}
  299. */
  300. runCTPH: function (input, args) {
  301. return ctph.digest(input);
  302. },
  303. /**
  304. * SSDEEP operation.
  305. *
  306. * @param {string} input
  307. * @param {Object[]} args
  308. * @returns {string}
  309. */
  310. runSSDEEP: function (input, args) {
  311. return ssdeep.digest(input);
  312. },
  313. /**
  314. * @constant
  315. * @default
  316. */
  317. DELIM_OPTIONS: ["Line feed", "CRLF", "Space", "Comma"],
  318. /**
  319. * Compare CTPH hashes operation.
  320. *
  321. * @param {string} input
  322. * @param {Object[]} args
  323. * @returns {Number}
  324. */
  325. runCompareCTPH: function (input, args) {
  326. const samples = input.split(Utils.charRep[args[0]]);
  327. if (samples.length !== 2) throw "Incorrect number of samples.";
  328. return ctph.similarity(samples[0], samples[1]);
  329. },
  330. /**
  331. * Compare SSDEEP hashes operation.
  332. *
  333. * @param {string} input
  334. * @param {Object[]} args
  335. * @returns {Number}
  336. */
  337. runCompareSSDEEP: function (input, args) {
  338. const samples = input.split(Utils.charRep[args[0]]);
  339. if (samples.length !== 2) throw "Incorrect number of samples.";
  340. return ssdeep.similarity(samples[0], samples[1]);
  341. },
  342. /**
  343. * @constant
  344. * @default
  345. */
  346. HMAC_FUNCTIONS: [
  347. "MD2",
  348. "MD4",
  349. "MD5",
  350. "SHA0",
  351. "SHA1",
  352. "SHA224",
  353. "SHA256",
  354. "SHA384",
  355. "SHA512",
  356. "SHA512/224",
  357. "SHA512/256",
  358. "RIPEMD128",
  359. "RIPEMD160",
  360. "RIPEMD256",
  361. "RIPEMD320",
  362. "HAS160",
  363. "Whirlpool",
  364. "Whirlpool-0",
  365. "Whirlpool-T",
  366. "Snefru"
  367. ],
  368. /**
  369. * HMAC operation.
  370. *
  371. * @param {ArrayBuffer} input
  372. * @param {Object[]} args
  373. * @returns {string}
  374. */
  375. runHMAC: function (input, args) {
  376. const key = args[0],
  377. hashFunc = args[1].toLowerCase(),
  378. msg = Utils.arrayBufferToStr(input, false),
  379. hasher = CryptoApi.getHasher(hashFunc);
  380. // Horrible shim to fix constructor bug. Reported in nf404/crypto-api#8
  381. hasher.reset = () => {
  382. hasher.state = {};
  383. const tmp = new hasher.constructor();
  384. hasher.state = tmp.state;
  385. };
  386. const mac = CryptoApi.getHmac(CryptoApi.encoder.fromUtf(key), hasher);
  387. mac.update(msg);
  388. return CryptoApi.encoder.toHex(mac.finalize());
  389. },
  390. /**
  391. * @constant
  392. * @default
  393. */
  394. BCRYPT_ROUNDS: 10,
  395. /**
  396. * Bcrypt operation.
  397. *
  398. * @param {string} input
  399. * @param {Object[]} args
  400. * @returns {string}
  401. */
  402. runBcrypt: async function (input, args) {
  403. const rounds = args[0];
  404. const salt = await bcrypt.genSalt(rounds);
  405. return await bcrypt.hash(input, salt, null, p => {
  406. // Progress callback
  407. if (ENVIRONMENT_IS_WORKER())
  408. self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
  409. });
  410. },
  411. /**
  412. * Bcrypt compare operation.
  413. *
  414. * @param {string} input
  415. * @param {Object[]} args
  416. * @returns {string}
  417. */
  418. runBcryptCompare: async function (input, args) {
  419. const hash = args[0];
  420. const match = await bcrypt.compare(input, hash, null, p => {
  421. // Progress callback
  422. if (ENVIRONMENT_IS_WORKER())
  423. self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
  424. });
  425. return match ? "Match: " + input : "No match";
  426. },
  427. /**
  428. * Bcrypt parse operation.
  429. *
  430. * @param {string} input
  431. * @param {Object[]} args
  432. * @returns {string}
  433. */
  434. runBcryptParse: async function (input, args) {
  435. try {
  436. return `Rounds: ${bcrypt.getRounds(input)}
  437. Salt: ${bcrypt.getSalt(input)}
  438. Password hash: ${input.split(bcrypt.getSalt(input))[1]}
  439. Full hash: ${input}`;
  440. } catch (err) {
  441. return "Error: " + err.toString();
  442. }
  443. },
  444. /**
  445. * @constant
  446. * @default
  447. */
  448. KEY_FORMAT: ["Hex", "Base64", "UTF8", "Latin1"],
  449. /**
  450. * @constant
  451. * @default
  452. */
  453. SCRYPT_ITERATIONS: 16384,
  454. /**
  455. * @constant
  456. * @default
  457. */
  458. SCRYPT_MEM_FACTOR: 8,
  459. /**
  460. * @constant
  461. * @default
  462. */
  463. SCRYPT_PARALLEL_FACTOR: 1,
  464. /**
  465. * @constant
  466. * @default
  467. */
  468. SCRYPT_KEY_LENGTH: 64,
  469. /**
  470. * Scrypt operation.
  471. *
  472. * @param {string} input
  473. * @param {Object[]} args
  474. * @returns {string}
  475. */
  476. runScrypt: function (input, args) {
  477. const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
  478. iterations = args[1],
  479. memFactor = args[2],
  480. parallelFactor = args[3],
  481. keyLength = args[4];
  482. try {
  483. const data = scrypt(
  484. input, salt, iterations, memFactor, parallelFactor, keyLength,
  485. p => {
  486. // Progress callback
  487. if (ENVIRONMENT_IS_WORKER())
  488. self.sendStatusMessage(`Progress: ${p.percent.toFixed(0)}%`);
  489. }
  490. );
  491. return data.toString("hex");
  492. } catch (err) {
  493. return "Error: " + err.toString();
  494. }
  495. },
  496. /**
  497. * Generate all hashes operation.
  498. *
  499. * @param {ArrayBuffer} input
  500. * @param {Object[]} args
  501. * @returns {string}
  502. */
  503. runAll: function (input, args) {
  504. const arrayBuffer = input,
  505. str = Utils.arrayBufferToStr(arrayBuffer, false),
  506. byteArray = new Uint8Array(arrayBuffer),
  507. output = "MD2: " + Hash.runMD2(arrayBuffer, []) +
  508. "\nMD4: " + Hash.runMD4(arrayBuffer, []) +
  509. "\nMD5: " + Hash.runMD5(arrayBuffer, []) +
  510. "\nMD6: " + Hash.runMD6(str, []) +
  511. "\nSHA0: " + Hash.runSHA0(arrayBuffer, []) +
  512. "\nSHA1: " + Hash.runSHA1(arrayBuffer, []) +
  513. "\nSHA2 224: " + Hash.runSHA2(arrayBuffer, ["224"]) +
  514. "\nSHA2 256: " + Hash.runSHA2(arrayBuffer, ["256"]) +
  515. "\nSHA2 384: " + Hash.runSHA2(arrayBuffer, ["384"]) +
  516. "\nSHA2 512: " + Hash.runSHA2(arrayBuffer, ["512"]) +
  517. "\nSHA3 224: " + Hash.runSHA3(arrayBuffer, ["224"]) +
  518. "\nSHA3 256: " + Hash.runSHA3(arrayBuffer, ["256"]) +
  519. "\nSHA3 384: " + Hash.runSHA3(arrayBuffer, ["384"]) +
  520. "\nSHA3 512: " + Hash.runSHA3(arrayBuffer, ["512"]) +
  521. "\nKeccak 224: " + Hash.runKeccak(arrayBuffer, ["224"]) +
  522. "\nKeccak 256: " + Hash.runKeccak(arrayBuffer, ["256"]) +
  523. "\nKeccak 384: " + Hash.runKeccak(arrayBuffer, ["384"]) +
  524. "\nKeccak 512: " + Hash.runKeccak(arrayBuffer, ["512"]) +
  525. "\nShake 128: " + Hash.runShake(arrayBuffer, ["128", 256]) +
  526. "\nShake 256: " + Hash.runShake(arrayBuffer, ["256", 512]) +
  527. "\nRIPEMD-128: " + Hash.runRIPEMD(arrayBuffer, ["128"]) +
  528. "\nRIPEMD-160: " + Hash.runRIPEMD(arrayBuffer, ["160"]) +
  529. "\nRIPEMD-256: " + Hash.runRIPEMD(arrayBuffer, ["256"]) +
  530. "\nRIPEMD-320: " + Hash.runRIPEMD(arrayBuffer, ["320"]) +
  531. "\nHAS-160: " + Hash.runHAS(arrayBuffer, []) +
  532. "\nWhirlpool-0: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool-0"]) +
  533. "\nWhirlpool-T: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool-T"]) +
  534. "\nWhirlpool: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool"]) +
  535. "\nSSDEEP: " + Hash.runSSDEEP(str) +
  536. "\nCTPH: " + Hash.runCTPH(str) +
  537. "\n\nChecksums:" +
  538. "\nFletcher-8: " + Checksum.runFletcher8(byteArray, []) +
  539. "\nFletcher-16: " + Checksum.runFletcher16(byteArray, []) +
  540. "\nFletcher-32: " + Checksum.runFletcher32(byteArray, []) +
  541. "\nFletcher-64: " + Checksum.runFletcher64(byteArray, []) +
  542. "\nAdler-32: " + Checksum.runAdler32(byteArray, []) +
  543. "\nCRC-16: " + Checksum.runCRC16(str, []) +
  544. "\nCRC-32: " + Checksum.runCRC32(str, []);
  545. return output;
  546. },
  547. /**
  548. * Analyse hash operation.
  549. *
  550. * @param {string} input
  551. * @param {Object[]} args
  552. * @returns {string}
  553. */
  554. runAnalyse: function(input, args) {
  555. input = input.replace(/\s/g, "");
  556. let output = "",
  557. byteLength = input.length / 2,
  558. bitLength = byteLength * 8,
  559. possibleHashFunctions = [];
  560. if (!/^[a-f0-9]+$/i.test(input)) {
  561. return "Invalid hash";
  562. }
  563. output += "Hash length: " + input.length + "\n" +
  564. "Byte length: " + byteLength + "\n" +
  565. "Bit length: " + bitLength + "\n\n" +
  566. "Based on the length, this hash could have been generated by one of the following hashing functions:\n";
  567. switch (bitLength) {
  568. case 4:
  569. possibleHashFunctions = [
  570. "Fletcher-4",
  571. "Luhn algorithm",
  572. "Verhoeff algorithm",
  573. ];
  574. break;
  575. case 8:
  576. possibleHashFunctions = [
  577. "Fletcher-8",
  578. ];
  579. break;
  580. case 16:
  581. possibleHashFunctions = [
  582. "BSD checksum",
  583. "CRC-16",
  584. "SYSV checksum",
  585. "Fletcher-16"
  586. ];
  587. break;
  588. case 32:
  589. possibleHashFunctions = [
  590. "CRC-32",
  591. "Fletcher-32",
  592. "Adler-32",
  593. ];
  594. break;
  595. case 64:
  596. possibleHashFunctions = [
  597. "CRC-64",
  598. "RIPEMD-64",
  599. "SipHash",
  600. ];
  601. break;
  602. case 128:
  603. possibleHashFunctions = [
  604. "MD5",
  605. "MD4",
  606. "MD2",
  607. "HAVAL-128",
  608. "RIPEMD-128",
  609. "Snefru",
  610. "Tiger-128",
  611. ];
  612. break;
  613. case 160:
  614. possibleHashFunctions = [
  615. "SHA-1",
  616. "SHA-0",
  617. "FSB-160",
  618. "HAS-160",
  619. "HAVAL-160",
  620. "RIPEMD-160",
  621. "Tiger-160",
  622. ];
  623. break;
  624. case 192:
  625. possibleHashFunctions = [
  626. "Tiger",
  627. "HAVAL-192",
  628. ];
  629. break;
  630. case 224:
  631. possibleHashFunctions = [
  632. "SHA-224",
  633. "SHA3-224",
  634. "ECOH-224",
  635. "FSB-224",
  636. "HAVAL-224",
  637. ];
  638. break;
  639. case 256:
  640. possibleHashFunctions = [
  641. "SHA-256",
  642. "SHA3-256",
  643. "BLAKE-256",
  644. "ECOH-256",
  645. "FSB-256",
  646. "GOST",
  647. "Grøstl-256",
  648. "HAVAL-256",
  649. "PANAMA",
  650. "RIPEMD-256",
  651. "Snefru",
  652. ];
  653. break;
  654. case 320:
  655. possibleHashFunctions = [
  656. "RIPEMD-320",
  657. ];
  658. break;
  659. case 384:
  660. possibleHashFunctions = [
  661. "SHA-384",
  662. "SHA3-384",
  663. "ECOH-384",
  664. "FSB-384",
  665. ];
  666. break;
  667. case 512:
  668. possibleHashFunctions = [
  669. "SHA-512",
  670. "SHA3-512",
  671. "BLAKE-512",
  672. "ECOH-512",
  673. "FSB-512",
  674. "Grøstl-512",
  675. "JH",
  676. "MD6",
  677. "Spectral Hash",
  678. "SWIFFT",
  679. "Whirlpool",
  680. ];
  681. break;
  682. case 1024:
  683. possibleHashFunctions = [
  684. "Fowler-Noll-Vo",
  685. ];
  686. break;
  687. default:
  688. possibleHashFunctions = [
  689. "Unknown"
  690. ];
  691. break;
  692. }
  693. return output + possibleHashFunctions.join("\n");
  694. },
  695. };
  696. export default Hash;