Hash.js 17 KB

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