Merge remote-tracking branch 'origin/dev' into cody/netwrok_SDK

# Conflicts:
#	apps/im_app/lib/features/chat/presentation/chat_db_test_view_model.dart
#	apps/im_app/lib/features/login/presentation/login_view_model.dart

修复逻辑漏洞,性能优化
This commit is contained in:
Cody
2026-03-08 20:47:28 +08:00
88 changed files with 5695 additions and 593 deletions

View File

@@ -9,6 +9,7 @@
library;
export 'src/presentation/facade/cipher_guard_sdk_api.dart';
export 'src/data/datasources/encryption_flutter_service.dart' show KdfMode;
export 'src/domain/entities/rsa_key_pair.dart';
export 'src/domain/entities/session_key.dart';
export 'src/domain/entities/encrypted_message.dart';

View File

@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:isolate';
import 'dart:math';
import 'dart:typed_data';
@@ -7,30 +8,96 @@ import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart' as encrypt_pkg;
import 'package:pointycastle/api.dart';
import 'package:pointycastle/asymmetric/api.dart';
import 'package:pointycastle/asymmetric/pkcs1.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
import 'package:pointycastle/digests/sha256.dart';
import 'package:pointycastle/key_derivators/api.dart';
import 'package:pointycastle/key_derivators/pbkdf2.dart';
import 'package:pointycastle/key_generators/api.dart';
import 'package:pointycastle/key_generators/rsa_key_generator.dart';
import 'package:pointycastle/macs/hmac.dart';
import 'package:pointycastle/random/fortuna_random.dart';
import 'package:pointycastle/asymmetric/rsa.dart';
import 'package:pointycastle/asymmetric/pkcs1.dart';
/// Flutter Encryption Service
/// Implements all encryption logic in Flutter using pointycastle and encrypt packages
/// Replaces native Android/iOS encryption implementations
/// 密钥派生模式
///
/// 决定 [EncryptionFlutterService._deriveKeyForRound] 使用哪种算法。
/// 默认 [md5]UU 兼容),可选 [pbkdf2](增强安全性)。
///
/// 解密旧数据时必须使用加密时相同的模式,
/// 通过消息的 version 字段区分。
enum KdfMode {
/// MD5 简单哈希UU 兼容默认模式)
///
/// 适用于 session key 已是 32 字节强随机值的场景。
/// 性能好,每次调用 < 0.1ms。
md5,
/// PBKDF2-HMAC-SHA256可选增强模式
///
/// 适用于从弱密码派生密钥的场景。
/// 性能取决于迭代次数10000 次约 10-50ms。
pbkdf2,
}
/// Flutter 加密服务
///
/// 端对端加密的核心引擎,纯 Dart 实现。
/// 使用 pointycastleRSA+ encryptAES+ cryptoMD5
///
/// ## 性能优化
///
/// - **RSA 密钥生成**:通过 [generateRsaKeyPairAsync] 在 Isolate 中运行,
/// 避免阻塞主线程1024-bit 约 150ms2048-bit 约 300ms
/// - **派生密钥缓存**[_deriveKeyForRound] 结果按 (sessionKey, round) 缓存,
/// 同一 session 的重复加解密直接命中缓存
/// - **Random.secure() 复用**:全局单例,不再每次调用创建新实例
/// - **KDF 双模式**MD5默认UU 兼容)/ PBKDF2可选增强安全性
class EncryptionFlutterService {
// ==================== Constants ====================
// ==================== 配置 ====================
/// 密钥派生模式,默认 MD5UU 兼容)
final KdfMode kdfMode;
/// PBKDF2 迭代次数(仅 PBKDF2 模式有效,默认 10000
final int pbkdf2Iterations;
EncryptionFlutterService({
this.kdfMode = KdfMode.md5,
this.pbkdf2Iterations = 10000,
});
// ==================== 常量 ====================
static const int sessionKeySize = 32;
static const int gcmIvLength = 12;
static const int _maxDerivedKeyCacheSize = 64;
// ==================== RSA Key Management ====================
// ==================== 性能优化:复用 Random 实例 ====================
/// Generate RSA key pair in PEM format
/// 全局 Random.secure() 单例,避免每次调用创建新实例
static final Random _secureRandom = Random.secure();
// ==================== 性能优化:派生密钥 LRU 缓存 ====================
/// 派生密钥缓存:'sessionKey:round:mode' -> Uint8List
///
/// 同一 session + round 的加解密只派生一次,后续直接命中缓存。
/// LinkedHashMap 保持插入顺序,满时淘汰最早条目。
final _derivedKeyCache = <String, Uint8List>{};
/// 清空派生密钥缓存session key 轮换时调用)
void clearDerivedKeyCache() => _derivedKeyCache.clear();
// ==================== RSA 密钥管理 ====================
/// 生成 RSA 密钥对(同步,阻塞主线程)
///
/// 建议使用 [generateRsaKeyPairAsync] 代替,避免 UI 卡顿。
RsaKeyPairResult generateRsaKeyPair({int keySize = 1024}) {
try {
// Get secure random
final secureRandom = FortunaRandom();
secureRandom.seed(KeyParameter(_generateSecureRandomBytes(32)));
// Create RSA key generator
final keyGen = RSAKeyGenerator();
keyGen.init(
ParametersWithRandom(
@@ -39,12 +106,10 @@ class EncryptionFlutterService {
),
);
// Generate key pair
final keyPair = keyGen.generateKeyPair();
final rsaPublicKey = keyPair.publicKey;
final rsaPrivateKey = keyPair.privateKey;
// Export to PEM format
final publicKeyPem = _encodeRSAPublicKey(rsaPublicKey);
final privateKeyPem = _encodeRSAPrivateKey(rsaPrivateKey);
@@ -57,26 +122,38 @@ class EncryptionFlutterService {
}
}
/// Encode RSA public key to PEM format using asn1lib
/// 生成 RSA 密钥对(异步,在 Isolate 中运行,不阻塞主线程)
///
/// RSA 密钥生成是 CPU 密集型操作1024-bit 约 150ms2048-bit 约 300ms
/// 放在 Isolate 中避免主线程卡顿。
///
/// **Isolate 隔离说明**
/// Isolate 内会创建一个**默认配置**的 EncryptionFlutterServiceKdfMode.md5
/// 不会继承当前实例的 kdfMode / pbkdf2Iterations。
/// 这对 RSA 密钥生成没有影响RSA 不走 KDF但如果将来需要在
/// Isolate 中执行依赖 KDF 的操作(如消息加解密),需要传递配置参数。
Future<RsaKeyPairResult> generateRsaKeyPairAsync({int keySize = 1024}) async {
return await Isolate.run(
() => EncryptionFlutterService().generateRsaKeyPair(keySize: keySize),
);
}
/// 编码 RSA 公钥为 PEM 格式
String _encodeRSAPublicKey(RSAPublicKey publicKey) {
// Build RSAPublicKeyInfo structure
final topSeq = ASN1Sequence();
// AlgorithmIdentifier: OID 1.2.840.113549.1.1.1 + NULL
final algoSeq = ASN1Sequence();
algoSeq.add(ASN1ObjectIdentifier([1, 2, 840, 113549, 1, 1, 1])); // RSA
algoSeq.add(ASN1ObjectIdentifier([1, 2, 840, 113549, 1, 1, 1]));
algoSeq.add(ASN1Null());
topSeq.add(algoSeq);
// RSAPublicKey: modulus + publicExponent
final keySeq = ASN1Sequence();
keySeq.add(ASN1Integer(publicKey.n!));
keySeq.add(ASN1Integer(publicKey.exponent!));
// BitString wrapping the key (with 0 unused bits prefix)
final keyBytes = keySeq.encodedBytes;
final keyList = List<int>.from(keyBytes);
keyList.insert(0, 0); // Add unused bits byte
keyList.insert(0, 0);
topSeq.add(ASN1BitString(keyList));
final derBytes = topSeq.encodedBytes;
@@ -84,51 +161,32 @@ class EncryptionFlutterService {
return '-----BEGIN PUBLIC KEY-----\n$base64\n-----END PUBLIC KEY-----';
}
/// Encode RSA private key to PEM format using asn1lib
/// 编码 RSA 私钥为 PEM 格式
String _encodeRSAPrivateKey(RSAPrivateKey privateKey) {
// Build RSAPrivateKey structure (PKCS#8 format)
final topSeq = ASN1Sequence();
// Version (0)
topSeq.add(ASN1Integer(BigInt.zero));
// Modulus
topSeq.add(ASN1Integer(privateKey.n!));
// Public Exponent
topSeq.add(ASN1Integer(privateKey.exponent!));
// Private Exponent
topSeq.add(ASN1Integer(privateKey.privateExponent!));
// Prime P
topSeq.add(ASN1Integer(privateKey.p!));
// Prime Q
topSeq.add(ASN1Integer(privateKey.q!));
// (Optional CRT params omitted for simplicity)
final derBytes = topSeq.encodedBytes;
final base64 = base64Encode(derBytes.toList());
return '-----BEGIN PRIVATE KEY-----\n$base64\n-----END PRIVATE KEY-----';
}
// ==================== Private Key Encryption/Decryption ====================
// ==================== 私钥加密/解密 ====================
/// Encrypt private key with password (AES-CBC with MD5-derived key)
/// 用密码加密私钥AES-CBC密码通过 MD5 派生密钥)
String encryptPrivateKey({
required String privateKey,
required String password,
}) {
try {
// Generate AES key from MD5(password)
final aesKey = _md5Hash(password);
// Generate random IV (16 bytes)
final iv = _generateSecureRandomBytes(16);
// AES encrypt using encrypt package
final secretKey = encrypt_pkg.Key(aesKey);
final encryptor = encrypt_pkg.Encrypter(
encrypt_pkg.AES(secretKey, mode: encrypt_pkg.AESMode.cbc),
@@ -137,7 +195,6 @@ class EncryptionFlutterService {
final encrypted = encryptor.encrypt(privateKey, iv: encrypt_pkg.IV(iv));
final encryptedBytes = encrypted.bytes;
// Combine IV + encrypted data
final combined = Uint8List(iv.length + encryptedBytes.length);
combined.setAll(0, iv);
combined.setAll(iv.length, encryptedBytes);
@@ -148,23 +205,17 @@ class EncryptionFlutterService {
}
}
/// Decrypt private key with password (AES-CBC with MD5-derived key)
/// 用密码解密私钥AES-CBC密码通过 MD5 派生密钥)
String decryptPrivateKey({
required String encryptedPrivateKey,
required String password,
}) {
try {
// Generate AES key from MD5(password)
final aesKey = _md5Hash(password);
// Decode Base64
final combined = base64Decode(encryptedPrivateKey);
// Extract IV and encrypted data
final iv = combined.sublist(0, 16);
final encBytes = combined.sublist(16);
// AES decrypt
final secretKey = encrypt_pkg.Key(aesKey);
final encryptor = encrypt_pkg.Encrypter(
encrypt_pkg.AES(secretKey, mode: encrypt_pkg.AESMode.cbc),
@@ -181,9 +232,9 @@ class EncryptionFlutterService {
}
}
// ==================== Session Key Management ====================
// ==================== 会话密钥管理 ====================
/// Generate session key (32 bytes random)
/// 生成会话密钥32 字节随机)
SessionKeyResult generateSessionKey({int initialRound = 1}) {
final keyBytes = _generateSecureRandomBytes(sessionKeySize);
final key = base64Encode(keyBytes);
@@ -191,16 +242,14 @@ class EncryptionFlutterService {
return SessionKeyResult(key: key, round: initialRound);
}
/// Encrypt session key with RSA public key
/// 用 RSA 公钥加密会话密钥
String encryptSessionKey({
required String sessionKey,
required String publicKey,
}) {
try {
// Parse RSA public key
final rsaPublicKey = _parsePublicKey(publicKey);
// RSA encrypt using PKCS1 padding (like native implementations)
final cipher = PKCS1Encoding(RSAEngine());
cipher.init(true, PublicKeyParameter<RSAPublicKey>(rsaPublicKey));
@@ -211,16 +260,14 @@ class EncryptionFlutterService {
}
}
/// Decrypt session key with RSA private key
/// 用 RSA 私钥解密会话密钥
String decryptSessionKey({
required String encryptedSessionKey,
required String privateKey,
}) {
try {
// Parse RSA private key
final rsaPrivateKey = _parsePrivateKey(privateKey);
// RSA decrypt using PKCS1 padding (like native implementations)
final cipher = PKCS1Encoding(RSAEngine());
cipher.init(false, PrivateKeyParameter<RSAPrivateKey>(rsaPrivateKey));
@@ -231,22 +278,18 @@ class EncryptionFlutterService {
}
}
// ==================== Message Encryption/Decryption ====================
// ==================== 消息加密/解密 ====================
/// Encrypt message (AES-CTR with round-based key derivation)
/// 加密消息(AES-CTR,使用 round 派生密钥)
EncryptedMessageResult encryptMessage({
required String plaintext,
required String sessionKey,
required int round,
}) {
try {
// Derive key for round
final actualKey = _deriveKeyForRound(sessionKey, round);
// Generate random IV (16 bytes for CTR)
final iv = _generateSecureRandomBytes(16);
// AES-CTR encrypt
final secretKey = encrypt_pkg.Key(actualKey);
final encryptor = encrypt_pkg.Encrypter(
encrypt_pkg.AES(secretKey, mode: encrypt_pkg.AESMode.ctr),
@@ -255,7 +298,6 @@ class EncryptionFlutterService {
final encrypted = encryptor.encrypt(plaintext, iv: encrypt_pkg.IV(iv));
final encryptedBytes = encrypted.bytes;
// Combine IV + encrypted data
final combined = Uint8List(iv.length + encryptedBytes.length);
combined.setAll(0, iv);
combined.setAll(iv.length, encryptedBytes);
@@ -268,24 +310,18 @@ class EncryptionFlutterService {
}
}
/// Decrypt message (AES-CTR with round-based key derivation)
/// 解密消息(AES-CTR,使用 round 派生密钥)
String decryptMessage({
required String encryptedData,
required String sessionKey,
required int round,
}) {
try {
// Derive key for round
final actualKey = _deriveKeyForRound(sessionKey, round);
// Decode Base64
final combined = base64Decode(encryptedData);
// Extract IV and encrypted data
final iv = combined.sublist(0, 16);
final encBytes = combined.sublist(16);
// AES-CTR decrypt
final secretKey = encrypt_pkg.Key(actualKey);
final encryptor = encrypt_pkg.Encrypter(
encrypt_pkg.AES(secretKey, mode: encrypt_pkg.AESMode.ctr),
@@ -302,16 +338,16 @@ class EncryptionFlutterService {
}
}
// ==================== Push Notification Decryption ====================
// ==================== 推送通知解密 ====================
/// Set AES secret for push notification decryption
/// 设置 AES secret(用于推送通知解密)
void setAesSecret(String aesSecret) {
_aesSecret = aesSecret;
}
String? _aesSecret;
/// Decrypt push notification (AES-GCM)
/// 解密推送通知(AES-GCM
String decryptPushNotification({required String encryptedData}) {
try {
final secret = _aesSecret;
@@ -319,17 +355,11 @@ class EncryptionFlutterService {
throw Exception('AES_SECRET not set');
}
// Convert hex string to bytes
final secretBytes = _hexStringToBytes(secret);
// Decode Base64
final combined = base64Decode(encryptedData);
// Extract IV and encrypted data
final iv = combined.sublist(0, gcmIvLength);
final encBytes = combined.sublist(gcmIvLength);
// AES-GCM decrypt
final secretKey = encrypt_pkg.Key(secretBytes);
final encryptor = encrypt_pkg.Encrypter(
encrypt_pkg.AES(secretKey, mode: encrypt_pkg.AESMode.gcm),
@@ -346,37 +376,91 @@ class EncryptionFlutterService {
}
}
// ==================== Helper Methods ====================
// ==================== 内部方法 ====================
/// Generate secure random bytes
/// 生成安全随机字节(复用全局 Random.secure() 实例)
Uint8List _generateSecureRandomBytes(int length) {
final random = Random.secure();
final bytes = Uint8List(length);
for (var i = 0; i < length; i++) {
bytes[i] = random.nextInt(256);
bytes[i] = _secureRandom.nextInt(256);
}
return bytes;
}
/// MD5 hash
/// MD5 哈希(用于密码派生密钥)
Uint8List _md5Hash(String input) {
final bytes = utf8.encode(input);
final hash = md5.convert(bytes).bytes as Uint8List;
return hash;
final hash = md5.convert(bytes).bytes;
return Uint8List.fromList(hash);
}
/// Derive key for round (MD5 hash of session key)
/// 按 round 派生 AES 密钥(带 LRU 缓存)
///
/// 支持两种模式:
/// - [KdfMode.md5]MD5(sessionKey + round),兼容模式,< 0.1ms
/// - [KdfMode.pbkdf2]PBKDF2-HMAC-SHA256(sessionKey, salt=round),约 10-50ms
///
/// 两种模式都会将 round 参与派生计算,保证不同 round 产出不同密钥。
/// 缓存命中时直接返回,跳过计算。
/// 缓存满时淘汰最久未访问的条目LRU
Uint8List _deriveKeyForRound(String sessionKey, int targetRound) {
// Base64 decode session key
final keyBytes = base64Decode(sessionKey);
final modeName = kdfMode == KdfMode.md5 ? 'md5' : 'pbkdf2';
final cacheKey = '$sessionKey:$targetRound:$modeName';
// Apply MD5 for the round (simplified version)
final hash = md5.convert(keyBytes).bytes as Uint8List;
// 缓存命中 — 移至末尾以维护 LRU 顺序
final cached = _derivedKeyCache.remove(cacheKey);
if (cached != null) {
_derivedKeyCache[cacheKey] = cached;
return cached;
}
return hash;
// 计算派生密钥
final Uint8List result;
switch (kdfMode) {
case KdfMode.md5:
// 将 sessionKey + round 一起参与 hash保证不同 round 产出不同密钥
final keyBytes = base64Decode(sessionKey);
final roundBytes = utf8.encode(':$targetRound');
final combined = Uint8List(keyBytes.length + roundBytes.length)
..setRange(0, keyBytes.length, keyBytes)
..setRange(
keyBytes.length,
keyBytes.length + roundBytes.length,
roundBytes,
);
final hash = md5.convert(combined).bytes;
result = Uint8List.fromList(hash);
case KdfMode.pbkdf2:
result = _pbkdf2Derive(sessionKey, targetRound);
}
// LRU 淘汰满时移除最久未访问的条目Map 头部)
if (_derivedKeyCache.length >= _maxDerivedKeyCacheSize) {
_derivedKeyCache.remove(_derivedKeyCache.keys.first);
}
_derivedKeyCache[cacheKey] = result;
return result;
}
/// Parse RSA public key from PEM
/// PBKDF2-HMAC-SHA256 密钥派生
///
/// salt 包含 round 信息,不同 round 派生不同密钥。
/// 迭代次数由 [pbkdf2Iterations] 控制(默认 10000
/// 输出 16 字节AES-128 密钥)。
Uint8List _pbkdf2Derive(String sessionKey, int targetRound) {
final keyBytes = base64Decode(sessionKey);
final salt = utf8.encode('round:$targetRound');
final derivator = PBKDF2KeyDerivator(HMac(SHA256Digest(), 64));
derivator.init(
Pbkdf2Parameters(Uint8List.fromList(salt), pbkdf2Iterations, 16),
);
return derivator.process(Uint8List.fromList(keyBytes));
}
/// 解析 RSA 公钥 PEM
RSAPublicKey _parsePublicKey(String pem) {
final base64 = pem
.replaceAll('-----BEGIN PUBLIC KEY-----', '')
@@ -385,7 +469,6 @@ class EncryptionFlutterService {
.trim();
final bytes = base64Decode(base64);
// Parse ASN.1 DER format
final asn1Parser = ASN1Parser(Uint8List.fromList(bytes));
final topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
@@ -403,7 +486,7 @@ class EncryptionFlutterService {
);
}
/// Parse RSA private key from PEM
/// 解析 RSA 私钥 PEM
RSAPrivateKey _parsePrivateKey(String pem) {
final base64 = pem
.replaceAll('-----BEGIN PRIVATE KEY-----', '')
@@ -412,7 +495,6 @@ class EncryptionFlutterService {
.trim();
final bytes = base64Decode(base64);
// Parse ASN.1 DER format
final asn1Parser = ASN1Parser(Uint8List.fromList(bytes));
final keySeq = asn1Parser.nextObject() as ASN1Sequence;
@@ -429,7 +511,7 @@ class EncryptionFlutterService {
);
}
/// Convert hex string to bytes
/// Hex 字符串转字节
Uint8List _hexStringToBytes(String hex) {
final len = hex.length;
final data = Uint8List(len ~/ 2);

View File

@@ -16,7 +16,8 @@ class EncryptionRepositoryImpl implements EncryptionRepository {
@override
Future<RsaKeyPair> generateRsaKeyPair({int keySize = 1024}) async {
final result = _service.generateRsaKeyPair(keySize: keySize);
// 在 Isolate 中运行避免阻塞主线程1024-bit 约 150ms
final result = await _service.generateRsaKeyPairAsync(keySize: keySize);
return RsaKeyPair(
publicKey: result.publicKey,
privateKey: result.privateKey,
@@ -50,10 +51,7 @@ class EncryptionRepositoryImpl implements EncryptionRepository {
@override
Future<SessionKey> generateSessionKey({int initialRound = 1}) async {
final result = _service.generateSessionKey(initialRound: initialRound);
return SessionKey(
key: result.key,
round: result.round,
);
return SessionKey(key: result.key, round: result.round);
}
@override
@@ -91,10 +89,7 @@ class EncryptionRepositoryImpl implements EncryptionRepository {
sessionKey: sessionKey,
round: round,
);
return EncryptedMessage(
round: result.round,
data: result.data,
);
return EncryptedMessage(round: result.round, data: result.data);
}
@override
@@ -110,6 +105,11 @@ class EncryptionRepositoryImpl implements EncryptionRepository {
);
}
// ==================== 缓存管理 ====================
@override
void clearDerivedKeyCache() => _service.clearDerivedKeyCache();
// ==================== 原生平台同步 ====================
@override
@@ -147,4 +147,3 @@ class EncryptionRepositoryImpl implements EncryptionRepository {
return _service.decryptPushNotification(encryptedData: encryptedData);
}
}

View File

@@ -8,7 +8,7 @@ import '../entities/encrypted_message.dart';
abstract class EncryptionRepository {
// ==================== RSA 金鑰管理 ====================
/// 生成 RSA 金鑰對
/// [keySize] 金鑰長度 (預設 1024, 可用 2048)
Future<RsaKeyPair> generateRsaKeyPair({int keySize = 1024});
@@ -84,6 +84,14 @@ abstract class EncryptionRepository {
required Map<String, Map<String, dynamic>> chatMap,
});
// ==================== 缓存管理 ====================
/// 清空派生密钥缓存
///
/// 在 session key 轮换时调用,确保旧密钥的派生结果不会被复用。
/// 不影响已加密的消息,只影响后续加解密操作的密钥派生。
void clearDerivedKeyCache();
// ==================== 配置相關 ====================
/// 設置 AES_SECRET (用於推送解密)
@@ -91,8 +99,5 @@ abstract class EncryptionRepository {
/// 解密 APNS 推送通知內容
/// 使用 release.json 中的 AES_SECRET
Future<String?> decryptPushNotification({
required String encryptedData,
});
Future<String?> decryptPushNotification({required String encryptedData});
}

View File

@@ -7,59 +7,93 @@ import 'package:cipher_guard_sdk/src/domain/entities/session_key.dart';
import 'package:cipher_guard_sdk/src/domain/entities/encrypted_message.dart';
import 'package:cipher_guard_sdk/src/presentation/wiring/cipher_guard_sdk_wiring.dart';
abstract class CipherGuardSdkApi
{
abstract class CipherGuardSdkApi {
factory CipherGuardSdkApi() => CipherGuardSdkWiring.build();
// ==================== 平台版本 ====================
/// 獲取平台版本
Future<String?> platformVersion();
// ==================== RSA 金鑰管理 ====================
/// 生成 RSA 金鑰對
Future<RsaKeyPair> generateRsaKeyPair({int keySize = 1024});
/// 用密碼加密私鑰
Future<String> encryptPrivateKey({required String privateKey, required String password,});
Future<String> encryptPrivateKey({
required String privateKey,
required String password,
});
/// 解密私鑰
Future<String> decryptPrivateKey({required String encryptedPrivateKey, required String password,});
Future<String> decryptPrivateKey({
required String encryptedPrivateKey,
required String password,
});
// ==================== 會話金鑰管理 ====================
/// 生成 AES 會話金鑰
Future<SessionKey> generateSessionKey({int initialRound = 1});
/// 用 RSA 公鑰加密會話金鑰
Future<String> encryptSessionKey({required String sessionKey, required String publicKey,});
Future<String> encryptSessionKey({
required String sessionKey,
required String publicKey,
});
/// 用 RSA 私鑰解密會話金鑰
Future<String> decryptSessionKey({required String encryptedSessionKey, required String privateKey,});
Future<String> decryptSessionKey({
required String encryptedSessionKey,
required String privateKey,
});
// ==================== 訊息加解密 ====================
/// 加密訊息
Future<EncryptedMessage> encryptMessage({required String plaintext, required String sessionKey, required int round,});
Future<EncryptedMessage> encryptMessage({
required String plaintext,
required String sessionKey,
required int round,
});
/// 解密訊息
Future<String> decryptMessage({required String encryptedData, required String sessionKey, required int round,});
Future<String> decryptMessage({
required String encryptedData,
required String sessionKey,
required int round,
});
// ==================== 缓存管理 ====================
/// 清空派生密钥缓存
///
/// session key 轮换后必须调用,否则旧 key 的派生结果可能被复用,
/// 导致加解密使用错误的密钥。
void clearDerivedKeyCache();
// ==================== 原生平台同步 ====================
/// 同步加密金鑰到原生平台 (iOS App Group)
Future<void> syncEncryptionKey({required String chatId, required int activeRound, required int round, required String activeKey, required bool isSingle,});
Future<void> syncEncryptionKey({
required String chatId,
required int activeRound,
required int round,
required String activeKey,
required bool isSingle,
});
/// 批量同步所有加密聊天室的金鑰
Future<void> syncAllEncryptionKeys({required Map<String, Map<String, dynamic>> chatMap,});
Future<void> syncAllEncryptionKeys({
required Map<String, Map<String, dynamic>> chatMap,
});
// ==================== 推送通知解密 ====================
/// 設置 AES_SECRET (用於推送解密)
Future<void> setAesSecret({required String aesSecret});
/// 解密 APNS 推送通知內容
Future<String?> decryptPushNotification({required String encryptedData,});
Future<String?> decryptPushNotification({required String encryptedData});
}

View File

@@ -93,6 +93,9 @@ class CipherGuardSdkApiImpl implements CipherGuardSdkApi {
);
}
@override
void clearDerivedKeyCache() => _core.encryptionRepo.clearDerivedKeyCache();
@override
Future<void> syncEncryptionKey({
required String chatId,
@@ -123,9 +126,9 @@ class CipherGuardSdkApiImpl implements CipherGuardSdkApi {
}
@override
Future<String?> decryptPushNotification({
required String encryptedData,
}) {
return _core.encryptionRepo.decryptPushNotification(encryptedData: encryptedData);
Future<String?> decryptPushNotification({required String encryptedData}) {
return _core.encryptionRepo.decryptPushNotification(
encryptedData: encryptedData,
);
}
}

View File

@@ -9,9 +9,18 @@ import 'package:cipher_guard_sdk/src/presentation/wiring/cipher_guard_sdk_api_im
/// 使用 Flutter 本地加密服務,無需原生平台處理加密邏輯
class CipherGuardSdkWiring {
/// 構建 SDK 實例
static CipherGuardSdkApi build() {
///
/// [kdfMode] — 密钥派生模式,默认 [KdfMode.md5](兼容模式)
/// [pbkdf2Iterations] — PBKDF2 迭代次数(仅 pbkdf2 模式生效,默认 10000
static CipherGuardSdkApi build({
KdfMode kdfMode = KdfMode.md5,
int pbkdf2Iterations = 10000,
}) {
// 1. 創建 Flutter 加密服務
final flutterService = EncryptionFlutterService();
final flutterService = EncryptionFlutterService(
kdfMode: kdfMode,
pbkdf2Iterations: pbkdf2Iterations,
);
// 2. 創建 Repository (使用 Flutter 服務)
final repository = EncryptionRepositoryImpl(flutterService);
@@ -39,4 +48,3 @@ class _CipherGuardPlatformImpl implements CipherGuardPlatform {
return 'Flutter Native'; // 所有加密邏輯現在都在 Flutter 端執行
}
}