Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes Blake2b/Blake2s issues. #160

Merged
merged 1 commit into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cryptography/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 2.6.0
* Improves Blake2b/Blake2s support:
* Adds support for using as a MAC algorithm
* Adds support for custom output lengths
* Improves test coverage
* Fixes bugs
* Removes long-deprecated `newSink()` methods in `HashAlgorithm` and `MacAlgorithm` (so Blake2
classes can implement both interfaces).
* Raises Dart SDK minimum to 3.1.0 and other small changes related to dependency constraints.
* Improves documentation.

## 2.5.0
* Adds enough DER encoding/decoding support for us to use Apple's CryptoKit ECDH/ECDSA functions.
* Improves BrowserHmac/etc. parameter checks.
Expand Down
2 changes: 2 additions & 0 deletions cryptography/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ The following implementations are available:
The following [MacAlgorithm](https://pub.dev/documentation/cryptography/latest/cryptography/MacAlgorithm-class.html)
implementations are available:

* [Blake2b](https://pub.dev/documentation/cryptography/latest/cryptography/Blake2b-class.html)
* [Blake2s](https://pub.dev/documentation/cryptography/latest/cryptography/Blake2s-class.html)
* [Hmac](https://pub.dev/documentation/cryptography/latest/cryptography/Hmac-class.html)
* [Poly1305](https://pub.dev/documentation/cryptography/latest/cryptography/Poly1305-class.html)

Expand Down
2 changes: 1 addition & 1 deletion cryptography/lib/src/browser/browser_cryptography.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import 'hkdf.dart';
import 'hmac.dart';
import 'pbkdf2.dart';

class BrowserCryptography extends DartCryptography {
base class BrowserCryptography extends DartCryptography {
// Documented in browser_cryptography_when_not_browser.dart
static final Cryptography defaultInstance =
isSupported ? BrowserCryptography() : DartCryptography();
Expand Down
148 changes: 126 additions & 22 deletions cryptography/lib/src/cryptography/algorithms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -548,11 +548,20 @@ abstract class Argon2id extends KdfAlgorithm {
')';
}

/// _BLAKE2B_ ([RFC 7693](https://tools.ietf.org/html/rfc7693)) [HashAlgorithm].
/// _BLAKE2B_ ([RFC 7693](https://tools.ietf.org/html/rfc7693)), which can be
/// used both as [HashAlgorithm] and [MacAlgorithm].
///
/// By default, [DartBlake2b] will be used.
///
/// ## Asynchronous usage
/// ## Things to know
/// * The default [hashLengthInBytes] / [macLength] is 64 bytes. You can
/// choose a shorter hash length when you call the constructor. You should
/// NOT truncate the hash yourself.
/// * The algorithm was designed to be used directly as [MacAlgorithm] (no
/// [Hmac] needed). Maximum secret key size is 64 bytes.
/// * Blake2 hash/MAC function family includes also [Blake2s].
///
/// ## Example: Hashing a byte list
/// ```
/// import 'package:cryptography/cryptography.dart';
///
Expand All @@ -566,7 +575,7 @@ abstract class Argon2id extends KdfAlgorithm {
///
/// If you need synchronous computations, use [DartBlake2b].
///
/// ## Streaming usage
/// ## Example: Hashing a sequence of chunks
/// ```
/// import 'package:cryptography/cryptography.dart';
///
Expand All @@ -587,14 +596,47 @@ abstract class Argon2id extends KdfAlgorithm {
/// print('Hash: ${hash.bytes}');
/// }
/// ```
abstract class Blake2b extends HashAlgorithm {
factory Blake2b() {
return Cryptography.instance.blake2b();
abstract class Blake2b extends HashAlgorithm implements MacAlgorithm {
/// Default value of [hashLengthInBytes] and [macLength].
static const int defaultHashLengthInBytes = 64;

factory Blake2b({
int hashLengthInBytes = defaultHashLengthInBytes,
}) {
if (hashLengthInBytes < 1 || hashLengthInBytes > defaultHashLengthInBytes) {
throw ArgumentError.value(hashLengthInBytes);
}
return Cryptography.instance.blake2b(
hashLengthInBytes: hashLengthInBytes,
);
}

/// Constructor for classes that extend this class.
/// Constructor for subclasses.
const Blake2b.constructor({
this.hashLengthInBytes = defaultHashLengthInBytes,
}) : assert(hashLengthInBytes > 0),
assert(hashLengthInBytes <= defaultHashLengthInBytes);

const Blake2b.constructor();
@override
void checkParameters({
int? length,
required SecretKey secretKey,
required int nonceLength,
required int aadLength,
required int keyStreamIndex,
}) {}

@override
int get keyStreamUsed => 0;

@override
int get macLength => hashLengthInBytes;

@override
bool get supportsAad => false;

@override
bool get supportsKeyStreamIndex => false;

@override
int get blockLengthInBytes => 64;
Expand All @@ -603,20 +645,39 @@ abstract class Blake2b extends HashAlgorithm {
int get hashCode => (Blake2b).hashCode;

@override
int get hashLengthInBytes => 64;
final int hashLengthInBytes;

@override
bool operator ==(other) => other is Blake2b;

@override
DartHashAlgorithm toSync() => const DartBlake2b();
DartBlake2b toSync() => DartBlake2b(
hashLengthInBytes: hashLengthInBytes,
);

@override
String toString() {
if (hashLengthInBytes == defaultHashLengthInBytes) {
return 'Blake2b()';
}
return 'Blake2b(hashLengthInBytes: $hashLengthInBytes)';
}
}

/// _BLAKE2S_ ([RFC 7693](https://tools.ietf.org/html/rfc7693)) [HashAlgorithm].
/// _BLAKE2S_ ([RFC 7693](https://tools.ietf.org/html/rfc7693)), which can be
/// used both as [HashAlgorithm] and [MacAlgorithm].
///
/// By default, [DartBlake2s], our pure Dart implementation, will be used.
/// By default, [DartBlake2s] will be used.
///
/// ## Asynchronous usage
/// ## Things to know
/// * The default [hashLengthInBytes] / [macLength] is 32 bytes. You can
/// choose a shorter hash length when you call the constructor. You should
/// NOT truncate the hash yourself.
/// * The algorithm was designed to be used directly as [MacAlgorithm] (no
/// [Hmac] needed). Maximum secret key size is 32 bytes.
/// * Blake2 hash/MAC function family includes also [Blake2b].
///
/// ## Example: Hashing a byte list
/// ```dart
/// import 'package:cryptography/cryptography.dart';
///
Expand All @@ -628,7 +689,7 @@ abstract class Blake2b extends HashAlgorithm {
/// }
/// ```
///
/// ## Streaming usage
/// ## Example: Hashing a sequence of chunks
/// ```dart
/// import 'package:cryptography/cryptography.dart';
///
Expand All @@ -650,14 +711,26 @@ abstract class Blake2b extends HashAlgorithm {
/// }
/// ```
///
abstract class Blake2s extends HashAlgorithm {
factory Blake2s() {
return Cryptography.instance.blake2s();
}
abstract class Blake2s extends HashAlgorithm implements MacAlgorithm {
/// Default value of [hashLengthInBytes] and [macLength].
static const int defaultHashLengthInBytes = 32;

/// Constructor for classes that extend this class.
factory Blake2s({
int hashLengthInBytes = defaultHashLengthInBytes,
}) {
if (hashLengthInBytes < 1 || hashLengthInBytes > defaultHashLengthInBytes) {
throw ArgumentError.value(hashLengthInBytes);
}
return Cryptography.instance.blake2s(
hashLengthInBytes: hashLengthInBytes,
);
}

const Blake2s.constructor();
/// Constructor for subclasses.
const Blake2s.constructor({
this.hashLengthInBytes = defaultHashLengthInBytes,
}) : assert(hashLengthInBytes > 0),
assert(hashLengthInBytes <= defaultHashLengthInBytes);

@override
int get blockLengthInBytes => 32;
Expand All @@ -666,13 +739,44 @@ abstract class Blake2s extends HashAlgorithm {
int get hashCode => (Blake2s).hashCode;

@override
int get hashLengthInBytes => 32;
final int hashLengthInBytes;

@override
void checkParameters({
int? length,
required SecretKey secretKey,
required int nonceLength,
required int aadLength,
required int keyStreamIndex,
}) {}

@override
int get keyStreamUsed => 0;

@override
int get macLength => hashLengthInBytes;

@override
bool get supportsAad => false;

@override
bool get supportsKeyStreamIndex => false;

@override
bool operator ==(other) => other is Blake2s;

@override
DartHashAlgorithm toSync() => const DartBlake2s();
String toString() {
if (hashLengthInBytes == defaultHashLengthInBytes) {
return 'Blake2s()';
}
return 'Blake2s(hashLengthInBytes: $hashLengthInBytes)';
}

@override
DartBlake2s toSync() => DartBlake2s(
hashLengthInBytes: hashLengthInBytes,
);
}

/// _ChaCha20_ ([RFC 7539](https://tools.ietf.org/html/rfc7539))
Expand Down
14 changes: 8 additions & 6 deletions cryptography/lib/src/cryptography/cipher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import '../../dart.dart';
/// print('MAC: ${secretBox.mac.bytes}')
///
/// // Decrypt
/// final clearText = await algorithm.encrypt(
/// final clearText = await algorithm.decrypt(
/// secretBox,
/// secretKey: secretKey,
/// );
Expand Down Expand Up @@ -443,8 +443,9 @@ abstract class Cipher {
/// It will have the correct length ([nonceLength]).
///
/// The source of random bytes is [Random.secure] (a cryptographically secure
/// random number generator) unless specified another random number generator
/// when you constructed the cipher (or your [Cryptography]).
/// random number generator) unless a custom random number generator was
/// specified when you constructed the cipher (or your [Cryptography]
/// instance).
List<int> newNonce() {
final bytes = Uint8List(nonceLength);
fillBytesWithSecureRandom(
Expand All @@ -459,8 +460,9 @@ abstract class Cipher {
/// It will have the correct length ([secretKeyLength]).
///
/// The source of random bytes is [Random.secure] (a cryptographically secure
/// random number generator) unless specified another random number generator
/// when you constructed the cipher (or your [Cryptography]).
/// random number generator) unless a custom random number generator was
/// specified when you constructed the cipher (or your [Cryptography]
/// instance).
Future<SecretKey> newSecretKey() async {
return SecretKeyData.random(
length: secretKeyLength,
Expand Down Expand Up @@ -497,7 +499,7 @@ abstract class Cipher {
/// import 'package:cryptography/cryptography.dart';
///
/// void main() {
/// final cipher = Chacha20.poly1305().toSync();
/// final cipher = Chacha20.poly1305Aead().toSync();
/// final secretKey = cipher.newSecretKeySync();
/// final secretBox = cipher.encryptSync(
/// [1,2,3],
Expand Down
4 changes: 2 additions & 2 deletions cryptography/lib/src/cryptography/cryptography.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ abstract class Cryptography {
});

/// A factory used by [Blake2b].
Blake2b blake2b();
Blake2b blake2b({int hashLengthInBytes = 64});

/// A factory used by [Blake2s].
Blake2s blake2s();
Blake2s blake2s({int hashLengthInBytes = 32});

/// A factory used by [Chacha20].
Chacha20 chacha20({required MacAlgorithm macAlgorithm});
Expand Down
6 changes: 0 additions & 6 deletions cryptography/lib/src/cryptography/hash_algorithm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import 'dart:typed_data';

import 'package:cryptography/cryptography.dart';
import 'package:cryptography/dart.dart';
import 'package:meta/meta.dart';

/// A hash algorithm that produces a [Hash].
///
Expand Down Expand Up @@ -105,11 +104,6 @@ abstract class HashAlgorithm {
/// ```
HashSink newHashSink() => _HashSink(this);

/// {@nodoc}
@nonVirtual
@Deprecated('Use newHashSink() instead')
HashSink newSink() => newHashSink();

@override
String toString() => '$runtimeType()';

Expand Down
18 changes: 3 additions & 15 deletions cryptography/lib/src/cryptography/mac_algorithm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import 'package:cryptography/dart.dart';
/// You can compute a [Mac] by calling [calculateMac] or [newMacSink].
///
/// ## Available algorithms
/// * [Hmac]
/// * [Blake2b]
/// * [Blake2s]
/// * [Hmac] (with any hash algorithm)
/// * [Poly1305]
///
/// ## Not using MAC?
Expand Down Expand Up @@ -143,20 +145,6 @@ abstract class MacAlgorithm {
);
}

/// {@nodoc}
@Deprecated('Use newMacSink()')
Future<MacSink> newSink({
required SecretKey secretKey,
List<int> nonce = const <int>[],
List<int> aad = const <int>[],
}) {
return newMacSink(
secretKey: secretKey,
nonce: nonce,
aad: aad,
);
}

@override
String toString() => '$runtimeType()';

Expand Down
31 changes: 28 additions & 3 deletions cryptography/lib/src/dart/blake2b.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,36 @@ import 'blake2b_impl_vm.dart'
///
/// For examples and more information about the algorithm, see documentation for
/// the class [Blake2b].
class DartBlake2b extends Blake2b with DartHashAlgorithmMixin {
const DartBlake2b() : super.constructor();
class DartBlake2b extends Blake2b
with DartHashAlgorithmMixin, DartMacAlgorithmMixin {
const DartBlake2b({
super.hashLengthInBytes = Blake2b.defaultHashLengthInBytes,
}) : super.constructor();

@override
DartBlake2b toSync() {
return this;
}

@override
DartMacSinkMixin newMacSinkSync({
required SecretKeyData secretKeyData,
List<int> nonce = const <int>[],
List<int> aad = const <int>[],
}) {
return Blake2bSink(
hashLengthInBytes: hashLengthInBytes,
)..initializeSync(
secretKey: secretKeyData,
nonce: nonce,
aad: aad,
);
}

@override
DartHashSink newHashSink() {
return Blake2bSink();
return Blake2bSink(
hashLengthInBytes: hashLengthInBytes,
);
}
}
Loading