pin migration, part 1

This commit is contained in:
fosse 2023-12-14 11:55:41 -05:00
parent fc6be2aa97
commit 0746687efc
5 changed files with 44 additions and 29 deletions

View file

@ -39,13 +39,13 @@ class AuthService with Store {
Future<void> 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<bool> canAuthenticate() async {
@ -64,10 +64,8 @@ class AuthService with Store {
Future<bool> 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() {

View file

@ -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();
}

View file

@ -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<void> defaultSettingsMigration(
break;
case 26:
await pinEncryptionMigration(secureStorage: secureStorage);
break;
default:
break;
}
@ -384,24 +386,32 @@ Future<void> 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");
}
}

View file

@ -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<String> 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<bool> 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);
}

View file

@ -163,7 +163,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 25);
initialMigrationVersion: 26);
}
Future<void> initialSetup(