Home Reference Source Test

src/hasher/sha1.mjs

  1. 'use strict';
  2.  
  3. import Hasher32be from "./hasher32be";
  4. import {rotateLeft} from "../tools/tools";
  5.  
  6. // Transform constants
  7. /** @type {number[]} */
  8. const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
  9.  
  10. /**
  11. * Calculates [SHA1](https://tools.ietf.org/html/rfc3174) hash
  12. *
  13. * @example <caption>Calculates SHA1 hash from string "message" - ES6 style</caption>
  14. * import Sha1 from "crypto-api/src/hasher/sha1";
  15. * import {toHex} from "crypto-api/src/encoder/hex";
  16. *
  17. * let hasher = new Sha1();
  18. * hasher.update('message');
  19. * console.log(toHex(hasher.finalize()));
  20. *
  21. * @example <caption>Calculates SHA1 hash from UTF string "message" - ES6 style</caption>
  22. * import Sha1 from "crypto-api/src/hasher/sha1";
  23. * import {toHex} from "crypto-api/src/encoder/hex";
  24. * import {fromUtf} from "crypto-api/src/encoder/utf";
  25. *
  26. * let hasher = new Sha1();
  27. * hasher.update(fromUtf('message'));
  28. * console.log(toHex(hasher.finalize()));
  29. *
  30. * @example <caption>Calculates SHA1 hash from string "message" - ES5 style</caption>
  31. * <script src="https://nf404.github.io/crypto-api/crypto-api.min.js"></script>
  32. * <script>
  33. * var hasher = CryptoApi.getHasher('sha1');
  34. * hasher.update('message');
  35. * console.log(CryptoApi.encoder.toHex(hasher.finalize()));
  36. * </script>
  37. *
  38. * @example <caption>Calculates SHA1 hash from UTF string "message" - ES5 style</caption>
  39. * <script src="https://nf404.github.io/crypto-api/crypto-api.min.js"></script>
  40. * <script>
  41. * console.log(CryptoApi.hash('sha1', 'message'));
  42. * </script>
  43. */
  44. class Sha1 extends Hasher32be {
  45. /**
  46. * @param {Object} [options]
  47. * @param {number} [options.rounds=80] - Number of rounds (Must be greater than 16)
  48. */
  49. constructor(options) {
  50. super(options);
  51. this.options.rounds = this.options.rounds || 80;
  52.  
  53. /**
  54. * Working variable (only for speed optimization)
  55. * @private
  56. * @ignore
  57. * @type {number[]}
  58. */
  59. this.W = new Array(80);
  60. }
  61.  
  62. /**
  63. * Reset hasher to initial state
  64. */
  65. reset() {
  66. super.reset();
  67. this.state.hash = [
  68. 0x67452301 | 0,
  69. 0xefcdab89 | 0,
  70. 0x98badcfe | 0,
  71. 0x10325476 | 0,
  72. 0xc3d2e1f0 | 0
  73. ];
  74. }
  75.  
  76. /**
  77. * Process ready blocks
  78. *
  79. * @protected
  80. * @ignore
  81. * @param {number[]} block - Block
  82. */
  83. processBlock(block) {
  84. // Working variables
  85. let a = this.state.hash[0] | 0;
  86. let b = this.state.hash[1] | 0;
  87. let c = this.state.hash[2] | 0;
  88. let d = this.state.hash[3] | 0;
  89. let e = this.state.hash[4] | 0;
  90.  
  91. // Calculate hash
  92. for (let i = 0; i < this.options.rounds; i++) {
  93. if (i < 16) {
  94. this.W[i] = block[i] | 0;
  95. } else {
  96. this.W[i] = rotateLeft(this.W[i - 3] ^ this.W[i - 8] ^ this.W[i - 14] ^ this.W[i - 16], 1) | 0;
  97. }
  98.  
  99. let t = (rotateLeft(a, 5) + e + this.W[i] + K[(i / 20) >> 0]) | 0;
  100. if (i < 20) {
  101. t = (t + ((b & c) | (~b & d))) | 0;
  102. } else if (i < 40) {
  103. t = (t + (b ^ c ^ d)) | 0;
  104. } else if (i < 60) {
  105. t = (t + ((b & c) | (b & d) | (c & d))) | 0;
  106. } else {
  107. t = (t + (b ^ c ^ d)) | 0;
  108. }
  109. e = d;
  110. d = c;
  111. c = rotateLeft(b, 30) | 0;
  112. b = a;
  113. a = t;
  114. }
  115.  
  116. this.state.hash[0] = (this.state.hash[0] + a) | 0;
  117. this.state.hash[1] = (this.state.hash[1] + b) | 0;
  118. this.state.hash[2] = (this.state.hash[2] + c) | 0;
  119. this.state.hash[3] = (this.state.hash[3] + d) | 0;
  120. this.state.hash[4] = (this.state.hash[4] + e) | 0;
  121. }
  122.  
  123. /**
  124. * Finalize hash and return result
  125. *
  126. * @returns {string}
  127. */
  128. finalize() {
  129. this.addPaddingISO7816(
  130. this.state.message.length < 56 ?
  131. 56 - this.state.message.length | 0 :
  132. 120 - this.state.message.length | 0);
  133. this.addLengthBits();
  134. this.process();
  135. return this.getStateHash();
  136. }
  137. }
  138.  
  139. export default Sha1;