| 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 library crypto.hash_base; | 5 library crypto.hash_base; |
| 6 | 6 |
| 7 import 'dart:typed_data'; | 7 import 'dart:typed_data'; |
| 8 | 8 |
| 9 import 'package:typed_data/typed_data.dart'; | 9 import 'package:typed_data/typed_data.dart'; |
| 10 | 10 |
| 11 import 'digest.dart'; |
| 11 import 'hash.dart'; | 12 import 'hash.dart'; |
| 12 import 'utils.dart'; | 13 import 'utils.dart'; |
| 13 | 14 |
| 14 /// A base class for [Hash] implementations. | 15 /// A base class for [Sink] implementations for hash algorithms. |
| 15 /// | 16 /// |
| 16 /// Subclasses should override [updateHash] and [digest]. | 17 /// Subclasses should override [updateHash] and [digest]. |
| 17 abstract class HashBase implements Hash { | 18 abstract class HashSink implements Sink<List<int>> { |
| 19 /// The inner sink that this should forward to. |
| 20 final Sink<Digest> _sink; |
| 21 |
| 18 /// Whether the hash function operates on big-endian words. | 22 /// Whether the hash function operates on big-endian words. |
| 19 final Endianness _endian; | 23 final Endianness _endian; |
| 20 | 24 |
| 21 /// The words in the current chunk. | 25 /// The words in the current chunk. |
| 22 /// | 26 /// |
| 23 /// This is an instance variable to avoid re-allocating, but its data isn't | 27 /// This is an instance variable to avoid re-allocating, but its data isn't |
| 24 /// used across invocations of [_iterate]. | 28 /// used across invocations of [_iterate]. |
| 25 final Uint32List _currentChunk; | 29 final Uint32List _currentChunk; |
| 26 | 30 |
| 27 /// The length of the input data so far, in bytes. | 31 /// The length of the input data so far, in bytes. |
| 28 int _lengthInBytes = 0; | 32 int _lengthInBytes = 0; |
| 29 | 33 |
| 30 /// Data that has yet to be processed by the hash function. | 34 /// Data that has yet to be processed by the hash function. |
| 31 final _pendingData = new Uint8Buffer(); | 35 final _pendingData = new Uint8Buffer(); |
| 32 | 36 |
| 33 /// Whether [close] has been called. | 37 /// Whether [close] has been called. |
| 34 bool _isClosed = false; | 38 bool _isClosed = false; |
| 35 | 39 |
| 36 /// The words in the current digest. | 40 /// The words in the current digest. |
| 37 /// | 41 /// |
| 38 /// This should be updated each time [updateHash] is called. | 42 /// This should be updated each time [updateHash] is called. |
| 39 Uint32List get digest; | 43 Uint32List get digest; |
| 40 | 44 |
| 41 int get blockSize => _currentChunk.lengthInBytes; | |
| 42 | |
| 43 /// Creates a new hash. | 45 /// Creates a new hash. |
| 44 /// | 46 /// |
| 45 /// [chunkSizeInWords] represents the size of the input chunks processed by | 47 /// [chunkSizeInWords] represents the size of the input chunks processed by |
| 46 /// the algorithm, in terms of 32-bit words. | 48 /// the algorithm, in terms of 32-bit words. |
| 47 HashBase(int chunkSizeInWords, {Endianness endian: Endianness.BIG_ENDIAN}) | 49 HashSink(this._sink, int chunkSizeInWords, |
| 50 {Endianness endian: Endianness.BIG_ENDIAN}) |
| 48 : _endian = endian, | 51 : _endian = endian, |
| 49 _currentChunk = new Uint32List(chunkSizeInWords); | 52 _currentChunk = new Uint32List(chunkSizeInWords); |
| 50 | 53 |
| 51 /// Runs a single iteration of the hash computation, updating [digest] with | 54 /// Runs a single iteration of the hash computation, updating [digest] with |
| 52 /// the result. | 55 /// the result. |
| 53 /// | 56 /// |
| 54 /// [m] is the current chunk, whose size is given by the `chunkSizeInWords` | 57 /// [m] is the current chunk, whose size is given by the `chunkSizeInWords` |
| 55 /// parameter passed to the constructor. | 58 /// parameter passed to the constructor. |
| 56 void updateHash(Uint32List chunk); | 59 void updateHash(Uint32List chunk); |
| 57 | 60 |
| 58 void add(List<int> data) { | 61 void add(List<int> data) { |
| 59 if (_isClosed) throw new StateError('Hash.add() called after close().'); | 62 if (_isClosed) throw new StateError('Hash.add() called after close().'); |
| 60 _lengthInBytes += data.length; | 63 _lengthInBytes += data.length; |
| 61 _pendingData.addAll(data); | 64 _pendingData.addAll(data); |
| 62 _iterate(); | 65 _iterate(); |
| 63 } | 66 } |
| 64 | 67 |
| 65 List<int> close() { | 68 void close() { |
| 66 if (_isClosed) return _byteDigest(); | 69 if (_isClosed) return; |
| 67 _isClosed = true; | 70 _isClosed = true; |
| 68 | 71 |
| 69 _finalizeData(); | 72 _finalizeData(); |
| 70 _iterate(); | 73 _iterate(); |
| 71 assert(_pendingData.isEmpty); | 74 assert(_pendingData.isEmpty); |
| 72 return _byteDigest(); | 75 _sink.add(new Digest(_byteDigest())); |
| 73 } | 76 } |
| 74 | 77 |
| 75 Uint8List _byteDigest() { | 78 Uint8List _byteDigest() { |
| 76 if (_endian == Endianness.HOST_ENDIAN) return digest.buffer.asUint8List(); | 79 if (_endian == Endianness.HOST_ENDIAN) return digest.buffer.asUint8List(); |
| 77 | 80 |
| 78 var byteDigest = new Uint8List(digest.lengthInBytes); | 81 var byteDigest = new Uint8List(digest.lengthInBytes); |
| 79 var byteData = byteDigest.buffer.asByteData(); | 82 var byteData = byteDigest.buffer.asByteData(); |
| 80 for (var i = 0; i < digest.length; i++) { | 83 for (var i = 0; i < digest.length; i++) { |
| 81 byteData.setUint32(i * bytesPerWord, digest[i]); | 84 byteData.setUint32(i * bytesPerWord, digest[i]); |
| 82 } | 85 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 // hash. | 131 // hash. |
| 129 var offset = _pendingData.length; | 132 var offset = _pendingData.length; |
| 130 _pendingData.addAll(new Uint8List(8)); | 133 _pendingData.addAll(new Uint8List(8)); |
| 131 _pendingData.buffer.asByteData().setUint64(offset, lengthInBits, _endian); | 134 _pendingData.buffer.asByteData().setUint64(offset, lengthInBits, _endian); |
| 132 } | 135 } |
| 133 | 136 |
| 134 /// Rounds [val] up to the next multiple of [n], as long as [n] is a power of | 137 /// Rounds [val] up to the next multiple of [n], as long as [n] is a power of |
| 135 /// two. | 138 /// two. |
| 136 int _roundUp(int val, int n) => (val + n - 1) & -n; | 139 int _roundUp(int val, int n) => (val + n - 1) & -n; |
| 137 } | 140 } |
| OLD | NEW |