mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-11 13:24:51 +00:00
pin migration, part 1
This commit is contained in:
parent
fc6be2aa97
commit
0746687efc
5 changed files with 44 additions and 29 deletions
|
@ -39,13 +39,13 @@ class AuthService with Store {
|
||||||
|
|
||||||
Future<void> setPassword(String password) async {
|
Future<void> setPassword(String password) async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
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
|
// secure storage has a weird bug on macOS, where overwriting a key doesn't work, unless
|
||||||
// we delete what's there first:
|
// we delete what's there first:
|
||||||
if (Platform.isMacOS) {
|
if (Platform.isMacOS) {
|
||||||
await secureStorage.delete(key: key);
|
await secureStorage.delete(key: key);
|
||||||
}
|
}
|
||||||
await secureStorage.write(key: key, value: encodedPassword);
|
await secureStorage.write(key: key, value: hashedPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> canAuthenticate() async {
|
Future<bool> canAuthenticate() async {
|
||||||
|
@ -64,10 +64,8 @@ class AuthService with Store {
|
||||||
|
|
||||||
Future<bool> authenticate(String pin) async {
|
Future<bool> authenticate(String pin) async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
final encodedPin = await secureStorage.read(key: key);
|
final hashedPassword = await secureStorage.read(key: key);
|
||||||
final decodedPin = decodedPinCode(pin: encodedPin!);
|
return verifyArgon2Hash(password: pin, hash: hashedPassword!);
|
||||||
|
|
||||||
return decodedPin == pin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveLastAuthTime() {
|
void saveLastAuthTime() {
|
||||||
|
|
|
@ -445,7 +445,7 @@ class BackupService {
|
||||||
});
|
});
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: pinCodeKey);
|
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();
|
keychainDumpFile.deleteSync();
|
||||||
}
|
}
|
||||||
|
@ -473,7 +473,7 @@ class BackupService {
|
||||||
});
|
});
|
||||||
|
|
||||||
await _flutterSecureStorage.delete(key: pinCodeKey);
|
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();
|
keychainDumpFile.deleteSync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:io' show Directory, File, Platform;
|
import 'dart:io' show Directory, File, Platform;
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
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:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||||
|
@ -187,6 +188,7 @@ Future<void> defaultSettingsMigration(
|
||||||
break;
|
break;
|
||||||
case 26:
|
case 26:
|
||||||
await pinEncryptionMigration(secureStorage: secureStorage);
|
await pinEncryptionMigration(secureStorage: secureStorage);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -384,24 +386,32 @@ Future<void> pinEncryptionMigration({required FlutterSecureStorage secureStorage
|
||||||
try {
|
try {
|
||||||
// first, get the encoded pin:
|
// first, get the encoded pin:
|
||||||
final keyForPinCode = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final keyForPinCode = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
String? encodedPin;
|
String? encodedPin = await secureStorage.read(key: keyForPinCode);
|
||||||
encodedPin = await secureStorage.read(key: keyForPinCode);
|
|
||||||
|
|
||||||
// if (encodedPin == null) {
|
// we don't have a pin?!?
|
||||||
// return;
|
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:
|
// decode & re-encode the pin:
|
||||||
// await secureStorage.delete(key: keyForPinCode);
|
final decodedPin = decodedPinCode(pin: encodedPin);
|
||||||
// await secureStorage.write(
|
final hashedPin = await argon2Hash(password: decodedPin);
|
||||||
// key: keyForPinCode,
|
|
||||||
// value: encodedPin,
|
// ensure we overwrite by deleting the old key first:
|
||||||
// iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
|
await secureStorage.delete(key: keyForPinCode);
|
||||||
// mOptions: MacOsOptions(accessibility: KeychainAccessibility.first_unlock),
|
// 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) {
|
} catch (e) {
|
||||||
// failure isn't really an option since we'll be updating how pins are stored and used
|
// failure isn't really an option since we'll be updating how pins are stored and used
|
||||||
print(e);
|
print("pinEncryptionMigration: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
import 'package:encrypt/encrypt.dart';
|
import 'package:encrypt/encrypt.dart';
|
||||||
// import 'package:password/password.dart';
|
// import 'package:password/password.dart';
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
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}) {
|
String encrypt({required String source, required String key}) {
|
||||||
final _key = Key.fromUtf8(key);
|
final _key = Key.fromUtf8(key);
|
||||||
final iv = IV.allZerosOfLength(16);
|
final iv = IV.allZerosOfLength(16);
|
||||||
final encrypter = Encrypter(AES(_key));
|
final encrypter = Encrypter(AES(_key));
|
||||||
final encrypted = encrypter.encrypt(source, iv: iv);
|
final encrypted = encrypter.encrypt(source, iv: iv);
|
||||||
|
|
||||||
return encrypted.base64;
|
return encrypted.base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +28,6 @@ String decrypt({required String source, required String key}) {
|
||||||
final iv = IV.allZerosOfLength(16);
|
final iv = IV.allZerosOfLength(16);
|
||||||
final encrypter = Encrypter(AES(_key));
|
final encrypter = Encrypter(AES(_key));
|
||||||
final decrypted = encrypter.decrypt64(source, iv: iv);
|
final decrypted = encrypter.decrypt64(source, iv: iv);
|
||||||
|
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,26 +42,22 @@ String hash({required String source}) {
|
||||||
|
|
||||||
String encodedPinCode({required String pin}) {
|
String encodedPinCode({required String pin}) {
|
||||||
final source = '${secrets.salt}$pin';
|
final source = '${secrets.salt}$pin';
|
||||||
|
|
||||||
return encrypt(source: source, key: secrets.key);
|
return encrypt(source: source, key: secrets.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
String decodedPinCode({required String pin}) {
|
String decodedPinCode({required String pin}) {
|
||||||
final decrypted = decrypt(source: pin, key: secrets.key);
|
final decrypted = decrypt(source: pin, key: secrets.key);
|
||||||
|
|
||||||
return decrypted.substring(secrets.key.length, decrypted.length);
|
return decrypted.substring(secrets.key.length, decrypted.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
String encodeWalletPassword({required String password}) {
|
String encodeWalletPassword({required String password}) {
|
||||||
final source = password;
|
final source = password;
|
||||||
final _key = secrets.shortKey + secrets.walletSalt;
|
final _key = secrets.shortKey + secrets.walletSalt;
|
||||||
|
|
||||||
return encrypt(source: source, key: _key);
|
return encrypt(source: source, key: _key);
|
||||||
}
|
}
|
||||||
|
|
||||||
String decodeWalletPassword({required String password}) {
|
String decodeWalletPassword({required String password}) {
|
||||||
final source = password;
|
final source = password;
|
||||||
final _key = secrets.shortKey + secrets.walletSalt;
|
final _key = secrets.shortKey + secrets.walletSalt;
|
||||||
|
|
||||||
return decrypt(source: source, key: _key);
|
return decrypt(source: source, key: _key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 25);
|
initialMigrationVersion: 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initialSetup(
|
Future<void> initialSetup(
|
||||||
|
|
Loading…
Reference in a new issue