Skip to content

Commit cfdd5b1

Browse files
authored
Merge pull request #163 from terrier989/master
Adds Argon2id implementation.
2 parents 5912a11 + 42259eb commit cfdd5b1

File tree

22 files changed

+2428
-173
lines changed

22 files changed

+2428
-173
lines changed

cryptography/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 2.7.0
2+
* Adds a cross-platform of Argon2id, a highly recommended algorithm for password hashing.
3+
* Introduces a dependency on "package:ffi" (a package by Google). A memory allocator in the package
4+
is used when the Argon2 implementation distributes computation to multiple isolates.
5+
* Small backwards-compatible changes in Blake2b and DartBlake2b API.
6+
17
## 2.6.1
28
* Fixes incorrect base class constraints.
39

cryptography/README.md

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ Android / iOS / Mac OS X operating system APIs whenever possible.
3333
In _pubspec.yaml_:
3434
```yaml
3535
dependencies:
36-
cryptography: ^2.6.1
37-
cryptography_flutter: ^2.3.1 # Remove if you don't use Flutter
36+
cryptography: ^2.7.0
37+
cryptography_flutter: ^2.3.2 # Remove if you don't use Flutter
3838
```
3939
4040
You are ready to go!
@@ -163,14 +163,15 @@ implementations are available:
163163
curve25519 Diffie-Hellman)
164164
* Throughput of the pure Dart implementation is around 1000 key agreements per second (in VM).
165165
166-
### Key derivation algorithms
166+
### Key derivation / password hashing algorithms
167167
168-
The following implementations are available:
168+
The following [KdfAlgorithm](https://pub.dev/documentation/cryptography/latest/cryptography/KdfAlgorithm-class.html) implementations are available:
169169
170-
* [Hchacha20](https://pub.dev/documentation/cryptography/latest/cryptography/Hchacha20-clas.html)
171-
* [Hkdf](https://pub.dev/documentation/cryptography/latest/cryptography/Hkdf-class.html) (HKDF)
172-
* [Pbkdf2](https://pub.dev/documentation/cryptography/latest/cryptography/Pbkdf2-class.html) (
173-
PBKDF2)
170+
* [Hchacha20](https://pub.dev/documentation/cryptography/latest/cryptography/Hchacha20-class.html)
171+
* [Hkdf](https://pub.dev/documentation/cryptography/latest/cryptography/Hkdf-class.html)
172+
* [Pbkdf2](https://pub.dev/documentation/cryptography/latest/cryptography/Pbkdf2-class.html)
173+
* [Argon2id](https://pub.dev/documentation/cryptography/latest/cryptography/Argon2id-class.html)
174+
* Argon2id is the recommended algorithm for password hashing.
174175
175176
## Message authentication codes
176177
@@ -392,6 +393,29 @@ Future<void> main() async {
392393
}
393394
```
394395

396+
## Password hashing
397+
In this example, we use [Argon2id](https://pub.dev/documentation/cryptography/latest/cryptography/Argon2id-class.html):
398+
```dart
399+
import 'package:cryptography/cryptography.dart';
400+
401+
Future<void> main() async {
402+
final algorithm = Argon2id(
403+
memory: 10*1000, // 10 MB
404+
parallelism: 2, // Use maximum two CPU cores.
405+
iterations: 1, // For more security, you should usually raise memory parameter, not iterations.
406+
hashLength: 32, // Number of bytes in the returned hash
407+
);
408+
409+
final secretKey = await algorithm.deriveKeyFromPassword(
410+
password: 'qwerty',
411+
nonce: [1, 2, 3],
412+
);
413+
final secretKeyBytes = await secretKey.extractBytes();
414+
415+
print('Hash: ${secretKeyBytes}');
416+
}
417+
```
418+
395419
## Hashing
396420
In this example, we use [Sha256](https://pub.dev/documentation/cryptography/latest/cryptography/Sha256-class.html):
397421
```dart

cryptography/lib/src/cryptography/algorithms.dart

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -440,23 +440,46 @@ abstract class AesGcm extends Cipher {
440440
}
441441
}
442442

443-
/// _Argon2id_ ([draft-irtf-cfrg-argon2-03](https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03))
444-
/// password hashing function.
443+
/// _Argon2id_ ([RFC 9106](https://datatracker.ietf.org/doc/rfc9106/))
444+
/// memory-hard password hashing function.
445445
///
446-
/// _Argon2_ is known for winning _Password Hashing Competition_ 2015. The
447-
/// algorithm can provide much better security than older algorithms such as
448-
/// [Pbkdf2].
446+
/// _Argon2_ is known for winning _Password Hashing Competition_ 2015. OWASP
447+
/// [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
448+
/// describes it as first choice for password hashing.
449449
///
450-
/// By default, [DartArgon2id], our pure Dart implementation, will be used.
450+
/// The default implementation is [DartArgon2id], our pure Dart implementation.
451+
///
452+
/// ## Things to know
453+
/// * You need to choose:
454+
/// * [memory]
455+
/// * Number of 1kB blocks of memory needed to compute the hash.
456+
/// * Higher is better for security. You should experiment what is good
457+
/// for your system. We recommend to start from 1000 (= 1 MB) and go
458+
/// as high as you can.
459+
/// * [parallelism]
460+
/// * Maximum number of parallel computations.
461+
/// * You should choose a small number such as 1 or 4.
462+
/// * [iterations]
463+
/// * Number of iterations. Higher is better for security, but usually
464+
/// you should use value `1` because it makes more sense (from security
465+
/// point of view) to raise [memory] parameter instead.
466+
/// * [hashLength]
467+
/// * The value should be at least 16 bytes. More than 32 bytes is
468+
/// unnecessary from security point of view.
469+
/// * OWASP [suggests](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
470+
/// the following parameter values:
471+
/// * memory = 19 MiB of memory
472+
/// * parallelism = 1
473+
/// * iterations = 2
451474
///
452475
/// ## Example
453476
/// ```
454477
/// import 'package:cryptography/cryptography.dart';
455478
///
456479
/// Future<void> main() async {
457480
/// final algorithm = Argon2id(
458-
/// parallelism: 3,
459-
/// memorySize: 10000000,
481+
/// parallelism: 4,
482+
/// memory: 10000, // 10 000 x 1kB block = 10 MB
460483
/// iterations: 3,
461484
/// hashLength: 32,
462485
/// );
@@ -479,13 +502,13 @@ abstract class AesGcm extends Cipher {
479502
abstract class Argon2id extends KdfAlgorithm {
480503
factory Argon2id({
481504
required int parallelism,
482-
required int memorySize,
505+
required int memory,
483506
required int iterations,
484507
required int hashLength,
485508
}) {
486509
return Cryptography.instance.argon2id(
487510
parallelism: parallelism,
488-
memorySize: memorySize,
511+
memory: memory,
489512
iterations: iterations,
490513
hashLength: hashLength,
491514
);
@@ -495,31 +518,30 @@ abstract class Argon2id extends KdfAlgorithm {
495518
const Argon2id.constructor();
496519

497520
@override
498-
int get hashCode => parallelism ^ memorySize ^ iterations ^ hashLength;
521+
int get hashCode => parallelism ^ memory ^ iterations ^ hashLength;
499522

500523
/// Hash length.
501524
int get hashLength;
502525

503526
/// Number of iterations.
504527
int get iterations;
505528

506-
/// Minimum number of bytes attacker needs to store in memory for each
507-
/// attempt.
508-
int get memorySize;
529+
/// Minimum number of 1 kB blocks needed to compute the hash.
530+
int get memory;
509531

510532
/// Maximum number of processors attacker can use concurrently for each
511533
/// attempt.
512534
int get parallelism;
513535

514536
/// Argon2id algorithm version number.
515537
@nonVirtual
516-
int get version => 0x13;
538+
int get version => 19;
517539

518540
@override
519541
bool operator ==(other) =>
520542
other is Argon2id &&
521543
parallelism == other.parallelism &&
522-
memorySize == other.memorySize &&
544+
memory == other.memory &&
523545
iterations == other.iterations &&
524546
hashLength == other.hashLength;
525547

@@ -535,14 +557,14 @@ abstract class Argon2id extends KdfAlgorithm {
535557
Future<SecretKey> deriveKey({
536558
required SecretKey secretKey,
537559
required List<int> nonce,
538-
List<int> k = const <int>[],
539-
List<int> ad = const <int>[],
560+
List<int> optionalSecret = const <int>[],
561+
List<int> associatedData = const <int>[],
540562
});
541563

542564
@override
543-
String toString() => 'Argon2id(\n'
565+
String toString() => '$runtimeType(\n'
544566
' parallelism: $parallelism,\n'
545-
' memorySize: $memorySize,\n'
567+
' memory: $memory,\n'
546568
' iterations: $iterations,\n'
547569
' hashLength: $hashLength,\n'
548570
')';
@@ -617,6 +639,19 @@ abstract class Blake2b extends HashAlgorithm implements MacAlgorithm {
617639
}) : assert(hashLengthInBytes > 0),
618640
assert(hashLengthInBytes <= defaultHashLengthInBytes);
619641

642+
/// Enables you to replace [hashLengthInBytes].
643+
///
644+
/// Subclasses should replace this with their own implementation.
645+
Blake2b replace({int? hashLength}) {
646+
hashLength ??= hashLengthInBytes;
647+
if (hashLength == hashLengthInBytes) {
648+
return this;
649+
}
650+
return Blake2b(
651+
hashLengthInBytes: hashLength,
652+
);
653+
}
654+
620655
@override
621656
void checkParameters({
622657
int? length,

cryptography/lib/src/cryptography/cryptography.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ abstract class Cryptography {
108108

109109
/// A factory used by [Argon2id].
110110
Argon2id argon2id({
111+
required int memory,
111112
required int parallelism,
112-
required int memorySize,
113113
required int iterations,
114114
required int hashLength,
115115
});

cryptography/lib/src/cryptography/kdf_algorithm.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import 'package:cryptography/cryptography.dart';
1919
/// Abstract superclass for Key Derivation Algorithms (KDFs).
2020
///
2121
/// ## Available algorithms
22-
/// * [Argon2id] (suitable for password hashing)
22+
/// * [Argon2id] (recommended for password hashing)
2323
/// * [Hchacha20]
2424
/// * [Hkdf]
25-
/// * [Pbkdf2] (suitable for password hashing)
25+
/// * [Pbkdf2]
2626
abstract class KdfAlgorithm {
2727
const KdfAlgorithm();
2828

0 commit comments

Comments
 (0)