| 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 import 'dart:convert'; | 5 import 'dart:convert'; |
| 6 import 'dart:typed_data'; | 6 import 'dart:typed_data'; |
| 7 | 7 |
| 8 import 'package:typed_data/typed_data.dart'; | 8 import 'package:typed_data/typed_data.dart'; |
| 9 | 9 |
| 10 import 'digest.dart'; | 10 import 'digest.dart'; |
| 11 import 'digest_sink.dart'; | 11 import 'digest_sink.dart'; |
| 12 import 'hash.dart'; | 12 import 'hash.dart'; |
| 13 | 13 |
| 14 /// An implementation of [keyed-hash method authentication codes][rfc]. | 14 /// An implementation of [keyed-hash method authentication codes][rfc]. |
| 15 /// | 15 /// |
| 16 /// [rfc]: https://tools.ietf.org/html/rfc2104 | 16 /// [rfc]: https://tools.ietf.org/html/rfc2104 |
| 17 /// | 17 /// |
| 18 /// HMAC allows messages to be cryptographically authenticated using any | 18 /// HMAC allows messages to be cryptographically authenticated using any |
| 19 /// iterated cryptographic hash function. | 19 /// iterated cryptographic hash function. |
| 20 class HMAC extends Converter<List<int>, Digest> { | 20 class Hmac extends Converter<List<int>, Digest> { |
| 21 /// The hash function used to compute the authentication digest. | 21 /// The hash function used to compute the authentication digest. |
| 22 final Hash _hash; | 22 final Hash _hash; |
| 23 | 23 |
| 24 /// The secret key shared by the sender and the receiver. | 24 /// The secret key shared by the sender and the receiver. |
| 25 final Uint8List _key; | 25 final Uint8List _key; |
| 26 | 26 |
| 27 /// The bytes from the message so far. | |
| 28 final _message = new Uint8Buffer(); | |
| 29 | |
| 30 /// The sink for implementing the deprecated APIs that involved adding data | |
| 31 /// directly to the [HMAC] instance. | |
| 32 _HmacSink _sink; | |
| 33 | |
| 34 /// The sink that [_sink] sends the [Digest] to once it finishes hashing. | |
| 35 DigestSink _innerSink; | |
| 36 | |
| 37 /// Create an [HMAC] object from a [Hash] and a binary key. | 27 /// Create an [HMAC] object from a [Hash] and a binary key. |
| 38 /// | 28 /// |
| 39 /// The key should be a secret shared between the sender and receiver of the | 29 /// The key should be a secret shared between the sender and receiver of the |
| 40 /// message. | 30 /// message. |
| 41 HMAC(Hash hash, List<int> key) | 31 Hmac(Hash hash, List<int> key) |
| 42 : _hash = hash, | 32 : _hash = hash, |
| 43 _key = new Uint8List(hash.blockSize) { | 33 _key = new Uint8List(hash.blockSize) { |
| 44 // Hash the key if it's longer than the block size of the hash. | 34 // Hash the key if it's longer than the block size of the hash. |
| 45 if (key.length > _hash.blockSize) key = _hash.convert(key).bytes; | 35 if (key.length > _hash.blockSize) key = _hash.convert(key).bytes; |
| 46 | 36 |
| 47 // If [key] is shorter than the block size, the rest of [_key] will be | 37 // If [key] is shorter than the block size, the rest of [_key] will be |
| 48 // 0-padded. | 38 // 0-padded. |
| 49 _key.setRange(0, key.length, key); | 39 _key.setRange(0, key.length, key); |
| 50 | |
| 51 _innerSink = new DigestSink(); | |
| 52 _sink = startChunkedConversion(_innerSink); | |
| 53 } | 40 } |
| 54 | 41 |
| 55 Digest convert(List<int> data) { | 42 Digest convert(List<int> data) { |
| 56 var innerSink = new DigestSink(); | 43 var innerSink = new DigestSink(); |
| 57 var outerSink = startChunkedConversion(innerSink); | 44 var outerSink = startChunkedConversion(innerSink); |
| 58 outerSink.add(data); | 45 outerSink.add(data); |
| 59 outerSink.close(); | 46 outerSink.close(); |
| 60 return innerSink.value; | 47 return innerSink.value; |
| 61 } | 48 } |
| 62 | 49 |
| 63 ByteConversionSink startChunkedConversion(Sink<Digest> sink) => | 50 ByteConversionSink startChunkedConversion(Sink<Digest> sink) => |
| 64 new _HmacSink(sink, _hash, _key); | 51 new _HmacSink(sink, _hash, _key); |
| 52 } |
| 65 | 53 |
| 66 /// Adds a list of bytes to the message. | 54 /// This is deprecated. |
| 55 /// |
| 56 /// Use [Hmac] instead. |
| 57 @Deprecated("Will be removed in crypto 1.0.0.") |
| 58 class HMAC { |
| 59 final Hmac _hmac; |
| 60 |
| 61 /// The sink for implementing the deprecated APIs that involved adding data |
| 62 /// directly to the [HMAC] instance. |
| 63 _HmacSink _sink; |
| 64 |
| 65 /// The sink that [_sink] sends the [Digest] to once it finishes hashing. |
| 66 DigestSink _innerSink; |
| 67 |
| 68 /// The bytes from the message so far. |
| 69 final _message = new Uint8Buffer(); |
| 70 |
| 71 /// Create an [HMAC] object from a [Hash] and a binary key. |
| 67 /// | 72 /// |
| 68 /// If [this] has already been closed, throws a [StateError]. | 73 /// The key should be a secret shared between the sender and receiver of the |
| 69 @Deprecated("Expires in 1.0.0. Use HMAC.convert() or " | 74 /// message. |
| 70 "HMAC.startChunkedConversion() instead.") | 75 HMAC(Hash hash, List<int> key) : _hmac = new Hmac(hash, key) { |
| 76 _innerSink = new DigestSink(); |
| 77 _sink = _hmac.startChunkedConversion(_innerSink); |
| 78 } |
| 79 |
| 71 void add(List<int> data) { | 80 void add(List<int> data) { |
| 72 _message.addAll(data); | 81 _message.addAll(data); |
| 73 _sink.add(data); | 82 _sink.add(data); |
| 74 } | 83 } |
| 75 | 84 |
| 76 /// Closes [this] and returns the digest of the message as a list of bytes. | |
| 77 /// | |
| 78 /// Once closed, [add] may no longer be called. | |
| 79 @Deprecated("Expires in 1.0.0. Use HMAC.convert() or " | |
| 80 "HMAC.startChunkedConversion() instead.") | |
| 81 List<int> close() { | 85 List<int> close() { |
| 82 _sink.close(); | 86 _sink.close(); |
| 83 return _innerSink.value.bytes; | 87 return _innerSink.value.bytes; |
| 84 } | 88 } |
| 85 | 89 |
| 86 /// Returns the digest of the message so far, as a list of bytes. | |
| 87 @Deprecated("Expires in 1.0.0. Use HMAC.convert() or " | |
| 88 "HMAC.startChunkedConversion() instead.") | |
| 89 List<int> get digest { | 90 List<int> get digest { |
| 90 if (_sink._isClosed) return _innerSink.value.bytes; | 91 if (_sink._isClosed) return _innerSink.value.bytes; |
| 91 | 92 |
| 92 // This may be called at any point while the message is being hashed, but | 93 // This may be called at any point while the message is being hashed, but |
| 93 // the [_HmacSink] only supports getting the value once. To make this work, | 94 // the [_HmacSink] only supports getting the value once. To make this work, |
| 94 // we just re-hash everything after we get the digest. It's redundant, but | 95 // we just re-hash everything after we get the digest. It's redundant, but |
| 95 // this API is deprecated anyway. | 96 // this API is deprecated anyway. |
| 96 _sink.close(); | 97 _sink.close(); |
| 97 var bytes = _innerSink.value.bytes; | 98 var bytes = _innerSink.value.bytes; |
| 98 | 99 |
| 99 _innerSink = new DigestSink(); | 100 _innerSink = new DigestSink(); |
| 100 _sink = _hash.startChunkedConversion(_innerSink); | 101 _sink = _hmac._hash.startChunkedConversion(_innerSink); |
| 101 _sink.add(_message); | 102 _sink.add(_message); |
| 102 | 103 |
| 103 return bytes; | 104 return bytes; |
| 104 } | 105 } |
| 105 | 106 |
| 106 /// Returns whether the digest computed for the data so far matches the given | |
| 107 /// [digest]. | |
| 108 /// | |
| 109 /// This method should be used instead of iterative comparisons to avoid | |
| 110 /// leaking information via timing. | |
| 111 /// | |
| 112 /// Throws an [ArgumentError] if the given digest does not have the same size | |
| 113 /// as the digest computed by [this]. | |
| 114 @Deprecated("Expires in 1.0.0. Use Digest.==() instead.") | |
| 115 bool verify(List<int> digest) { | 107 bool verify(List<int> digest) { |
| 116 var computedDigest = this.digest; | 108 var computedDigest = this.digest; |
| 117 if (digest.length != computedDigest.length) { | 109 if (digest.length != computedDigest.length) { |
| 118 throw new ArgumentError( | 110 throw new ArgumentError( |
| 119 'Invalid digest size: ${digest.length} in HMAC.verify. ' | 111 'Invalid digest size: ${digest.length} in HMAC.verify. ' |
| 120 'Expected: ${_hash.blockSize}.'); | 112 'Expected: ${_hmac._hash.blockSize}.'); |
| 121 } | 113 } |
| 122 | 114 |
| 123 var result = 0; | 115 var result = 0; |
| 124 for (var i = 0; i < digest.length; i++) { | 116 for (var i = 0; i < digest.length; i++) { |
| 125 result |= digest[i] ^ computedDigest[i]; | 117 result |= digest[i] ^ computedDigest[i]; |
| 126 } | 118 } |
| 127 return result == 0; | 119 return result == 0; |
| 128 } | 120 } |
| 129 } | 121 } |
| 130 | 122 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 | 164 |
| 173 void close() { | 165 void close() { |
| 174 if (_isClosed) return; | 166 if (_isClosed) return; |
| 175 _isClosed = true; | 167 _isClosed = true; |
| 176 | 168 |
| 177 _innerSink.close(); | 169 _innerSink.close(); |
| 178 _outerSink.add(_innerResultSink.value.bytes); | 170 _outerSink.add(_innerResultSink.value.bytes); |
| 179 _outerSink.close(); | 171 _outerSink.close(); |
| 180 } | 172 } |
| 181 } | 173 } |
| OLD | NEW |