Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/hash/sha1.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * SHA-1.
7 * Ripped from package:crypto.
8 */
9 library sha1;
10
11 import 'dart:math' show pow;
12 import 'dart:convert';
13
14 /// Returns the base64-encoded SHA-1 hash of the utf-8 bytes of [input].
15 String hashOfString(String input) {
16 Hash hasher = new SHA1();
17 hasher.add(const Utf8Encoder().convert(input));
18 return _bytesToBase64(hasher.close());
19 }
20
21 /**
22 * Converts a list of bytes into a Base 64 encoded string.
23 *
24 * The list can be any list of integers in the range 0..255,
25 * for example a message digest.
26 *
27 * If [addLineSeparator] is true, the resulting string will be
28 * broken into lines of 76 characters, separated by "\r\n".
29 *
30 * If [urlSafe] is true, the result is URL and filename safe.
31 *
32 * Based on [RFC 4648](http://tools.ietf.org/html/rfc4648)
33 *
34 */
35 String _bytesToBase64(List<int> bytes,
36 {bool urlSafe : false,
37 bool addLineSeparator : false}) {
38 return _CryptoUtils.bytesToBase64(bytes,
39 urlSafe,
40 addLineSeparator);
41 }
42
43
44 // Constants.
45 const _MASK_8 = 0xff;
46 const _MASK_32 = 0xffffffff;
47 const _BITS_PER_BYTE = 8;
48 const _BYTES_PER_WORD = 4;
49
50 // Helper functions used by more than one hasher.
51
52 // Rotate left limiting to unsigned 32-bit values.
53 int _rotl32(int val, int shift) {
54 var mod_shift = shift & 31;
55 return ((val << mod_shift) & _MASK_32) |
56 ((val & _MASK_32) >> (32 - mod_shift));
57 }
58
59 // Base class encapsulating common behavior for cryptographic hash
60 // functions.
61 abstract class _HashBase implements Hash {
62 final int _chunkSizeInWords;
63 final int _digestSizeInWords;
64 final bool _bigEndianWords;
65 final List<int> _currentChunk;
66 final List<int> _h;
67 int _lengthInBytes = 0;
68 List<int> _pendingData;
69 bool _digestCalled = false;
70
71 _HashBase(int chunkSizeInWords,
72 int digestSizeInWords,
73 bool this._bigEndianWords)
74 : _pendingData = [],
75 _currentChunk = new List(chunkSizeInWords),
76 _h = new List(digestSizeInWords),
77 _chunkSizeInWords = chunkSizeInWords,
78 _digestSizeInWords = digestSizeInWords;
79
80 // Update the hasher with more data.
81 void add(List<int> data) {
82 if (_digestCalled) {
83 throw new StateError(
84 'Hash update method called after digest was retrieved');
85 }
86 _lengthInBytes += data.length;
87 _pendingData.addAll(data);
88 _iterate();
89 }
90
91 // Finish the hash computation and return the digest string.
92 List<int> close() {
93 if (_digestCalled) {
94 return _resultAsBytes();
95 }
96 _digestCalled = true;
97 _finalizeData();
98 _iterate();
99 assert(_pendingData.length == 0);
100 return _resultAsBytes();
101 }
102
103 // Returns the block size of the hash in bytes.
104 int get blockSize {
105 return _chunkSizeInWords * _BYTES_PER_WORD;
106 }
107
108 // One round of the hash computation.
109 void _updateHash(List<int> m);
110
111 // Helper methods.
112 int _add32(x, y) => (x + y) & _MASK_32;
113 int _roundUp(val, n) => (val + n - 1) & -n;
114
115 // Compute the final result as a list of bytes from the hash words.
116 List<int> _resultAsBytes() {
117 var result = [];
118 for (var i = 0; i < _h.length; i++) {
119 result.addAll(_wordToBytes(_h[i]));
120 }
121 return result;
122 }
123
124 // Converts a list of bytes to a chunk of 32-bit words.
125 void _bytesToChunk(List<int> data, int dataIndex) {
126 assert((data.length - dataIndex) >= (_chunkSizeInWords * _BYTES_PER_WORD));
127
128 for (var wordIndex = 0; wordIndex < _chunkSizeInWords; wordIndex++) {
129 var w3 = _bigEndianWords ? data[dataIndex] : data[dataIndex + 3];
130 var w2 = _bigEndianWords ? data[dataIndex + 1] : data[dataIndex + 2];
131 var w1 = _bigEndianWords ? data[dataIndex + 2] : data[dataIndex + 1];
132 var w0 = _bigEndianWords ? data[dataIndex + 3] : data[dataIndex];
133 dataIndex += 4;
134 var word = (w3 & 0xff) << 24;
135 word |= (w2 & _MASK_8) << 16;
136 word |= (w1 & _MASK_8) << 8;
137 word |= (w0 & _MASK_8);
138 _currentChunk[wordIndex] = word;
139 }
140 }
141
142 // Convert a 32-bit word to four bytes.
143 List<int> _wordToBytes(int word) {
144 List<int> bytes = new List(_BYTES_PER_WORD);
145 bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
146 bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
147 bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8;
148 bytes[3] = (word >> (_bigEndianWords ? 0 : 24)) & _MASK_8;
149 return bytes;
150 }
151
152 // Iterate through data updating the hash computation for each
153 // chunk.
154 void _iterate() {
155 var len = _pendingData.length;
156 var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
157 if (len >= chunkSizeInBytes) {
158 var index = 0;
159 for (; (len - index) >= chunkSizeInBytes; index += chunkSizeInBytes) {
160 _bytesToChunk(_pendingData, index);
161 _updateHash(_currentChunk);
162 }
163 _pendingData = _pendingData.sublist(index, len);
164 }
165 }
166
167 // Finalize the data. Add a 1 bit to the end of the message. Expand with
168 // 0 bits and add the length of the message.
169 void _finalizeData() {
170 _pendingData.add(0x80);
171 var contentsLength = _lengthInBytes + 9;
172 var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
173 var finalizedLength = _roundUp(contentsLength, chunkSizeInBytes);
174 var zeroPadding = finalizedLength - contentsLength;
175 for (var i = 0; i < zeroPadding; i++) {
176 _pendingData.add(0);
177 }
178 var lengthInBits = _lengthInBytes * _BITS_PER_BYTE;
179 assert(lengthInBits < pow(2, 32));
180 if (_bigEndianWords) {
181 _pendingData.addAll(_wordToBytes(0));
182 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
183 } else {
184 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
185 _pendingData.addAll(_wordToBytes(0));
186 }
187 }
188 }
189
190
191 /**
192 * Interface for cryptographic hash functions.
193 *
194 * The [add] method is used to add data to the hash. The [close] method
195 * is used to extract the message digest.
196 *
197 * Once the [close] method has been called no more data can be added using the
198 * [add] method. If [add] is called after the first call to [close] a
199 * HashException is thrown.
200 *
201 * If multiple instances of a given Hash is needed the [newInstance]
202 * method can provide a new instance.
203 */
204 // TODO(floitsch): make Hash implement Sink, EventSink or similar.
205 abstract class Hash {
206 /**
207 * Add a list of bytes to the hash computation.
208 */
209 void add(List<int> data);
210
211 /**
212 * Finish the hash computation and extract the message digest as
213 * a list of bytes.
214 */
215 List<int> close();
216
217 /**
218 * Internal block size of the hash in bytes.
219 *
220 * This is exposed for use by the HMAC class which needs to know the
221 * block size for the [Hash] it is using.
222 */
223 int get blockSize;
224 }
225
226 /**
227 * SHA1 hash function implementation.
228 */
229 class SHA1 extends _HashBase {
230 final List<int> _w;
231
232 // Construct a SHA1 hasher object.
233 SHA1() : _w = new List(80), super(16, 5, true) {
234 _h[0] = 0x67452301;
235 _h[1] = 0xEFCDAB89;
236 _h[2] = 0x98BADCFE;
237 _h[3] = 0x10325476;
238 _h[4] = 0xC3D2E1F0;
239 }
240
241 // Compute one iteration of the SHA1 algorithm with a chunk of
242 // 16 32-bit pieces.
243 void _updateHash(List<int> m) {
244 assert(m.length == 16);
245
246 var a = _h[0];
247 var b = _h[1];
248 var c = _h[2];
249 var d = _h[3];
250 var e = _h[4];
251
252 for (var i = 0; i < 80; i++) {
253 if (i < 16) {
254 _w[i] = m[i];
255 } else {
256 var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
257 _w[i] = _rotl32(n, 1);
258 }
259 var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
260 if (i < 20) {
261 t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
262 } else if (i < 40) {
263 t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
264 } else if (i < 60) {
265 t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
266 } else {
267 t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
268 }
269
270 e = d;
271 d = c;
272 c = _rotl32(b, 30);
273 b = a;
274 a = t & _MASK_32;
275 }
276
277 _h[0] = _add32(a, _h[0]);
278 _h[1] = _add32(b, _h[1]);
279 _h[2] = _add32(c, _h[2]);
280 _h[3] = _add32(d, _h[3]);
281 _h[4] = _add32(e, _h[4]);
282 }
283 }
284
285 abstract class _CryptoUtils {
286
287 static const int PAD = 61; // '='
288 static const int CR = 13; // '\r'
289 static const int LF = 10; // '\n'
290 static const int LINE_LENGTH = 76;
291
292 static const String _encodeTable =
293 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
294
295 static const String _encodeTableUrlSafe =
296 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
297
298 // Lookup table used for finding Base 64 alphabet index of a given byte.
299 // -2 : Outside Base 64 alphabet.
300 // -1 : '\r' or '\n'
301 // 0 : = (Padding character).
302 // >0 : Base 64 alphabet index of given byte.
303 static const List<int> _decodeTable =
304 const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2,
305 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
306 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63,
307 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2,
308 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
309 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63,
310 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
311 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
312 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
313 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
314 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
315 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
316 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
317 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
318 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
319 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ];
320
321 static String bytesToBase64(List<int> bytes,
322 [bool urlSafe = false,
323 bool addLineSeparator = false]) {
324 int len = bytes.length;
325 if (len == 0) {
326 return "";
327 }
328 final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable;
329 // Size of 24 bit chunks.
330 final int remainderLength = len.remainder(3);
331 final int chunkLength = len - remainderLength;
332 // Size of base output.
333 int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0);
334 // Add extra for line separators.
335 if (addLineSeparator) {
336 outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1;
337 }
338 List<int> out = new List<int>(outputLen);
339
340 // Encode 24 bit chunks.
341 int j = 0, i = 0, c = 0;
342 while (i < chunkLength) {
343 int x = ((bytes[i++] << 16) & 0xFFFFFF) |
344 ((bytes[i++] << 8) & 0xFFFFFF) |
345 bytes[i++];
346 out[j++] = lookup.codeUnitAt(x >> 18);
347 out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F);
348 out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F);
349 out[j++] = lookup.codeUnitAt(x & 0x3f);
350 // Add optional line separator for each 76 char output.
351 if (addLineSeparator && ++c == 19 && j < outputLen - 2) {
352 out[j++] = CR;
353 out[j++] = LF;
354 c = 0;
355 }
356 }
357
358 // If input length if not a multiple of 3, encode remaining bytes and
359 // add padding.
360 if (remainderLength == 1) {
361 int x = bytes[i];
362 out[j++] = lookup.codeUnitAt(x >> 2);
363 out[j++] = lookup.codeUnitAt((x << 4) & 0x3F);
364 out[j++] = PAD;
365 out[j++] = PAD;
366 } else if (remainderLength == 2) {
367 int x = bytes[i];
368 int y = bytes[i + 1];
369 out[j++] = lookup.codeUnitAt(x >> 2);
370 out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F);
371 out[j++] = lookup.codeUnitAt((y << 2) & 0x3F);
372 out[j++] = PAD;
373 }
374
375 return new String.fromCharCodes(out);
376 }
377 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698