6363import 'dart:convert' ;
6464import 'dart:math' ;
6565import 'dart:typed_data' ;
66+ import 'package:argon2/argon2.dart' ;
6667import 'package:cryptography/cryptography.dart' ;
6768
69+ /// Return a list of all known versions
70+ List <int > getVersions () {
71+ return [1 , 2 , 3 ];
72+ }
73+
6874/// Get the PBKDF iterations for this version
6975/// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
7076int getPbkdfIterations (int version) {
@@ -78,6 +84,17 @@ int getPbkdfIterations(int version) {
7884 }
7985}
8086
87+ /// Get the Argon2id memory parameter for this version
88+ /// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id
89+ int getArgon2Memory (int version) {
90+ switch (version) {
91+ case 3 :
92+ return 47104 ;
93+ default :
94+ throw VersionError ();
95+ }
96+ }
97+
8198/// Constants that should not be changed without good reason
8299const int saltLength = 16 ; // in bytes
83100const String dataKeyDomain = 'STACK_WALLET_DATA_KEY' ;
@@ -135,7 +152,14 @@ class StorageCryptoHandler {
135152 final salt = _randomBytes (saltLength);
136153
137154 // Use the passphrase and salt to derive the main key with the PBKDF
138- final mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
155+ Uint8List mainKey = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
156+ if (version == 1 || version == 2 ) {
157+ mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
158+ } else if (version == 3 ) {
159+ mainKey = await _argon2id (salt, _stringToBytes (passphrase), version);
160+ } else {
161+ throw VersionError ();
162+ }
139163
140164 // Generate a random data key
141165 final dataKey = _randomBytes (Xchacha20 .poly1305Aead ().secretKeyLength);
@@ -156,7 +180,14 @@ class StorageCryptoHandler {
156180 Uint8List encryptedDataKey = keyBlobBytes.sublist (saltLength);
157181
158182 // Derive the candidate main key
159- final Uint8List mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
183+ Uint8List mainKey = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
184+ if (version == 1 || version == 2 ) {
185+ mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
186+ } else if (version == 3 ) {
187+ mainKey = await _argon2id (salt, _stringToBytes (passphrase), version);
188+ } else {
189+ throw VersionError ();
190+ }
160191
161192 // Determine if the main key is valid against the encrypted data key
162193 try {
@@ -188,7 +219,13 @@ class StorageCryptoHandler {
188219 _salt = _randomBytes (saltLength);
189220
190221 // Use the passphrase and salt to derive the main key with the PBKDF
191- _mainKey = await _pbkdf2 (_salt, _stringToBytes (passphrase), version);
222+ if (version == 1 || version == 2 ) {
223+ _mainKey = await _pbkdf2 (_salt, _stringToBytes (passphrase), version);
224+ } else if (version == 3 ) {
225+ _mainKey = await _argon2id (_salt, _stringToBytes (passphrase), version);
226+ } else {
227+ throw VersionError ();
228+ }
192229 }
193230
194231 /// Get the key blob, which is safe to store
@@ -362,6 +399,25 @@ Future<Uint8List> _pbkdf2(Uint8List salt, Uint8List passphrase, int version) asy
362399 return Uint8List .fromList (mainKeyBytes);
363400}
364401
402+ /// Argon2id
403+ Future <Uint8List > _argon2id (Uint8List salt, Uint8List passphrase, int version) async {
404+ final parameters = Argon2Parameters (
405+ Argon2Parameters .ARGON2_id ,
406+ salt,
407+ version: Argon2Parameters .ARGON2_VERSION_13 ,
408+ iterations: 1 ,
409+ lanes: 1 ,
410+ memory: getArgon2Memory (version),
411+ );
412+ final Argon2BytesGenerator argon2 = Argon2BytesGenerator ();
413+ argon2.init (parameters);
414+
415+ var derivedKeyBytes = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
416+ argon2.generateBytes (passphrase, derivedKeyBytes);
417+
418+ return derivedKeyBytes;
419+ }
420+
365421/// XChaCha20-Poly1305 encryption
366422Future <SecretBox > _xChaCha20Poly1305Encrypt (Uint8List key, Uint8List nonce, Uint8List data, Uint8List aad) async {
367423 final Xchacha20 aead = Xchacha20 .poly1305Aead ();
0 commit comments