1 | var Buffer = require('buffer/').Buffer;
|
2 | var hashUtils = require('./browserHashUtils');
|
3 |
|
4 | var BLOCK_SIZE = 64;
|
5 |
|
6 | var DIGEST_LENGTH = 20;
|
7 |
|
8 | var KEY = new Uint32Array([
|
9 | 0x5a827999,
|
10 | 0x6ed9eba1,
|
11 | 0x8f1bbcdc | 0,
|
12 | 0xca62c1d6 | 0
|
13 | ]);
|
14 |
|
15 | var INIT = [
|
16 | 0x6a09e667,
|
17 | 0xbb67ae85,
|
18 | 0x3c6ef372,
|
19 | 0xa54ff53a,
|
20 | 0x510e527f,
|
21 | 0x9b05688c,
|
22 | 0x1f83d9ab,
|
23 | 0x5be0cd19,
|
24 | ];
|
25 |
|
26 | var MAX_HASHABLE_LENGTH = Math.pow(2, 53) - 1;
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | function Sha1() {
|
32 | this.h0 = 0x67452301;
|
33 | this.h1 = 0xEFCDAB89;
|
34 | this.h2 = 0x98BADCFE;
|
35 | this.h3 = 0x10325476;
|
36 | this.h4 = 0xC3D2E1F0;
|
37 |
|
38 | this.block = new Uint32Array(80);
|
39 | this.offset = 0;
|
40 | this.shift = 24;
|
41 | this.totalLength = 0;
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | module.exports = exports = Sha1;
|
48 |
|
49 | Sha1.BLOCK_SIZE = BLOCK_SIZE;
|
50 |
|
51 | Sha1.prototype.update = function (data) {
|
52 | if (this.finished) {
|
53 | throw new Error('Attempted to update an already finished hash.');
|
54 | }
|
55 |
|
56 | if (hashUtils.isEmptyData(data)) {
|
57 | return this;
|
58 | }
|
59 |
|
60 | data = hashUtils.convertToBuffer(data);
|
61 |
|
62 | var length = data.length;
|
63 | this.totalLength += length * 8;
|
64 | for (var i = 0; i < length; i++) {
|
65 | this.write(data[i]);
|
66 | }
|
67 |
|
68 | return this;
|
69 | };
|
70 |
|
71 | Sha1.prototype.write = function write(byte) {
|
72 | this.block[this.offset] |= (byte & 0xff) << this.shift;
|
73 | if (this.shift) {
|
74 | this.shift -= 8;
|
75 | } else {
|
76 | this.offset++;
|
77 | this.shift = 24;
|
78 | }
|
79 |
|
80 | if (this.offset === 16) this.processBlock();
|
81 | };
|
82 |
|
83 | Sha1.prototype.digest = function (encoding) {
|
84 |
|
85 | this.write(0x80);
|
86 | if (this.offset > 14 || (this.offset === 14 && this.shift < 24)) {
|
87 | this.processBlock();
|
88 | }
|
89 | this.offset = 14;
|
90 | this.shift = 24;
|
91 |
|
92 |
|
93 | this.write(0x00);
|
94 | this.write(0x00);
|
95 | this.write(this.totalLength > 0xffffffffff ? this.totalLength / 0x10000000000 : 0x00);
|
96 | this.write(this.totalLength > 0xffffffff ? this.totalLength / 0x100000000 : 0x00);
|
97 | for (var s = 24; s >= 0; s -= 8) {
|
98 | this.write(this.totalLength >> s);
|
99 | }
|
100 |
|
101 |
|
102 | var out = new Buffer(DIGEST_LENGTH);
|
103 | var outView = new DataView(out.buffer);
|
104 | outView.setUint32(0, this.h0, false);
|
105 | outView.setUint32(4, this.h1, false);
|
106 | outView.setUint32(8, this.h2, false);
|
107 | outView.setUint32(12, this.h3, false);
|
108 | outView.setUint32(16, this.h4, false);
|
109 |
|
110 | return encoding ? out.toString(encoding) : out;
|
111 | };
|
112 |
|
113 | Sha1.prototype.processBlock = function processBlock() {
|
114 |
|
115 | for (var i = 16; i < 80; i++) {
|
116 | var w = this.block[i - 3] ^ this.block[i - 8] ^ this.block[i - 14] ^ this.block[i - 16];
|
117 | this.block[i] = (w << 1) | (w >>> 31);
|
118 | }
|
119 |
|
120 |
|
121 | var a = this.h0;
|
122 | var b = this.h1;
|
123 | var c = this.h2;
|
124 | var d = this.h3;
|
125 | var e = this.h4;
|
126 | var f, k;
|
127 |
|
128 |
|
129 | for (i = 0; i < 80; i++) {
|
130 | if (i < 20) {
|
131 | f = d ^ (b & (c ^ d));
|
132 | k = 0x5A827999;
|
133 | }
|
134 | else if (i < 40) {
|
135 | f = b ^ c ^ d;
|
136 | k = 0x6ED9EBA1;
|
137 | }
|
138 | else if (i < 60) {
|
139 | f = (b & c) | (d & (b | c));
|
140 | k = 0x8F1BBCDC;
|
141 | }
|
142 | else {
|
143 | f = b ^ c ^ d;
|
144 | k = 0xCA62C1D6;
|
145 | }
|
146 | var temp = (a << 5 | a >>> 27) + f + e + k + (this.block[i]|0);
|
147 | e = d;
|
148 | d = c;
|
149 | c = (b << 30 | b >>> 2);
|
150 | b = a;
|
151 | a = temp;
|
152 | }
|
153 |
|
154 |
|
155 | this.h0 = (this.h0 + a) | 0;
|
156 | this.h1 = (this.h1 + b) | 0;
|
157 | this.h2 = (this.h2 + c) | 0;
|
158 | this.h3 = (this.h3 + d) | 0;
|
159 | this.h4 = (this.h4 + e) | 0;
|
160 |
|
161 |
|
162 | this.offset = 0;
|
163 | for (i = 0; i < 16; i++) {
|
164 | this.block[i] = 0;
|
165 | }
|
166 | };
|