From c7f974cf5849c260027fc028aad8fe7f3a5963c6 Mon Sep 17 00:00:00 2001 From: Sudipto Chandra Date: Sun, 8 Sep 2024 23:07:04 +0400 Subject: [PATCH] Modifies `MACHash` and `MACHashBase` interfaces for accessibility --- .pubignore | 5 +- CHANGELOG.md | 4 + lib/src/algorithms/blake2/blake2b_32bit.dart | 14 +-- lib/src/algorithms/blake2/blake2b_64bit.dart | 10 +- lib/src/algorithms/blake2/blake2s.dart | 10 +- lib/src/algorithms/pbkdf2/pbkdf2.dart | 6 +- lib/src/algorithms/pbkdf2/security.dart | 2 +- lib/src/blake2b.dart | 101 ++++++++++--------- lib/src/blake2s.dart | 101 ++++++++++--------- lib/src/core/block_hash.dart | 5 +- lib/src/core/hash_base.dart | 5 +- lib/src/core/mac_base.dart | 29 ++---- lib/src/hmac.dart | 23 ++++- lib/src/hotp.dart | 2 +- lib/src/pbkdf2.dart | 2 +- lib/src/poly1305.dart | 26 +++-- pubspec.yaml | 2 +- test/blake2b_test.dart | 75 +++++--------- test/blake2s_test.dart | 82 ++++++--------- test/compare_test.dart | 16 ++- test/core/mac_base_test.dart | 2 +- 21 files changed, 251 insertions(+), 271 deletions(-) diff --git a/.pubignore b/.pubignore index d147cdf..3b3f29d 100644 --- a/.pubignore +++ b/.pubignore @@ -1,6 +1,7 @@ /test -/script -/benchmark /coverage +/benchmark +/doc /build +/scripts /.github diff --git a/CHANGELOG.md b/CHANGELOG.md index e6b883a..5b7b9d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.20.1 + +- Modifies `MACHash` and `MACHashBase` interfaces for accessibility. + # 1.20.0 - [![codecov](https://codecov.io/gh/bitanon/hashlib/graph/badge.svg?token=ISIYJ8MNI0)](https://codecov.io/gh/bitanon/hashlib) diff --git a/lib/src/algorithms/blake2/blake2b_32bit.dart b/lib/src/algorithms/blake2/blake2b_32bit.dart index 740f7de..8a88266 100644 --- a/lib/src/algorithms/blake2/blake2b_32bit.dart +++ b/lib/src/algorithms/blake2/blake2b_32bit.dart @@ -100,7 +100,7 @@ class Blake2bHash extends BlockHashSink implements MACSinkBase { int digestSize, { this.key, List? salt, - List? personalization, + List? aad, }) : hashLength = digestSize, derivedKeyLength = digestSize, super(1024 >>> 3) { @@ -152,21 +152,21 @@ class Blake2bHash extends BlockHashSink implements MACSinkBase { } } - if (personalization != null && personalization.isNotEmpty) { - if (personalization.length != 16) { + if (aad != null && aad.isNotEmpty) { + if (aad.length != 16) { throw ArgumentError('The valid length of personalization is 16 bytes'); } for (int i = 0, p = 0; i < 4; i++, p += 8) { - _s12 ^= (personalization[i] & 0xFF) << p; + _s12 ^= (aad[i] & 0xFF) << p; } for (int i = 4, p = 0; i < 8; i++, p += 8) { - _s13 ^= (personalization[i] & 0xFF) << p; + _s13 ^= (aad[i] & 0xFF) << p; } for (int i = 8, p = 0; i < 12; i++, p += 8) { - _s14 ^= (personalization[i] & 0xFF) << p; + _s14 ^= (aad[i] & 0xFF) << p; } for (int i = 12, p = 0; i < 16; i++, p += 8) { - _s15 ^= (personalization[i] & 0xFF) << p; + _s15 ^= (aad[i] & 0xFF) << p; } } diff --git a/lib/src/algorithms/blake2/blake2b_64bit.dart b/lib/src/algorithms/blake2/blake2b_64bit.dart index 8843117..9010045 100644 --- a/lib/src/algorithms/blake2/blake2b_64bit.dart +++ b/lib/src/algorithms/blake2/blake2b_64bit.dart @@ -78,7 +78,7 @@ class Blake2bHash extends BlockHashSink implements MACSinkBase { int digestSize, { this.key, List? salt, - List? personalization, + List? aad, }) : hashLength = digestSize, derivedKeyLength = digestSize, super(1024 >>> 3) { @@ -116,15 +116,15 @@ class Blake2bHash extends BlockHashSink implements MACSinkBase { } } - if (personalization != null && personalization.isNotEmpty) { - if (personalization.length != 16) { + if (aad != null && aad.isNotEmpty) { + if (aad.length != 16) { throw ArgumentError('The valid length of personalization is 16 bytes'); } for (int i = 0, p = 0; i < 8; i++, p += 8) { - _s6 ^= (personalization[i] & 0xFF) << p; + _s6 ^= (aad[i] & 0xFF) << p; } for (int i = 8, p = 0; i < 16; i++, p += 8) { - _s7 ^= (personalization[i] & 0xFF) << p; + _s7 ^= (aad[i] & 0xFF) << p; } } diff --git a/lib/src/algorithms/blake2/blake2s.dart b/lib/src/algorithms/blake2/blake2s.dart index b9c251e..0742637 100644 --- a/lib/src/algorithms/blake2/blake2s.dart +++ b/lib/src/algorithms/blake2/blake2s.dart @@ -78,7 +78,7 @@ class Blake2sHash extends BlockHashSink implements MACSinkBase { int digestSize, { this.key, List? salt, - List? personalization, + List? aad, }) : hashLength = digestSize, derivedKeyLength = digestSize, super(64) { @@ -116,15 +116,15 @@ class Blake2sHash extends BlockHashSink implements MACSinkBase { } } - if (personalization != null && personalization.isNotEmpty) { - if (personalization.length != 8) { + if (aad != null && aad.isNotEmpty) { + if (aad.length != 8) { throw ArgumentError('The valid length of personalization is 8 bytes'); } for (int i = 0, p = 0; i < 4; i++, p += 8) { - _s6 ^= (personalization[i] & 0xFF) << p; + _s6 ^= (aad[i] & 0xFF) << p; } for (int i = 4, p = 0; i < 8; i++, p += 8) { - _s7 ^= (personalization[i] & 0xFF) << p; + _s7 ^= (aad[i] & 0xFF) << p; } } diff --git a/lib/src/algorithms/pbkdf2/pbkdf2.dart b/lib/src/algorithms/pbkdf2/pbkdf2.dart index f8d599c..3423ffb 100644 --- a/lib/src/algorithms/pbkdf2/pbkdf2.dart +++ b/lib/src/algorithms/pbkdf2/pbkdf2.dart @@ -32,7 +32,7 @@ class PBKDF2 extends KeyDerivatorBase { String get name => '${algo.name}/PBKDF2'; /// The underlying algorithm used as Pseudo Random Function (PRF) - final MACHashBase algo; + final MACHash algo; /// The byte array containing salt final List salt; @@ -52,7 +52,7 @@ class PBKDF2 extends KeyDerivatorBase { /// Create a [PBKDF2] instance with a MAC instance. factory PBKDF2( - MACHashBase mac, + MACHash mac, int iterations, { List? salt, int? keyLength, @@ -84,7 +84,7 @@ class PBKDF2 extends KeyDerivatorBase { factory PBKDF2.fromSecurity( PBKDF2Security security, { List? salt, - MACHashBase? mac, + MACHash? mac, int? iterations, int? keyLength, }) => diff --git a/lib/src/algorithms/pbkdf2/security.dart b/lib/src/algorithms/pbkdf2/security.dart index 2494e38..dc77715 100644 --- a/lib/src/algorithms/pbkdf2/security.dart +++ b/lib/src/algorithms/pbkdf2/security.dart @@ -22,7 +22,7 @@ class PBKDF2Security { final int dklen; /// The underlying algorithm - final MACHashBase mac; + final MACHash mac; const PBKDF2Security( this.name, { diff --git a/lib/src/blake2b.dart b/lib/src/blake2b.dart index cfef1f8..6d2e6be 100644 --- a/lib/src/blake2b.dart +++ b/lib/src/blake2b.dart @@ -5,25 +5,27 @@ import 'package:hashlib/src/algorithms/blake2/blake2b.dart'; import 'package:hashlib/src/core/block_hash.dart'; import 'package:hashlib/src/core/mac_base.dart'; +export 'algorithms/blake2/blake2b.dart' show Blake2bHash; + /// For generating un-keyed message digest with BLAKE2b-160. /// /// Use [Blake2b] for keyed hash generation. -const Blake2b blake2b160 = Blake2b(160 >>> 3); +const Blake2b blake2b160 = Blake2b._(160 >>> 3); /// For generating un-keyed message digest with BLAKE2b-256. /// /// Use [Blake2b] for keyed hash generation. -const Blake2b blake2b256 = Blake2b(256 >>> 3); +const Blake2b blake2b256 = Blake2b._(256 >>> 3); /// For generating un-keyed message digest with BLAKE2b-384. /// /// Use [Blake2b] for keyed hash generation. -const Blake2b blake2b384 = Blake2b(384 >>> 3); +const Blake2b blake2b384 = Blake2b._(384 >>> 3); /// For generating un-keyed message digest with BLAKE2b-512. /// /// Use [Blake2b] for keyed hash generation. -const Blake2b blake2b512 = Blake2b(512 >>> 3); +const Blake2b blake2b512 = Blake2b._(512 >>> 3); /// Blake2b is a highly secure cryptographic hash function optimized for 64-bit /// platforms. It generates hash values of data ranging from 1 to 64 bytes in @@ -34,34 +36,47 @@ const Blake2b blake2b512 = Blake2b(512 >>> 3); /// This implementation is based on the [RFC-7693][rfc] /// /// [rfc]: https://www.ietf.org/rfc/rfc7693.html -class Blake2b extends BlockHashBase { +class Blake2b extends BlockHashBase with MACHashBase { + final List? _key; + final List? _salt; + final List? _aad; + + /// The number of bytes in the output. final int digestSize; - final List? salt; - final List? personalization; @override - String get name => 'BLAKE2b-${digestSize << 3}'; + final String name; + + const Blake2b._( + this.digestSize, [ + this._key, + this._salt, + this._aad, + String? _name, + ]) : name = _name ?? 'BLAKE2b-${digestSize << 3}'; /// Creates an instance to generate hash using BLAKE-2b algorithm. /// /// Parameters: /// - [digestSize] The number of bytes in the output. /// - [salt] An optional nonce. Must be exactly 16 bytes long. - /// - [personalization] Second optional nonce. Must be exactly 16 bytes long. + /// - [aad] Second optional nonce. Must be exactly 16 bytes long. /// /// See also: /// - [mac] or [Blake2bMAC] for generating MAC with this algorithm. - const Blake2b( - this.digestSize, { - this.salt, - this.personalization, - }); + factory Blake2b( + int digestSize, { + List? salt, + List? aad, + }) => + Blake2b._(digestSize, null, salt, aad); @override Blake2bHash createSink() => Blake2bHash( digestSize, - salt: salt, - personalization: personalization, + key: _key, + salt: _salt, + aad: _aad, ); /// Get a builder to generate MAC using this algorithm. @@ -72,49 +87,39 @@ class Blake2b extends BlockHashBase { /// final message = 'plain message'.codeUnits; /// final mac = blake2s256.mac.by(key).convert(message); /// ``` - Blake2bMAC get mac => Blake2bMAC._(this); - - /// Get a new instance with different [salt] and [personalization] value. - /// - /// If a parameter is null, it passes the current one to the new instance. - Blake2b config({ - List? salt, - List? personalization, - }) => - Blake2b( - digestSize, - salt: salt ?? this.salt, - personalization: personalization ?? this.personalization, - ); + Blake2bMAC get mac => Blake2bMAC(digestSize); } -class Blake2bMAC extends MACHashBase { - final Blake2b _algo; - - const Blake2bMAC._(this._algo); +class Blake2bMAC extends MACHash { + /// The number of bytes in the output. + final int digestSize; @override - String get name => '${_algo.name}/MAC'; + final String name; + + /// Creates an instance to generate MAC using BLAKE-2b algorithm. + /// + /// Parameters: + /// - [digestSize] The number of bytes in the output. + /// + /// See also: + /// - [Blake2b] for generating hash only. + const Blake2bMAC( + this.digestSize, + ) : name = 'BLAKE2b-${digestSize << 3}/MAC'; - /// Get an [MACHash] instance initialized by a [key]. + /// Get an [MACHashBase] instance initialized by a [key]. /// /// Parameters: /// - [key] An optional key for MAC generation. Should not exceed 64 bytes. /// - [salt] An optional nonce. Must be exactly 16 bytes long. - /// - [personalization] Second optional nonce. Must be exactly 16 bytes long. + /// - [aad] Second optional nonce. Must be exactly 16 bytes long. @override @pragma('vm:prefer-inline') - MACHash by( + MACHashBase by( List key, { List? salt, - List? personalization, - }) { - final sink = Blake2bHash( - _algo.digestSize, - key: key, - salt: salt ?? _algo.salt, - personalization: personalization ?? _algo.personalization, - ); - return MACHash(name, sink); - } + List? aad, + }) => + Blake2b._(digestSize, key, salt, aad, name); } diff --git a/lib/src/blake2s.dart b/lib/src/blake2s.dart index d5d73eb..045c4b4 100644 --- a/lib/src/blake2s.dart +++ b/lib/src/blake2s.dart @@ -5,25 +5,27 @@ import 'package:hashlib/src/algorithms/blake2/blake2s.dart'; import 'package:hashlib/src/core/block_hash.dart'; import 'package:hashlib/src/core/mac_base.dart'; +export 'algorithms/blake2/blake2s.dart' show Blake2sHash; + /// For generating un-keyed message digest with BLAKE2s-128. /// /// Use [Blake2s] for keyed hash generation. -const Blake2s blake2s128 = Blake2s(128 >>> 3); +const Blake2s blake2s128 = Blake2s._(128 >>> 3); /// For generating un-keyed message digest with BLAKE2s-160. /// /// Use [Blake2s] for keyed hash generation. -const Blake2s blake2s160 = Blake2s(160 >>> 3); +const Blake2s blake2s160 = Blake2s._(160 >>> 3); /// For generating un-keyed message digest with BLAKE2s-224. /// /// Use [Blake2s] for keyed hash generation. -const Blake2s blake2s224 = Blake2s(224 >>> 3); +const Blake2s blake2s224 = Blake2s._(224 >>> 3); /// For generating un-keyed message digest with BLAKE2s-256. /// /// Use [Blake2s] for keyed hash generation. -const Blake2s blake2s256 = Blake2s(256 >>> 3); +const Blake2s blake2s256 = Blake2s._(256 >>> 3); /// Blake2s is a cryptographic hash function optimized for 8-bit to 32-bit /// platforms. It generates hash values of data ranging from 1 to 32 bytes in @@ -33,34 +35,47 @@ const Blake2s blake2s256 = Blake2s(256 >>> 3); /// This implementation is based on the [RFC-7693][rfc] /// /// [rfc]: https://www.ietf.org/rfc/rfc7693.html -class Blake2s extends BlockHashBase { +class Blake2s extends BlockHashBase with MACHashBase { + final List? _key; + final List? _salt; + final List? _aad; + + /// The number of bytes in the output. final int digestSize; - final List? salt; - final List? personalization; @override - String get name => 'BLAKE2s-${digestSize << 3}'; + final String name; + + const Blake2s._( + this.digestSize, [ + this._key, + this._salt, + this._aad, + String? _name, + ]) : name = _name ?? 'BLAKE2s-${digestSize << 3}'; /// Creates an instance to generate hash using BLAKE-2s algorithm. /// /// Parameters: /// - [digestSize] The number of bytes in the output. /// - [salt] An optional nonce. Must be exactly 8 bytes long. - /// - [personalization] Second optional nonce. Must be exactly 8 bytes long. + /// - [aad] Second optional nonce. Must be exactly 8 bytes long. /// /// See also: /// - [mac] or [Blake2sMAC] for generating MAC with this algorithm. - const Blake2s( - this.digestSize, { - this.salt, - this.personalization, - }); + factory Blake2s( + int digestSize, { + List? salt, + List? aad, + }) => + Blake2s._(digestSize, null, salt, aad); @override Blake2sHash createSink() => Blake2sHash( digestSize, - salt: salt, - personalization: personalization, + key: _key, + salt: _salt, + aad: _aad, ); /// Get a builder to generate MAC using this algorithm. @@ -71,49 +86,39 @@ class Blake2s extends BlockHashBase { /// final message = 'plain message'.codeUnits; /// final mac = blake2s256.mac.by(key).convert(message); /// ``` - Blake2sMAC get mac => Blake2sMAC._(this); - - /// Get a new instance with different [salt] and [personalization] value. - /// - /// If a parameter is null, it passes the current one to the new instance. - Blake2s config({ - List? salt, - List? personalization, - }) => - Blake2s( - digestSize, - salt: salt ?? this.salt, - personalization: personalization ?? this.personalization, - ); + Blake2sMAC get mac => Blake2sMAC(digestSize); } -class Blake2sMAC extends MACHashBase { - final Blake2s _algo; - - const Blake2sMAC._(this._algo); +class Blake2sMAC extends MACHash { + /// The number of bytes in the output. + final int digestSize; @override - String get name => '${_algo.name}/MAC'; + final String name; + + /// Creates an instance to generate MAC using BLAKE-2s algorithm. + /// + /// Parameters: + /// - [digestSize] The number of bytes in the output. + /// + /// See also: + /// - [Blake2s] for generating hash only. + const Blake2sMAC( + this.digestSize, + ) : name = 'BLAKE2s-${digestSize << 3}/MAC'; - /// Get an [MACHash] instance initialized by a [key]. + /// Get an [MACHashBase] instance initialized by a [key]. /// /// Parameters: /// - [key] The key for MAC generation. Should not exceed 32 bytes. /// - [salt] An optional nonce. Must be exactly 8 bytes long. - /// - [personalization] Second optional nonce. Must be exactly 8 bytes long. + /// - [aad] Second optional nonce. Must be exactly 8 bytes long. @override @pragma('vm:prefer-inline') - MACHash by( + MACHashBase by( List key, { List? salt, - List? personalization, - }) { - final sink = Blake2sHash( - _algo.digestSize, - key: key, - salt: salt ?? _algo.salt, - personalization: personalization ?? _algo.personalization, - ); - return MACHash(name, sink); - } + List? aad, + }) => + Blake2s._(digestSize, key, salt, aad, name); } diff --git a/lib/src/core/block_hash.dart b/lib/src/core/block_hash.dart index 9ad24f6..73b22e4 100644 --- a/lib/src/core/block_hash.dart +++ b/lib/src/core/block_hash.dart @@ -5,11 +5,8 @@ import 'dart:typed_data'; import 'package:hashlib/src/core/hash_base.dart'; -abstract class BlockHashBase extends HashBase { +abstract class BlockHashBase extends HashBase { const BlockHashBase(); - - @override - BlockHashSink createSink(); } abstract class BlockHashSink extends HashDigestSink { diff --git a/lib/src/core/hash_base.dart b/lib/src/core/hash_base.dart index dd4c620..722e5bd 100644 --- a/lib/src/core/hash_base.dart +++ b/lib/src/core/hash_base.dart @@ -66,14 +66,15 @@ abstract class HashDigestSink implements Sink> { /// The base class used by the hash algorithm implementations. It implements /// the [StreamTransformer] and exposes few convenient methods to handle any /// types of data source. -abstract class HashBase implements StreamTransformer, HashDigest> { +abstract class HashBase + implements StreamTransformer, HashDigest> { const HashBase(); /// The name of this algorithm String get name; /// Create a [HashDigestSink] for generating message-digests - HashDigestSink createSink(); + T createSink(); /// Process the byte array [input] and returns a [HashDigest]. @pragma('vm:prefer-inline') diff --git a/lib/src/core/mac_base.dart b/lib/src/core/mac_base.dart index 04c41cd..426c30b 100644 --- a/lib/src/core/mac_base.dart +++ b/lib/src/core/mac_base.dart @@ -11,21 +11,8 @@ abstract class MACSinkBase extends HashDigestSink { int get derivedKeyLength => hashLength; } -class MACHash extends HashBase { - final T _sink; - - @override - final String name; - - const MACHash(this.name, this._sink); - - @override - @pragma('vm:prefer-inline') - T createSink() { - _sink.reset(); - return _sink; - } - +/// This can be used as a mixin for MAC algorithm interfaces +abstract class MACHashBase implements HashBase { /// Signing the [message] using this MAC to generate a tag. @pragma('vm:prefer-inline') HashDigest sign(List message) => convert(message); @@ -36,21 +23,21 @@ class MACHash extends HashBase { convert(message).isEqual(tag); } -abstract class MACHashBase { - const MACHashBase(); +abstract class MACHash { + const MACHash(); /// The name of this algorithm String get name; - /// Get an [MACHash] instance initialized by a [key]. + /// Get a [MACHashBase] instance initialized by a [key]. @pragma('vm:prefer-inline') - MACHash by(List key); + MACHashBase by(List key); - /// Get an [MACHash] instance initialized by a string [key]. + /// Get a [MACHashBase] instance initialized by a string [key]. /// /// If [encoding] is not specified, the [String.codeUnits] are used. @pragma('vm:prefer-inline') - MACHash byString(String key, [Encoding? encoding]) => + MACHashBase byString(String key, [Encoding? encoding]) => by(encoding != null ? encoding.encode(key) : key.codeUnits); /// Signing the [message] using a [key] to generate a tag. diff --git a/lib/src/hmac.dart b/lib/src/hmac.dart index cfb7689..3fc2df6 100644 --- a/lib/src/hmac.dart +++ b/lib/src/hmac.dart @@ -3,6 +3,7 @@ import 'package:hashlib/src/algorithms/hmac.dart'; import 'package:hashlib/src/core/block_hash.dart'; +import 'package:hashlib/src/core/hash_base.dart'; import 'package:hashlib/src/core/mac_base.dart'; import 'package:hashlib/src/sha256.dart'; @@ -12,7 +13,24 @@ const hmac_sha256 = HMAC(sha256); /// HMAC is a hash-based message authentication code that can be used to /// simultaneously verify both the data integrity and authenticity of a message. -class HMAC extends MACHashBase> { +class _HMAC extends HashBase> + with MACHashBase> { + /// The algorithm for the MAC generation + final T algo; + final List key; + + const _HMAC(this.algo, this.key); + + @override + String get name => '${algo.name}/HMAC'; + + @override + HMACSink createSink() => HMACSink(algo, key); +} + +/// HMAC is a hash-based message authentication code that can be used to +/// simultaneously verify both the data integrity and authenticity of a message. +class HMAC extends MACHash> { /// The algorithm for the MAC generation final T algo; @@ -22,8 +40,7 @@ class HMAC extends MACHashBase> { String get name => '${algo.name}/HMAC'; @override - @pragma('vm:prefer-inline') - MACHash> by(List key) => MACHash(name, HMACSink(algo, key)); + MACHashBase> by(List key) => _HMAC(algo, key); } /// Extension on [BlockHashBase] to get an [HMAC] instance diff --git a/lib/src/hotp.dart b/lib/src/hotp.dart index f68c0eb..c6ea56c 100644 --- a/lib/src/hotp.dart +++ b/lib/src/hotp.dart @@ -35,7 +35,7 @@ class HOTP extends OTPAuth { final int _max; /// The underlying MAC algorithm - final MACHash algo; + final MACHashBase algo; /// The secret key final List secret; diff --git a/lib/src/pbkdf2.dart b/lib/src/pbkdf2.dart index 258471c..21eb48f 100644 --- a/lib/src/pbkdf2.dart +++ b/lib/src/pbkdf2.dart @@ -13,7 +13,7 @@ export 'algorithms/pbkdf2/pbkdf2.dart' show PBKDF2; export 'algorithms/pbkdf2/security.dart' show PBKDF2Security; /// Extension to the HashBase to get an [PBKDF2] instance -extension PBKDF2onMACHashBase on MACHashBase { +extension PBKDF2onMACHashBase on MACHash { /// Generate a secret using [PBKDF2] hash algorithm. @pragma('vm:prefer-inline') PBKDF2 pbkdf2( diff --git a/lib/src/poly1305.dart b/lib/src/poly1305.dart index 1999569..c10162e 100644 --- a/lib/src/poly1305.dart +++ b/lib/src/poly1305.dart @@ -4,6 +4,7 @@ import 'dart:typed_data'; import 'package:hashlib/src/algorithms/poly1305/poly1305_sink.dart'; +import 'package:hashlib/src/core/hash_base.dart'; import 'package:hashlib/src/core/hash_digest.dart'; import 'package:hashlib/src/core/mac_base.dart'; @@ -13,7 +14,19 @@ export 'algorithms/poly1305/poly1305_sink.dart' show Poly1305Sink; /// message using either 16 or 32-byte long authentication key. const poly1305 = Poly1305(); -class Poly1305 extends MACHashBase { +class _Poly1305 extends HashBase with MACHashBase { + final Uint8List key; + + const _Poly1305(this.key); + + @override + final String name = 'Poly1305'; + + @override + Poly1305Sink createSink() => Poly1305Sink(key); +} + +class Poly1305 extends MACHash { const Poly1305(); @override @@ -36,11 +49,8 @@ class Poly1305 extends MACHashBase { /// See also: /// - [Poly1305.pair] to input key(`r`) and secret(`s`) pair separately. @override - @pragma('vm:prefer-inline') - MACHash by(List keypair) { - var key8 = keypair is Uint8List ? keypair : Uint8List.fromList(keypair); - return MACHash(name, Poly1305Sink(key8)); - } + MACHashBase by(List keypair) => + _Poly1305(keypair is Uint8List ? keypair : Uint8List.fromList(keypair)); /// Creates a new instance of [Poly1305]. /// @@ -59,7 +69,7 @@ class Poly1305 extends MACHashBase { /// /// See also: /// - [Poly1305.by] to input key(`r`) and secret(`s`) pair together. - MACHash pair(List key, [List? secret]) { + MACHashBase pair(List key, [List? secret]) { if (secret == null) { return by(key); } @@ -72,7 +82,7 @@ class Poly1305 extends MACHashBase { var pair = Uint8List(32); pair.setAll(0, key); pair.setAll(16, secret); - return by(pair); + return _Poly1305(pair); } } diff --git a/pubspec.yaml b/pubspec.yaml index a16db13..180e703 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hashlib description: Secure hash functions, checksum generators, and key derivation algorithms optimized for Dart. homepage: https://github.com/bitanon/hashlib -version: 1.20.0 +version: 1.20.1 environment: sdk: '>=2.14.0 <4.0.0' diff --git a/test/blake2b_test.dart b/test/blake2b_test.dart index d1c8d7c..097df95 100644 --- a/test/blake2b_test.dart +++ b/test/blake2b_test.dart @@ -7,6 +7,33 @@ import 'package:hashlib/hashlib.dart'; import 'package:test/test.dart'; void main() { + group('Blake2bHash functionality test', () { + test('The digest size must be between 1 and 64', () { + Blake2bHash(1); + Blake2bHash(64); + expect(() => Blake2bHash(0), throwsArgumentError); + expect(() => Blake2bHash(65), throwsArgumentError); + }); + test('The valid length of salt is 16 bytes ', () { + Blake2bHash(16, salt: Uint8List(0)); + Blake2bHash(16, salt: Uint8List(16)); + expect(() => Blake2bHash(16, salt: Uint8List(1)), throwsArgumentError); + expect(() => Blake2bHash(16, salt: Uint8List(17)), throwsArgumentError); + }); + test('The valid length of personalization is 16 bytes ', () { + Blake2bHash(16, aad: Uint8List(0)); + Blake2bHash(16, aad: Uint8List(16)); + expect(() => Blake2bHash(16, aad: Uint8List(1)), throwsArgumentError); + expect(() => Blake2bHash(16, aad: Uint8List(17)), throwsArgumentError); + }); + test('The key should not be greater than 64 bytes ', () { + Blake2bHash(16, key: Uint8List(0)); + Blake2bHash(16, key: Uint8List(1)); + Blake2bHash(16, key: Uint8List(64)); + expect(() => Blake2bHash(16, key: Uint8List(65)), throwsArgumentError); + }); + }); + group('Blake2b funtionality test', () { test("Blake2b name", () { expect(Blake2b(8).name, 'BLAKE2b-64'); @@ -27,45 +54,6 @@ void main() { expect(blake2b512.mac.pbkdf2([2]).name, 'BLAKE2b-512/MAC/PBKDF2'); expect(blake2b512.hmac.pbkdf2([2]).name, 'BLAKE2b-512/HMAC/PBKDF2'); }); - test('The digest size must be between 1 and 64', () { - Blake2b(1).createSink(); - Blake2b(64).createSink(); - expect(() => Blake2b(0).createSink(), throwsArgumentError); - expect(() => Blake2b(65).createSink(), throwsArgumentError); - }); - test('The valid length of salt is 16 bytes ', () { - Blake2b(16, salt: Uint8List(0)).createSink(); - Blake2b(16, salt: Uint8List(16)).createSink(); - expect( - () => Blake2b(16, salt: Uint8List(1)).convert([]), - throwsArgumentError, - ); - expect( - () => Blake2b(16, salt: Uint8List(17)).convert([]), - throwsArgumentError, - ); - }); - test('The valid length of personalization is 16 bytes ', () { - Blake2b(16, personalization: Uint8List(0)).createSink(); - Blake2b(16, personalization: Uint8List(16)).createSink(); - expect( - () => Blake2b(16, personalization: Uint8List(1)).convert([]), - throwsArgumentError, - ); - expect( - () => Blake2b(16, personalization: Uint8List(17)).convert([]), - throwsArgumentError, - ); - }); - test('The key should not be greater than 64 bytes ', () { - Blake2b(16).mac.by(Uint8List(0)).createSink(); - Blake2b(16).mac.by(Uint8List(1)).createSink(); - Blake2b(16).mac.by(Uint8List(64)).createSink(); - expect( - () => Blake2b(16).mac.by(Uint8List(65)).createSink(), - throwsArgumentError, - ); - }); test('sink test', () { final input = List.generate(512, (i) => i & 0xFF); final output = @@ -86,15 +74,6 @@ void main() { expect(sink.closed, isTrue); expect(sink.digest().hex(), equals(output)); }); - test('Blake2b config without any parameters', () { - expect(blake2b256.config().string('abc').hex(), - "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"); - }); - test('Blake2b config with salt', () { - final salt = 'some long salt'.codeUnits; - expect(blake2b256.config(salt: salt).string('a').hex(), - "5f6b5bcc59698fbbe2d8ff7b3dd1b7c841cf4b1a8cec88e05c02bc97d12ad52b"); - }); }); group('blake2b512 test', () { diff --git a/test/blake2s_test.dart b/test/blake2s_test.dart index f5e5837..ac833ee 100644 --- a/test/blake2s_test.dart +++ b/test/blake2s_test.dart @@ -6,6 +6,36 @@ import 'package:hashlib/hashlib.dart'; import 'package:test/test.dart'; void main() { + group('Blake2sHash functionality test', () { + test('The digest size must be between 1 and 32', () { + Blake2sHash(1); + Blake2sHash(32); + expect(() => Blake2sHash(0), throwsArgumentError); + expect(() => Blake2sHash(33), throwsArgumentError); + expect(() => Blake2sHash(64), throwsArgumentError); + }); + test('The valid length of salt is 8 bytes ', () { + Blake2sHash(16, salt: Uint8List(0)); + Blake2sHash(16, salt: Uint8List(8)); + expect(() => Blake2sHash(16, salt: Uint8List(1)), throwsArgumentError); + expect(() => Blake2sHash(16, salt: Uint8List(9)), throwsArgumentError); + expect(() => Blake2sHash(16, salt: Uint8List(16)), throwsArgumentError); + }); + test('The valid length of personalization is 8 bytes ', () { + Blake2sHash(16, aad: Uint8List(0)); + Blake2sHash(16, aad: Uint8List(8)); + expect(() => Blake2sHash(16, aad: Uint8List(1)), throwsArgumentError); + expect(() => Blake2sHash(16, aad: Uint8List(9)), throwsArgumentError); + expect(() => Blake2sHash(16, aad: Uint8List(16)), throwsArgumentError); + }); + test('The key should not be greater than 32 bytes ', () { + Blake2sHash(16, key: Uint8List(0)); + Blake2sHash(16, key: Uint8List(1)); + Blake2sHash(16, key: Uint8List(32)); + expect(() => Blake2sHash(16, key: Uint8List(33)), throwsArgumentError); + expect(() => Blake2sHash(16, key: Uint8List(64)), throwsArgumentError); + }); + }); group('Blake2s funtionality test', () { test("Blake2s name", () { expect(Blake2s(8).name, 'BLAKE2s-64'); @@ -25,49 +55,6 @@ void main() { expect(blake2s224.mac.by(key).name, 'BLAKE2s-224/MAC'); expect(blake2s256.mac.by(key).name, 'BLAKE2s-256/MAC'); }); - test('The digest size must be between 1 and 32', () { - Blake2s(1).createSink(); - Blake2s(32).createSink(); - expect(() => Blake2s(0).createSink(), throwsArgumentError); - expect(() => Blake2s(33).createSink(), throwsArgumentError); - }); - test('The valid length of salt is 8 bytes ', () { - Blake2s(16, salt: Uint8List(0)).createSink(); - Blake2s(16, salt: Uint8List(8)).createSink(); - expect( - () => Blake2s(16, salt: Uint8List(1)).createSink(), - throwsArgumentError, - ); - expect( - () => Blake2s(16, salt: Uint8List(9)).createSink(), - throwsArgumentError, - ); - }); - test('The valid length of personalization is 8 bytes ', () { - Blake2s(16, personalization: Uint8List(0)).createSink(); - Blake2s(16, personalization: Uint8List(8)).createSink(); - expect( - () => Blake2s(16, personalization: Uint8List(1)).createSink(), - throwsArgumentError, - ); - expect( - () => Blake2s(16, personalization: Uint8List(9)).createSink(), - throwsArgumentError, - ); - }); - test('The key should not be greater than 32 bytes ', () { - Blake2s(16).mac.by(Uint8List(0)).createSink(); - Blake2s(16).mac.by(Uint8List(1)).createSink(); - Blake2s(16).mac.by(Uint8List(32)).createSink(); - expect( - () => Blake2s(16).mac.by(Uint8List(33)).createSink(), - throwsArgumentError, - ); - expect( - () => Blake2s(16).mac.by(Uint8List(64)).createSink(), - throwsArgumentError, - ); - }); test('sink test', () { final input = List.generate(512, (i) => i & 0xFF); final output = @@ -135,15 +122,6 @@ void main() { expect(blake2s256.mac.byString('secret').string('').hex(), "864f60ce88fc1c80c7b3b4f0bb920255fb464484a9dc7346f1d0e4e190d358cd"); }); - test('Blake2s config without any parameters', () { - expect(blake2s256.config().string('a').hex(), - "4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90"); - }); - test('Blake2s config with a salt', () { - final salt = 'somesalt'.codeUnits; - expect(blake2s256.config(salt: salt).string('a').hex(), - "01dc5d55926ffeeedf384a3fa709f6be647decd99e85a9695ef2aac8b6d4ffc8"); - }); }); group('blake2s128 test', () { diff --git a/test/compare_test.dart b/test/compare_test.dart index 1963604..d6bd20c 100644 --- a/test/compare_test.dart +++ b/test/compare_test.dart @@ -47,7 +47,7 @@ void main() { final salt = randomBytes(16); for (int i = 0; i < 100; ++i) { final data = randomBytes(i); - final out1 = blake2b512.config(salt: salt).convert(data).hex(); + final out1 = Blake2b(64, salt: salt).convert(data).hex(); final out2 = toHex( pc_blake2b.Blake2bDigest(digestSize: 64, salt: salt).process(data), ); @@ -61,7 +61,7 @@ void main() { final data = randomBytes(i); final out1 = Blake2b( 64, - personalization: personalization, + aad: personalization, ).convert(data).hex(); final out2 = toHex( pc_blake2b.Blake2bDigest( @@ -81,7 +81,7 @@ void main() { final out1 = Blake2b( 64, salt: salt, - personalization: personalization, + aad: personalization, ).convert(data).hex(); final out2 = toHex( pc_blake2b.Blake2bDigest( @@ -97,20 +97,16 @@ void main() { test('with pointycastle with key, salt and personalization', () { final key = randomBytes(16); final salt = randomBytes(16); - final personalization = randomBytes(16); + final aad = randomBytes(16); for (int i = 0; i < 100; ++i) { final data = randomBytes(i); - final out1 = Blake2b( - 64, - salt: salt, - personalization: personalization, - ).mac.by(key).convert(data).hex(); + final out1 = Blake2b(64).mac.by(key, salt: salt, aad: aad).hex(data); final out2 = toHex( pc_blake2b.Blake2bDigest( digestSize: 64, key: key, salt: salt, - personalization: personalization, + personalization: aad, ).process(data), ); expect(out1, equals(out2), reason: 'size: $i'); diff --git a/test/core/mac_base_test.dart b/test/core/mac_base_test.dart index c245f29..9d603da 100644 --- a/test/core/mac_base_test.dart +++ b/test/core/mac_base_test.dart @@ -54,7 +54,7 @@ void main() { group('MACHashBase', () { test('by create a MACHash', () { - expect(sha1.hmac.by([2]), isA()); + expect(sha1.hmac.by([2]), isA()); }); test('sign should return a HashDigest', () {