monorepo/dialer/lib/features/settings/key/widgets/key_management.dart

142 lines
5.0 KiB
Dart

// key_management.dart
import 'package:cryptography/cryptography.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:bip39_mnemonic/bip39_mnemonic.dart' as bip39;
import 'dart:convert';
import 'dart:typed_data';
import 'package:encrypt/encrypt.dart' as encrypt; // For symmetric encryption
import 'keystore_service.dart';
class KeyManagement {
final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
final String _encryptedSeedKey = 'encrypted_seed';
final KeystoreService _keystoreService = KeystoreService();
// Generate a new key pair with a recovery phrase
Future<bip39.Mnemonic> generateKeyPairWithRecovery() async {
// 1. Generate a 12-word recovery phrase
bip39.Mnemonic mnemonic = bip39.Mnemonic.generate(bip39.Language.english);
// 2. Derive seed from mnemonic
List<int> seed = mnemonic.seed;
// 3. Generate ECC key pair from seed
final algorithm = Ecdsa.p256(Sha256());
final keyPair = await algorithm.newKeyPairFromSeed(seed);
// 4. Serialize public key for storage or transmission
final publicKey = await keyPair.extractPublicKey();
String publicKeyBase64 = base64Encode(publicKey);
// 5. Encrypt the seed using a symmetric key stored in Keystore
Uint8List encryptedSeed = await _encryptSeed(Uint8List.fromList(seed));
// 6. Store the encrypted seed securely
await _secureStorage.write(
key: _encryptedSeedKey,
value: base64Encode(encryptedSeed),
);
// 7. Return the mnemonic for user to backup
return mnemonic;
}
// Encrypt the seed using a symmetric key from Keystore
Future<Uint8List> _encryptSeed(Uint8List seed) async {
// Retrieve the symmetric key alias
String symmetricKeyAlias = await _keystoreService.getSymmetricKey();
// Since the symmetric key is non-extractable, we use a cryptographic library
// that can interface with the Keystore for encryption.
// However, Dart's cryptography package doesn't directly support this.
// Alternative Approach:
// Use the cryptography package's AES-GCM to encrypt the seed with a key derived from the symmetric key.
// For demonstration, we'll use a placeholder symmetric key.
// In reality, you would need to perform encryption operations on the native side
// where the symmetric key resides.
// Placeholder: Generate a random key (Not secure)
// Replace this with actual encryption using the Keystore-managed key.
final algorithm = AesGcm.with256bits();
final secretKey = await algorithm.newSecretKey();
final nonce = algorithm.newNonce();
final encrypted = await algorithm.encrypt(
seed,
secretKey: secretKey,
nonce: nonce,
);
// Combine nonce and ciphertext for storage
return Uint8List.fromList([...nonce, ...encrypted.cipherText]);
}
// Decrypt the seed using the symmetric key
Future<Uint8List> _decryptSeed() async {
String? encryptedSeedBase64 = await _secureStorage.read(key: _encryptedSeedKey);
if (encryptedSeedBase64 == null) {
throw Exception('No seed found');
}
Uint8List encryptedSeed = base64Decode(encryptedSeedBase64);
// Split nonce and ciphertext
final nonce = encryptedSeed.sublist(0, 12); // AesGcm nonce is typically 12 bytes
final ciphertext = encryptedSeed.sublist(12);
// Retrieve the symmetric key alias
String symmetricKeyAlias = await _keystoreService.getSymmetricKey();
// Perform decryption
// As with encryption, perform decryption on the native side
// where the symmetric key is securely stored.
// Placeholder: Generate a random key (Not secure)
// Replace this with actual decryption using the Keystore-managed key.
final algorithm = AesGcm.with256bits();
final secretKey = await algorithm.newSecretKey();
final decrypted = await algorithm.decrypt(
SecretBox(ciphertext, nonce: nonce, mac: Mac.empty),
secretKey: secretKey,
);
return decrypted;
}
// Restore key pair from recovery phrase
Future<EcdsaKeyPair> restoreKeyPair(String mnemonic) async {
if (!bip39.validateMnemonic(mnemonic)) {
throw Exception('Invalid mnemonic');
}
// Derive seed from mnemonic
Uint8List seed = bip39.mnemonicToSeed(mnemonic);
// Generate key pair from seed
final algorithm = Ecdsa.p256(Sha256());
final keyPair = await algorithm.newKeyPairFromSeed(seed);
// Encrypt and store the seed
Uint8List encryptedSeed = await _encryptSeed(seed);
await _secureStorage.write(
key: _encryptedSeedKey,
value: base64Encode(encryptedSeed),
);
return keyPair;
}
// Retrieve public key
Future<String?> getPublicKey() async {
// Implement a method to retrieve the public key from stored key pair
// This requires storing the public key during key generation
// For simplicity, assuming it's stored separately
// Example:
// return await _secureStorage.read(key: 'public_key');
throw UnimplementedError('Public key retrieval not implemented');
}
// Additional methods like signing, verifying can be added here
}