import 'dart:convert'; import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; /// Stores and verifies a PIN. The raw PIN is never persisted — only a /// salted SHA-256 hash of it, kept in secure storage (Keychain on iOS, /// EncryptedSharedPreferences/Keystore on Android). class PinLockService { PinLockService({FlutterSecureStorage? storage}) : _storage = storage ?? const FlutterSecureStorage(); static const _saltKey = 'pin_salt'; static const _hashKey = 'pin_hash'; final FlutterSecureStorage _storage; Future hasPin() async { final hash = await _storage.read(key: _hashKey); return hash != null && hash.isNotEmpty; } Future setPin(String pin) async { final salt = _generateSalt(); final hash = _hash(pin, salt); await _storage.write(key: _saltKey, value: salt); await _storage.write(key: _hashKey, value: hash); } Future verifyPin(String pin) async { final salt = await _storage.read(key: _saltKey); final storedHash = await _storage.read(key: _hashKey); if (salt == null || storedHash == null) return false; return _hash(pin, salt) == storedHash; } Future clearPin() async { await _storage.delete(key: _saltKey); await _storage.delete(key: _hashKey); } String _generateSalt([int length = 16]) { final random = Random.secure(); final bytes = List.generate(length, (_) => random.nextInt(256)); return base64UrlEncode(bytes); } String _hash(String pin, String salt) { final bytes = utf8.encode('$salt:$pin'); return sha256.convert(bytes).toString(); } }