import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'package:crypto/crypto.dart'; 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) { return _pbkdf2(sha256, utf8.encode(password), salt, 100000, keySize); } static Uint8List _pbkdf2(Hash hash, List password, List salt, int iterations, int keyLength) { const hLen = 32; final blocks = (keyLength + hLen - 1) ~/ hLen; final result = Uint8List(keyLength); for (int block = 1; block <= blocks; block++) { final blockBytes = ByteData(4)..setUint32(0, block, Endian.big); final blockSalt = Uint8List.fromList([...salt, ...blockBytes.buffer.asUint8List()]); final prf = Hmac(hash, password); var u = prf.convert(blockSalt).bytes; var t = Uint8List.fromList(u); for (int i = 1; i < iterations; i++) { u = prf.convert(u).bytes; for (int j = 0; j < hLen; j++) { t[j] ^= u[j]; } } final offset = (block - 1) * hLen; final length = min(hLen, keyLength - offset); result.setRange(offset, offset + length, t.sublist(0, length)); } return result; } Uint8List encrypt(Uint8List plaintext, Uint8List key) { final hmac = Hmac(sha256, key); final mac = hmac.convert(plaintext).bytes; final nonce = generateNonce(); 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 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(); } }