Skip to content

Commit 69627aa

Browse files
jtmcdoleefortuna
authored andcommitted
Add missing SHA224, SHA384, and SHA512 (dart-archive/crypto#63)
* Add SHA384 and SHA512 Sha384 and Sha512 share the same implementation and differ only in the initailization vectors and the digest concatentation. The algorithm from from rfc6234 calls for 64bit words and operations and to remain dart2js friendly, BigInt was used. INPUT REQUESTED: I'm not sure where the test vectors came from; but a simple comparison to sha384 and sha512 command line methods shows it matching. If you can point me to them, then I can write a better test. * Add Sha224 + Refactor Do something less stupid; use _Sha32BitSink and _Sha64BitSink to have class heirarchies make better sense. * Support 32bit and 64bit operations for SHA384/512 Two modes of operation: if you're in a browser, you get the slower 32bit algorithm because you only have 2^53 bits. If you are on the VM / Flutter, you'll have 64bit operations wich is *much* faster: 32BIT NUMBERS: ~20MB/s hashing Removing BigInt has some good results: Instance of 'Sha224' warmup: 0:00:00.015599 Instance of 'Sha256' warmup: 0:00:00.002325 Instance of 'Sha384' warmup: 0:00:00.019082 Instance of 'Sha512' warmup: 0:00:00.010288 Instance of 'Sha224' real: 0:00:00.092928 Instance of 'Sha256' real: 0:00:00.093426 Instance of 'Sha384' real: 0:00:00.823335 Instance of 'Sha512' real: 0:00:00.807871 64BIT NUMBERS: ~236MB/s hashing On the VM, this is much faster with 64bit operations. Instance of 'Sha224' warmup: 0:00:00.013285 Instance of 'Sha256' warmup: 0:00:00.002443 Instance of 'Sha384' warmup: 0:00:00.020954 Instance of 'Sha512' warmup: 0:00:00.005616 Instance of 'Sha224' real: 0:00:00.097196 Instance of 'Sha256' real: 0:00:00.094167 Instance of 'Sha384' real: 0:00:00.067605 Instance of 'Sha512' real: 0:00:00.067564 NOTE: Compiles with dart2js - cannot reference 64bit hex as the compiler just vomits... but you can left shift by 32. * Fix comment * Add conditional imports * De-listify 32bit allocations Speed is still meh in dart2js: 384/512 numbers: Instance of 'minified:a2' real: 0:00:02.203820 Instance of 'minified:aO' real: 0:00:02.192515 * Add sha monte tests for 224,256,384, and 512 RSP values came from http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip * Fix formattting of lib/crypto.dart * Bump version (adding new features) + min sdk * Bump travis (hidden file) * Rework monte test to function-only.
1 parent 2b7c62f commit 69627aa

11 files changed

+955
-65
lines changed

pkgs/crypto/.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
language: dart
22

33
dart:
4-
- 2.0.0
5-
- dev
4+
- 2.1.0
5+
- stable
66

77
dart_task:
88
- test: -p vm

pkgs/crypto/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ A set of cryptographic hashing functions implemented in pure Dart
55
The following hashing algorithms are supported:
66

77
* SHA-1
8+
* SHA-224
89
* SHA-256
10+
* SHA-384
11+
* SHA-512
912
* MD5
1013
* HMAC (i.e. HMAC-MD5, HMAC-SHA1, HMAC-SHA256)
1114

@@ -105,7 +108,10 @@ Please file feature requests and bugs at the [issue tracker][tracker].
105108
[Hmac]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Hmac-class.html
106109
[MD5]: https://www.dartdocs.org/documentation/crypto/latest/crypto/MD5-class.html
107110
[Sha1]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Sha1-class.html
111+
[Sha224]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Sha224-class.html
108112
[Sha256]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Sha256-class.html
113+
[Sha384]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Sha384-class.html
114+
[Sha512]: https://www.dartdocs.org/documentation/crypto/latest/crypto/Sha512-class.html
109115
[md5-obj]: https://www.dartdocs.org/documentation/crypto/latest/crypto/md5.html
110116
[sha1-obj]: https://www.dartdocs.org/documentation/crypto/latest/crypto/sha1.html
111117
[sha256-obj]: https://www.dartdocs.org/documentation/crypto/latest/crypto/sha256.html

pkgs/crypto/lib/crypto.dart

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export 'src/hmac.dart';
88
export 'src/md5.dart';
99
export 'src/sha1.dart';
1010
export 'src/sha256.dart';
11+
export 'src/sha512.dart';

pkgs/crypto/lib/src/sha256.dart

+94-38
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ import 'utils.dart';
1717
/// [rfc]: http://tools.ietf.org/html/rfc6234
1818
final sha256 = Sha256._();
1919

20+
/// An instance of [Sha224].
21+
///
22+
/// This instance provides convenient access to the [Sha224][rfc] hash function.
23+
///
24+
/// [rfc]: http://tools.ietf.org/html/rfc6234
25+
final sha224 = Sha224._();
26+
2027
/// An implementation of the [SHA-256][rfc] hash function.
2128
///
2229
/// [rfc]: http://tools.ietf.org/html/rfc6234
@@ -36,6 +43,25 @@ class Sha256 extends Hash {
3643
ByteConversionSink.from(_Sha256Sink(sink));
3744
}
3845

46+
/// An implementation of the [SHA-224][rfc] hash function.
47+
///
48+
/// [rfc]: http://tools.ietf.org/html/rfc6234
49+
///
50+
/// Note that it's almost always easier to use [sha224] rather than creating a
51+
/// new instance.
52+
class Sha224 extends Hash {
53+
@override
54+
final int blockSize = 16 * bytesPerWord;
55+
56+
Sha224._();
57+
58+
Sha224 newInstance() => Sha224._();
59+
60+
@override
61+
ByteConversionSink startChunkedConversion(Sink<Digest> sink) =>
62+
ByteConversionSink.from(_Sha224Sink(sink));
63+
}
64+
3965
/// Data from a non-linear function that functions as reproducible noise.
4066
const List<int> _noise = [
4167
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, //
@@ -51,34 +77,16 @@ const List<int> _noise = [
5177
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
5278
];
5379

54-
/// The concrete implementation of [Sha256].
55-
///
56-
/// This is separate so that it can extend [HashSink] without leaking additional
57-
/// public members.
58-
class _Sha256Sink extends HashSink {
59-
@override
60-
final digest = Uint32List(8);
80+
abstract class _Sha32BitSink extends HashSink {
81+
final Uint32List _digest;
6182

6283
/// The sixteen words from the original chunk, extended to 64 words.
6384
///
6485
/// This is an instance variable to avoid re-allocating, but its data isn't
6586
/// used across invocations of [updateHash].
66-
final Uint32List _extended;
87+
final _extended = Uint32List(64);
6788

68-
_Sha256Sink(Sink<Digest> sink)
69-
: _extended = Uint32List(64),
70-
super(sink, 16) {
71-
// Initial value of the hash parts. First 32 bits of the fractional parts
72-
// of the square roots of the first 8 prime numbers.
73-
digest[0] = 0x6a09e667;
74-
digest[1] = 0xbb67ae85;
75-
digest[2] = 0x3c6ef372;
76-
digest[3] = 0xa54ff53a;
77-
digest[4] = 0x510e527f;
78-
digest[5] = 0x9b05688c;
79-
digest[6] = 0x1f83d9ab;
80-
digest[7] = 0x5be0cd19;
81-
}
89+
_Sha32BitSink(Sink<Digest> sink, this._digest) : super(sink, 16);
8290

8391
// The following helper functions are taken directly from
8492
// http://tools.ietf.org/html/rfc6234.
@@ -105,14 +113,14 @@ class _Sha256Sink extends HashSink {
105113
}
106114

107115
// Shuffle around the bits.
108-
var a = digest[0];
109-
var b = digest[1];
110-
var c = digest[2];
111-
var d = digest[3];
112-
var e = digest[4];
113-
var f = digest[5];
114-
var g = digest[6];
115-
var h = digest[7];
116+
var a = _digest[0];
117+
var b = _digest[1];
118+
var c = _digest[2];
119+
var d = _digest[3];
120+
var e = _digest[4];
121+
var f = _digest[5];
122+
var g = _digest[6];
123+
var h = _digest[7];
116124

117125
for (var i = 0; i < 64; i++) {
118126
var temp1 = add32(add32(h, _bsig1(e)),
@@ -129,13 +137,61 @@ class _Sha256Sink extends HashSink {
129137
}
130138

131139
// Update hash values after iteration.
132-
digest[0] = add32(a, digest[0]);
133-
digest[1] = add32(b, digest[1]);
134-
digest[2] = add32(c, digest[2]);
135-
digest[3] = add32(d, digest[3]);
136-
digest[4] = add32(e, digest[4]);
137-
digest[5] = add32(f, digest[5]);
138-
digest[6] = add32(g, digest[6]);
139-
digest[7] = add32(h, digest[7]);
140+
_digest[0] = add32(a, _digest[0]);
141+
_digest[1] = add32(b, _digest[1]);
142+
_digest[2] = add32(c, _digest[2]);
143+
_digest[3] = add32(d, _digest[3]);
144+
_digest[4] = add32(e, _digest[4]);
145+
_digest[5] = add32(f, _digest[5]);
146+
_digest[6] = add32(g, _digest[6]);
147+
_digest[7] = add32(h, _digest[7]);
140148
}
141149
}
150+
151+
/// The concrete implementation of [Sha256].
152+
///
153+
/// This is separate so that it can extend [HashSink] without leaking additional
154+
/// public members.
155+
class _Sha256Sink extends _Sha32BitSink {
156+
@override
157+
Uint32List get digest => _digest;
158+
159+
// Initial value of the hash parts. First 32 bits of the fractional parts
160+
// of the square roots of the first 8 prime numbers.
161+
_Sha256Sink(Sink<Digest> sink)
162+
: super(
163+
sink,
164+
Uint32List.fromList([
165+
0x6a09e667,
166+
0xbb67ae85,
167+
0x3c6ef372,
168+
0xa54ff53a,
169+
0x510e527f,
170+
0x9b05688c,
171+
0x1f83d9ab,
172+
0x5be0cd19,
173+
]));
174+
}
175+
176+
/// The concrete implementation of [Sha224].
177+
///
178+
/// This is separate so that it can extend [HashSink] without leaking additional
179+
/// public members.
180+
class _Sha224Sink extends _Sha32BitSink {
181+
@override
182+
Uint32List get digest => _digest.buffer.asUint32List(0, 7);
183+
184+
_Sha224Sink(Sink<Digest> sink)
185+
: super(
186+
sink,
187+
Uint32List.fromList([
188+
0xc1059ed8,
189+
0x367cd507,
190+
0x3070dd17,
191+
0xf70e5939,
192+
0xffc00b31,
193+
0x68581511,
194+
0x64f98fa7,
195+
0xbefa4fa4,
196+
]));
197+
}

pkgs/crypto/lib/src/sha512.dart

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2019, 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+
import 'dart:convert';
6+
7+
import 'digest.dart';
8+
import 'hash.dart';
9+
import 'sha512_fastsinks.dart' if (dart.library.js) 'sha512_slowsinks.dart';
10+
//import 'sha512_slowsinks.dart';
11+
import 'utils.dart';
12+
13+
/// An instance of [Sha2Sha384].
14+
///
15+
/// This instance provides convenient access to the [Sha384][rfc] hash function.
16+
///
17+
/// [rfc]: http://tools.ietf.org/html/rfc6234
18+
final sha384 = Sha384._();
19+
20+
/// An instance of [Sha2Sha512].
21+
///
22+
/// This instance provides convenient access to the [Sha512][rfc] hash function.
23+
///
24+
/// [rfc]: http://tools.ietf.org/html/rfc6234
25+
final sha512 = Sha512._();
26+
27+
/// An implementation of the [SHA-384][rfc] hash function.
28+
///
29+
/// [rfc]: http://tools.ietf.org/html/rfc6234
30+
///
31+
/// Note that it's almost always easier to use [sha384] rather than creating a
32+
/// new instance.
33+
class Sha384 extends Hash {
34+
@override
35+
final int blockSize = 16 * bytesPerWord;
36+
37+
Sha384._();
38+
39+
Sha384 newInstance() => Sha384._();
40+
41+
@override
42+
ByteConversionSink startChunkedConversion(Sink<Digest> sink) =>
43+
ByteConversionSink.from(Sha384Sink(sink));
44+
}
45+
46+
/// An implementation of the [SHA-512][rfc] hash function.
47+
///
48+
/// [rfc]: http://tools.ietf.org/html/rfc6234
49+
///
50+
/// Note that it's almost always easier to use [sha512] rather than creating a
51+
/// new instance.
52+
class Sha512 extends Sha384 {
53+
Sha512._() : super._();
54+
55+
Sha512 newInstance() => Sha512._();
56+
57+
@override
58+
ByteConversionSink startChunkedConversion(Sink<Digest> sink) =>
59+
ByteConversionSink.from(Sha512Sink(sink));
60+
}

0 commit comments

Comments
 (0)