diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index c072bf65e..12ce72e7b 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -39,13 +39,13 @@ class AuthService with Store { Future setPassword(String password) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); - final encodedPassword = encodedPinCode(pin: password); + final hashedPassword = await argon2Hash(password: password); // secure storage has a weird bug on macOS, where overwriting a key doesn't work, unless // we delete what's there first: if (Platform.isMacOS) { await secureStorage.delete(key: key); } - await secureStorage.write(key: key, value: encodedPassword); + await secureStorage.write(key: key, value: hashedPassword); } Future canAuthenticate() async { @@ -64,10 +64,8 @@ class AuthService with Store { Future authenticate(String pin) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); - final encodedPin = await secureStorage.read(key: key); - final decodedPin = decodedPinCode(pin: encodedPin!); - - return decodedPin == pin; + final hashedPassword = await secureStorage.read(key: key); + return verifyArgon2Hash(password: pin, hash: hashedPassword!); } void saveLastAuthTime() { diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index 7dd0b50f3..ebe4a2613 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -445,7 +445,7 @@ class BackupService { }); await _flutterSecureStorage.delete(key: pinCodeKey); - await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); + await _flutterSecureStorage.write(key: pinCodeKey, value: (await argon2Hash(password: decodedPin))); keychainDumpFile.deleteSync(); } @@ -473,7 +473,7 @@ class BackupService { }); await _flutterSecureStorage.delete(key: pinCodeKey); - await _flutterSecureStorage.write(key: pinCodeKey, value: encodedPinCode(pin: decodedPin)); + await _flutterSecureStorage.write(key: pinCodeKey, value: (await argon2Hash(password: decodedPin))); keychainDumpFile.deleteSync(); } diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 6466a5b41..8a916d7cc 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -1,5 +1,6 @@ import 'dart:io' show Directory, File, Platform; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/encrypt.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; @@ -187,6 +188,7 @@ Future defaultSettingsMigration( break; case 26: await pinEncryptionMigration(secureStorage: secureStorage); + break; default: break; } @@ -384,24 +386,32 @@ Future pinEncryptionMigration({required FlutterSecureStorage secureStorage try { // first, get the encoded pin: final keyForPinCode = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); - String? encodedPin; - encodedPin = await secureStorage.read(key: keyForPinCode); + String? encodedPin = await secureStorage.read(key: keyForPinCode); - // if (encodedPin == null) { - // return; - // } + // we don't have a pin?!? + if (encodedPin == null) { + print("pinEncryptionMigration: no pin found in secure storage!"); + // this should never happen, but just in case let's just set the pin to "0000" + // as it's better than permanently locking the user out with an un-decryptable pin + encodedPin = encodedPinCode(pin: "0000"); + } - // // ensure we overwrite by deleting the old key first: - // await secureStorage.delete(key: keyForPinCode); - // await secureStorage.write( - // key: keyForPinCode, - // value: encodedPin, - // iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), - // mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock), - // ); + // decode & re-encode the pin: + final decodedPin = decodedPinCode(pin: encodedPin); + final hashedPin = await argon2Hash(password: decodedPin); + + // ensure we overwrite by deleting the old key first: + await secureStorage.delete(key: keyForPinCode); + // write the new argon2 hashed pin: + await secureStorage.write( + key: keyForPinCode, + value: hashedPin, + iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), + mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock), + ); } catch (e) { // failure isn't really an option since we'll be updating how pins are stored and used - print(e); + print("pinEncryptionMigration: $e"); } } diff --git a/lib/entities/encrypt.dart b/lib/entities/encrypt.dart index 891f7a92d..9f41cb111 100644 --- a/lib/entities/encrypt.dart +++ b/lib/entities/encrypt.dart @@ -1,13 +1,25 @@ import 'package:encrypt/encrypt.dart'; // import 'package:password/password.dart'; import 'package:cake_wallet/.secrets.g.dart' as secrets; +import 'package:dargon2_flutter/dargon2_flutter.dart'; + +Future argon2Hash({required String password}) async { + final result = await argon2.hashPasswordString(password, salt: Salt.newSalt()); + // the salt is stored within the encoded string: + return result.encodedString; +} + +Future verifyArgon2Hash({required String password, required String hash}) async { + return argon2.verifyHashString(password, hash); +} + +// @@@@@@@@@@@@@@@ OLD (kept for reference purposes, do not use!) @@@@@@@@@@@@@ String encrypt({required String source, required String key}) { final _key = Key.fromUtf8(key); final iv = IV.allZerosOfLength(16); final encrypter = Encrypter(AES(_key)); final encrypted = encrypter.encrypt(source, iv: iv); - return encrypted.base64; } @@ -16,7 +28,6 @@ String decrypt({required String source, required String key}) { final iv = IV.allZerosOfLength(16); final encrypter = Encrypter(AES(_key)); final decrypted = encrypter.decrypt64(source, iv: iv); - return decrypted; } @@ -31,26 +42,22 @@ String hash({required String source}) { String encodedPinCode({required String pin}) { final source = '${secrets.salt}$pin'; - return encrypt(source: source, key: secrets.key); } String decodedPinCode({required String pin}) { final decrypted = decrypt(source: pin, key: secrets.key); - return decrypted.substring(secrets.key.length, decrypted.length); } String encodeWalletPassword({required String password}) { final source = password; final _key = secrets.shortKey + secrets.walletSalt; - return encrypt(source: source, key: _key); } String decodeWalletPassword({required String password}) { final source = password; final _key = secrets.shortKey + secrets.walletSalt; - return decrypt(source: source, key: _key); } diff --git a/lib/main.dart b/lib/main.dart index 165db1ddd..306b109a0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -163,7 +163,7 @@ Future initializeAppConfigs() async { transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, anonpayInvoiceInfo: anonpayInvoiceInfo, - initialMigrationVersion: 25); + initialMigrationVersion: 26); } Future initialSetup(