OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * SHA-1. | 6 * SHA-1. |
7 * Ripped from package:crypto. | 7 * Ripped from package:crypto. |
8 */ | 8 */ |
9 library sha1; | 9 library sha1; |
10 | 10 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 * | 47 * |
48 * If [addLineSeparator] is true, the resulting string will be | 48 * If [addLineSeparator] is true, the resulting string will be |
49 * broken into lines of 76 characters, separated by "\r\n". | 49 * broken into lines of 76 characters, separated by "\r\n". |
50 * | 50 * |
51 * If [urlSafe] is true, the result is URL and filename safe. | 51 * If [urlSafe] is true, the result is URL and filename safe. |
52 * | 52 * |
53 * Based on [RFC 4648](http://tools.ietf.org/html/rfc4648) | 53 * Based on [RFC 4648](http://tools.ietf.org/html/rfc4648) |
54 * | 54 * |
55 */ | 55 */ |
56 String _bytesToBase64(List<int> bytes, | 56 String _bytesToBase64(List<int> bytes, |
57 {bool urlSafe : false, | 57 {bool urlSafe: false, bool addLineSeparator: false}) { |
58 bool addLineSeparator : false}) { | 58 return _CryptoUtils.bytesToBase64(bytes, urlSafe, addLineSeparator); |
59 return _CryptoUtils.bytesToBase64(bytes, | |
60 urlSafe, | |
61 addLineSeparator); | |
62 } | 59 } |
63 } | 60 } |
64 | 61 |
65 | |
66 // Constants. | 62 // Constants. |
67 const _MASK_8 = 0xff; | 63 const _MASK_8 = 0xff; |
68 const _MASK_32 = 0xffffffff; | 64 const _MASK_32 = 0xffffffff; |
69 const _BITS_PER_BYTE = 8; | 65 const _BITS_PER_BYTE = 8; |
70 const _BYTES_PER_WORD = 4; | 66 const _BYTES_PER_WORD = 4; |
71 | 67 |
72 // Helper functions used by more than one hasher. | 68 // Helper functions used by more than one hasher. |
73 | 69 |
74 // Rotate left limiting to unsigned 32-bit values. | 70 // Rotate left limiting to unsigned 32-bit values. |
75 int _rotl32(int val, int shift) { | 71 int _rotl32(int val, int shift) { |
76 var mod_shift = shift & 31; | 72 var mod_shift = shift & 31; |
77 return ((val << mod_shift) & _MASK_32) | | 73 return ((val << mod_shift) & _MASK_32) | |
78 ((val & _MASK_32) >> (32 - mod_shift)); | 74 ((val & _MASK_32) >> (32 - mod_shift)); |
79 } | 75 } |
80 | 76 |
81 // Base class encapsulating common behavior for cryptographic hash | 77 // Base class encapsulating common behavior for cryptographic hash |
82 // functions. | 78 // functions. |
83 abstract class _HashBase implements Hash { | 79 abstract class _HashBase implements Hash { |
84 final int _chunkSizeInWords; | 80 final int _chunkSizeInWords; |
85 final int _digestSizeInWords; | 81 final int _digestSizeInWords; |
86 final bool _bigEndianWords; | 82 final bool _bigEndianWords; |
87 final List<int> _currentChunk; | 83 final List<int> _currentChunk; |
88 final List<int> _h; | 84 final List<int> _h; |
89 int _lengthInBytes = 0; | 85 int _lengthInBytes = 0; |
90 List<int> _pendingData; | 86 List<int> _pendingData; |
91 bool _digestCalled = false; | 87 bool _digestCalled = false; |
92 | 88 |
93 _HashBase(int chunkSizeInWords, | 89 _HashBase( |
94 int digestSizeInWords, | 90 int chunkSizeInWords, int digestSizeInWords, bool this._bigEndianWords) |
95 bool this._bigEndianWords) | |
96 : _pendingData = [], | 91 : _pendingData = [], |
97 _currentChunk = new List(chunkSizeInWords), | 92 _currentChunk = new List(chunkSizeInWords), |
98 _h = new List(digestSizeInWords), | 93 _h = new List(digestSizeInWords), |
99 _chunkSizeInWords = chunkSizeInWords, | 94 _chunkSizeInWords = chunkSizeInWords, |
100 _digestSizeInWords = digestSizeInWords; | 95 _digestSizeInWords = digestSizeInWords; |
101 | 96 |
102 // Update the hasher with more data. | 97 // Update the hasher with more data. |
103 void add(List<int> data) { | 98 void add(List<int> data) { |
104 if (_digestCalled) { | 99 if (_digestCalled) { |
105 throw new StateError( | 100 throw new StateError( |
106 'Hash update method called after digest was retrieved'); | 101 'Hash update method called after digest was retrieved'); |
107 } | 102 } |
108 _lengthInBytes += data.length; | 103 _lengthInBytes += data.length; |
109 _pendingData.addAll(data); | 104 _pendingData.addAll(data); |
110 _iterate(); | 105 _iterate(); |
111 } | 106 } |
112 | 107 |
113 // Finish the hash computation and return the digest string. | 108 // Finish the hash computation and return the digest string. |
114 List<int> close() { | 109 List<int> close() { |
115 if (_digestCalled) { | 110 if (_digestCalled) { |
116 return _resultAsBytes(); | 111 return _resultAsBytes(); |
117 } | 112 } |
118 _digestCalled = true; | 113 _digestCalled = true; |
119 _finalizeData(); | 114 _finalizeData(); |
120 _iterate(); | 115 _iterate(); |
121 assert(_pendingData.length == 0); | 116 assert(_pendingData.length == 0); |
122 return _resultAsBytes(); | 117 return _resultAsBytes(); |
123 } | 118 } |
124 | 119 |
125 // Returns the block size of the hash in bytes. | 120 // Returns the block size of the hash in bytes. |
126 int get blockSize { | 121 int get blockSize { |
127 return _chunkSizeInWords * _BYTES_PER_WORD; | 122 return _chunkSizeInWords * _BYTES_PER_WORD; |
128 } | 123 } |
129 | 124 |
130 // One round of the hash computation. | 125 // One round of the hash computation. |
131 void _updateHash(List<int> m); | 126 void _updateHash(List<int> m); |
132 | 127 |
133 // Helper methods. | 128 // Helper methods. |
134 int _add32(x, y) => (x + y) & _MASK_32; | 129 int _add32(x, y) => (x + y) & _MASK_32; |
135 int _roundUp(val, n) => (val + n - 1) & -n; | 130 int _roundUp(val, n) => (val + n - 1) & -n; |
136 | 131 |
137 // Compute the final result as a list of bytes from the hash words. | 132 // Compute the final result as a list of bytes from the hash words. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 if (_bigEndianWords) { | 197 if (_bigEndianWords) { |
203 _pendingData.addAll(_wordToBytes(0)); | 198 _pendingData.addAll(_wordToBytes(0)); |
204 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32)); | 199 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32)); |
205 } else { | 200 } else { |
206 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32)); | 201 _pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32)); |
207 _pendingData.addAll(_wordToBytes(0)); | 202 _pendingData.addAll(_wordToBytes(0)); |
208 } | 203 } |
209 } | 204 } |
210 } | 205 } |
211 | 206 |
212 | |
213 /** | 207 /** |
214 * Interface for cryptographic hash functions. | 208 * Interface for cryptographic hash functions. |
215 * | 209 * |
216 * The [add] method is used to add data to the hash. The [close] method | 210 * The [add] method is used to add data to the hash. The [close] method |
217 * is used to extract the message digest. | 211 * is used to extract the message digest. |
218 * | 212 * |
219 * Once the [close] method has been called no more data can be added using the | 213 * Once the [close] method has been called no more data can be added using the |
220 * [add] method. If [add] is called after the first call to [close] a | 214 * [add] method. If [add] is called after the first call to [close] a |
221 * HashException is thrown. | 215 * HashException is thrown. |
222 * | 216 * |
(...skipping 22 matching lines...) Expand all Loading... |
245 int get blockSize; | 239 int get blockSize; |
246 } | 240 } |
247 | 241 |
248 /** | 242 /** |
249 * SHA1 hash function implementation. | 243 * SHA1 hash function implementation. |
250 */ | 244 */ |
251 class SHA1 extends _HashBase { | 245 class SHA1 extends _HashBase { |
252 final List<int> _w; | 246 final List<int> _w; |
253 | 247 |
254 // Construct a SHA1 hasher object. | 248 // Construct a SHA1 hasher object. |
255 SHA1() : _w = new List(80), super(16, 5, true) { | 249 SHA1() |
| 250 : _w = new List(80), |
| 251 super(16, 5, true) { |
256 _h[0] = 0x67452301; | 252 _h[0] = 0x67452301; |
257 _h[1] = 0xEFCDAB89; | 253 _h[1] = 0xEFCDAB89; |
258 _h[2] = 0x98BADCFE; | 254 _h[2] = 0x98BADCFE; |
259 _h[3] = 0x10325476; | 255 _h[3] = 0x10325476; |
260 _h[4] = 0xC3D2E1F0; | 256 _h[4] = 0xC3D2E1F0; |
261 } | 257 } |
262 | 258 |
263 // Compute one iteration of the SHA1 algorithm with a chunk of | 259 // Compute one iteration of the SHA1 algorithm with a chunk of |
264 // 16 32-bit pieces. | 260 // 16 32-bit pieces. |
265 void _updateHash(List<int> m) { | 261 void _updateHash(List<int> m) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 | 294 |
299 _h[0] = _add32(a, _h[0]); | 295 _h[0] = _add32(a, _h[0]); |
300 _h[1] = _add32(b, _h[1]); | 296 _h[1] = _add32(b, _h[1]); |
301 _h[2] = _add32(c, _h[2]); | 297 _h[2] = _add32(c, _h[2]); |
302 _h[3] = _add32(d, _h[3]); | 298 _h[3] = _add32(d, _h[3]); |
303 _h[4] = _add32(e, _h[4]); | 299 _h[4] = _add32(e, _h[4]); |
304 } | 300 } |
305 } | 301 } |
306 | 302 |
307 abstract class _CryptoUtils { | 303 abstract class _CryptoUtils { |
308 | |
309 static const int PAD = 61; // '=' | 304 static const int PAD = 61; // '=' |
310 static const int CR = 13; // '\r' | 305 static const int CR = 13; // '\r' |
311 static const int LF = 10; // '\n' | 306 static const int LF = 10; // '\n' |
312 static const int LINE_LENGTH = 76; | 307 static const int LINE_LENGTH = 76; |
313 | 308 |
314 static const String _encodeTable = | 309 static const String _encodeTable = |
315 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 310 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
316 | 311 |
317 static const String _encodeTableUrlSafe = | 312 static const String _encodeTableUrlSafe = |
318 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | 313 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
319 | 314 |
320 static String bytesToBase64(List<int> bytes, | 315 static String bytesToBase64(List<int> bytes, |
321 [bool urlSafe = false, | 316 [bool urlSafe = false, bool addLineSeparator = false]) { |
322 bool addLineSeparator = false]) { | |
323 int len = bytes.length; | 317 int len = bytes.length; |
324 if (len == 0) { | 318 if (len == 0) { |
325 return ""; | 319 return ""; |
326 } | 320 } |
327 final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable; | 321 final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable; |
328 // Size of 24 bit chunks. | 322 // Size of 24 bit chunks. |
329 final int remainderLength = len.remainder(3); | 323 final int remainderLength = len.remainder(3); |
330 final int chunkLength = len - remainderLength; | 324 final int chunkLength = len - remainderLength; |
331 // Size of base output. | 325 // Size of base output. |
332 int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0); | 326 int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0); |
333 // Add extra for line separators. | 327 // Add extra for line separators. |
334 if (addLineSeparator) { | 328 if (addLineSeparator) { |
335 outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1; | 329 outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1; |
336 } | 330 } |
337 List<int> out = new List<int>(outputLen); | 331 List<int> out = new List<int>(outputLen); |
338 | 332 |
339 // Encode 24 bit chunks. | 333 // Encode 24 bit chunks. |
340 int j = 0, i = 0, c = 0; | 334 int j = 0, i = 0, c = 0; |
341 while (i < chunkLength) { | 335 while (i < chunkLength) { |
342 int x = ((bytes[i++] << 16) & 0xFFFFFF) | | 336 int x = ((bytes[i++] << 16) & 0xFFFFFF) | |
343 ((bytes[i++] << 8) & 0xFFFFFF) | | 337 ((bytes[i++] << 8) & 0xFFFFFF) | |
344 bytes[i++]; | 338 bytes[i++]; |
345 out[j++] = lookup.codeUnitAt(x >> 18); | 339 out[j++] = lookup.codeUnitAt(x >> 18); |
346 out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F); | 340 out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F); |
347 out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F); | 341 out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F); |
348 out[j++] = lookup.codeUnitAt(x & 0x3f); | 342 out[j++] = lookup.codeUnitAt(x & 0x3f); |
349 // Add optional line separator for each 76 char output. | 343 // Add optional line separator for each 76 char output. |
350 if (addLineSeparator && ++c == 19 && j < outputLen - 2) { | 344 if (addLineSeparator && ++c == 19 && j < outputLen - 2) { |
351 out[j++] = CR; | 345 out[j++] = CR; |
352 out[j++] = LF; | 346 out[j++] = LF; |
353 c = 0; | 347 c = 0; |
354 } | 348 } |
355 } | 349 } |
356 | 350 |
357 // If input length if not a multiple of 3, encode remaining bytes and | 351 // If input length if not a multiple of 3, encode remaining bytes and |
358 // add padding. | 352 // add padding. |
359 if (remainderLength == 1) { | 353 if (remainderLength == 1) { |
360 int x = bytes[i]; | 354 int x = bytes[i]; |
361 out[j++] = lookup.codeUnitAt(x >> 2); | 355 out[j++] = lookup.codeUnitAt(x >> 2); |
362 out[j++] = lookup.codeUnitAt((x << 4) & 0x3F); | 356 out[j++] = lookup.codeUnitAt((x << 4) & 0x3F); |
363 out[j++] = PAD; | 357 out[j++] = PAD; |
364 out[j++] = PAD; | 358 out[j++] = PAD; |
365 } else if (remainderLength == 2) { | 359 } else if (remainderLength == 2) { |
366 int x = bytes[i]; | 360 int x = bytes[i]; |
367 int y = bytes[i + 1]; | 361 int y = bytes[i + 1]; |
368 out[j++] = lookup.codeUnitAt(x >> 2); | 362 out[j++] = lookup.codeUnitAt(x >> 2); |
369 out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F); | 363 out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F); |
370 out[j++] = lookup.codeUnitAt((y << 2) & 0x3F); | 364 out[j++] = lookup.codeUnitAt((y << 2) & 0x3F); |
371 out[j++] = PAD; | 365 out[j++] = PAD; |
372 } | 366 } |
373 | 367 |
374 return new String.fromCharCodes(out); | 368 return new String.fromCharCodes(out); |
375 } | 369 } |
376 } | 370 } |
OLD | NEW |