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' ;
@@ -130,7 +147,14 @@ class StorageCryptoHandler {
130147 final salt = _randomBytes (saltLength);
131148
132149 // Use the passphrase and salt to derive the main key with the PBKDF
133- final mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
150+ Uint8List mainKey = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
151+ if (version == 1 || version == 2 ) {
152+ mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
153+ } else if (version == 3 ) {
154+ mainKey = await _argon2id (salt, _stringToBytes (passphrase), version);
155+ } else {
156+ throw VersionError ();
157+ }
134158
135159 // Generate a random data key
136160 final dataKey = _randomBytes (Xchacha20 .poly1305Aead ().secretKeyLength);
@@ -151,7 +175,14 @@ class StorageCryptoHandler {
151175 Uint8List encryptedDataKey = keyBlobBytes.sublist (saltLength);
152176
153177 // Derive the candidate main key
154- final Uint8List mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
178+ Uint8List mainKey = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
179+ if (version == 1 || version == 2 ) {
180+ mainKey = await _pbkdf2 (salt, _stringToBytes (passphrase), version);
181+ } else if (version == 3 ) {
182+ mainKey = await _argon2id (salt, _stringToBytes (passphrase), version);
183+ } else {
184+ throw VersionError ();
185+ }
155186
156187 // Determine if the main key is valid against the encrypted data key
157188 try {
@@ -183,7 +214,13 @@ class StorageCryptoHandler {
183214 _salt = _randomBytes (saltLength);
184215
185216 // Use the passphrase and salt to derive the main key with the PBKDF
186- _mainKey = await _pbkdf2 (_salt, _stringToBytes (passphrase), version);
217+ if (version == 1 || version == 2 ) {
218+ _mainKey = await _pbkdf2 (_salt, _stringToBytes (passphrase), version);
219+ } else if (version == 3 ) {
220+ _mainKey = await _argon2id (_salt, _stringToBytes (passphrase), version);
221+ } else {
222+ throw VersionError ();
223+ }
187224 }
188225
189226 /// Get the key blob, which is safe to store
@@ -357,6 +394,25 @@ Future<Uint8List> _pbkdf2(Uint8List salt, Uint8List passphrase, int version) asy
357394 return Uint8List .fromList (mainKeyBytes);
358395}
359396
397+ /// Argon2id
398+ Future <Uint8List > _argon2id (Uint8List salt, Uint8List passphrase, int version) async {
399+ final parameters = Argon2Parameters (
400+ Argon2Parameters .ARGON2_id ,
401+ salt,
402+ version: Argon2Parameters .ARGON2_VERSION_13 ,
403+ iterations: 1 ,
404+ lanes: 1 ,
405+ memory: getArgon2Memory (version),
406+ );
407+ final Argon2BytesGenerator argon2 = Argon2BytesGenerator ();
408+ argon2.init (parameters);
409+
410+ var derivedKeyBytes = Uint8List (Xchacha20 .poly1305Aead ().secretKeyLength);
411+ argon2.generateBytes (passphrase, derivedKeyBytes);
412+
413+ return derivedKeyBytes;
414+ }
415+
360416/// XChaCha20-Poly1305 encryption
361417Future <SecretBox > _xChaCha20Poly1305Encrypt (Uint8List key, Uint8List nonce, Uint8List data, Uint8List aad) async {
362418 final Xchacha20 aead = Xchacha20 .poly1305Aead ();
0 commit comments