import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'package:crypto/crypto.dart'; import 'package:pointycastle/export.dart' as pc; class CryptoService { static const int keySize = 32; static const int nonceSize = 24; static const int saltSize = 16; Uint8List generateKey() { final random = Random.secure(); final key = Uint8List(keySize); for (int i = 0; i < keySize; i++) { key[i] = random.nextInt(256); } return key; } Uint8List generateNonce() { final random = Random.secure(); final nonce = Uint8List(nonceSize); for (int i = 0; i < nonceSize; i++) { nonce[i] = random.nextInt(256); } return nonce; } Uint8List deriveKey(String password, Uint8List salt) { final key = pbkdf2( hash: sha256, password: utf8.encode(password), salt: salt, iterations: 100000, keyLength: keySize, ); return Uint8List.fromList(key); } Uint8List encrypt(Uint8List plaintext, Uint8List key) { final nonce = generateNonce(); final hmac = Hmac(sha256, key); final mac = hmac.convert(plaintext).bytes; final result = Uint8List(nonce.length + mac.length + plaintext.length); result.setAll(0, nonce); result.setAll(nonce.length, mac); result.setAll(nonce.length + mac.length, plaintext); return result; } Uint8List? decrypt(Uint8List ciphertext, Uint8List key) { try { if (ciphertext.length < nonceSize + 32) return null; final nonce = ciphertext.sublist(0, nonceSize); final mac = ciphertext.sublist(nonceSize, nonceSize + 32); final plaintext = ciphertext.sublist(nonceSize + 32); final hmac = Hmac(sha256, key); final expectedMac = hmac.convert(plaintext).bytes; if (!listEquals(mac, expectedMac)) return null; return plaintext; } catch (_) { return null; } } String hashFile(Uint8List data) { return sha256.convert(data).toString(); } bool listEquals(List a, List b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) return false; } return true; } Uint8List generateKeyPairSeed() { return generateKey(); } }