优化配置,修复 demo bug

1,network 框架完善
2,websocket 机制完善
3,设计文档整理到架构文档
4,脚本,配置完善
This commit is contained in:
Cody
2026-03-07 14:58:10 +08:00
parent f8a118af73
commit 0ee2c8c63c
82 changed files with 2704 additions and 1045 deletions

View File

@@ -1,66 +0,0 @@
group = "com.example.cipher_guard_sdk"
version = "1.0-SNAPSHOT"
buildscript {
ext.kotlin_version = "2.2.20"
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.11.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
namespace = "com.example.cipher_guard_sdk"
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17
}
sourceSets {
main.java.srcDirs += "src/main/kotlin"
test.java.srcDirs += "src/test/kotlin"
}
defaultConfig {
minSdk = 24
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.0.0")
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}

View File

@@ -0,0 +1,71 @@
group = "com.example.cipher_guard_sdk"
version = "1.0-SNAPSHOT"
buildscript {
val kotlinVersion = "2.2.20"
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.11.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.example.cipher_guard_sdk"
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
sourceSets {
getByName("main") { java.srcDirs("src/main/kotlin") }
getByName("test") { java.srcDirs("src/test/kotlin") }
}
defaultConfig {
minSdk = 24
}
testOptions {
unitTests {
isIncludeAndroidResources = true
all {
it.useJUnitPlatform()
it.outputs.upToDateWhen { false }
it.testLogging {
events("passed", "skipped", "failed", "standardOut", "standardError")
showStandardStreams = true
}
}
}
}
}
kotlin {
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
}
}
dependencies {
// Compose BOM 统一管理子库版本,按需在各 SDK 中引入具体组件
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.0.0")
}

View File

@@ -1,4 +1,4 @@
import Flutter
@preconcurrency import Flutter
import UIKit
public class CipherGuardSdkPlugin: NSObject, FlutterPlugin {

View File

@@ -19,7 +19,7 @@ A new Flutter plugin project.
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0'
s.swift_version = '6.2'
# If your plugin requires a privacy manifest, for example if it uses any
# required reason APIs, update the PrivacyInfo.xcprivacy file to describe your

View File

@@ -29,23 +29,25 @@ class EncryptionFlutterService {
// Get secure random
final secureRandom = FortunaRandom();
secureRandom.seed(KeyParameter(_generateSecureRandomBytes(32)));
// Create RSA key generator
final keyGen = RSAKeyGenerator();
keyGen.init(ParametersWithRandom(
RSAKeyGeneratorParameters(BigInt.parse('65537'), keySize, 64),
secureRandom,
));
keyGen.init(
ParametersWithRandom(
RSAKeyGeneratorParameters(BigInt.parse('65537'), keySize, 64),
secureRandom,
),
);
// Generate key pair
final keyPair = keyGen.generateKeyPair();
final rsaPublicKey = keyPair.publicKey as RSAPublicKey;
final rsaPrivateKey = keyPair.privateKey as RSAPrivateKey;
final rsaPublicKey = keyPair.publicKey;
final rsaPrivateKey = keyPair.privateKey;
// Export to PEM format
final publicKeyPem = _encodeRSAPublicKey(rsaPublicKey);
final privateKeyPem = _encodeRSAPrivateKey(rsaPrivateKey);
return RsaKeyPairResult(
publicKey: publicKeyPem,
privateKey: privateKeyPem,
@@ -59,18 +61,18 @@ class EncryptionFlutterService {
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(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);
@@ -86,27 +88,27 @@ class EncryptionFlutterService {
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-----';
@@ -122,24 +124,24 @@ class EncryptionFlutterService {
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),
);
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);
return base64Encode(combined);
} catch (e) {
throw Exception('Failed to encrypt private key: $e');
@@ -154,25 +156,25 @@ class EncryptionFlutterService {
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),
);
final decrypted = encryptor.decrypt(
encrypt_pkg.Encrypted(encBytes),
iv: encrypt_pkg.IV(iv),
);
return decrypted;
} catch (e) {
throw Exception('Failed to decrypt private key: $e');
@@ -185,11 +187,8 @@ class EncryptionFlutterService {
SessionKeyResult generateSessionKey({int initialRound = 1}) {
final keyBytes = _generateSecureRandomBytes(sessionKeySize);
final key = base64Encode(keyBytes);
return SessionKeyResult(
key: key,
round: initialRound,
);
return SessionKeyResult(key: key, round: initialRound);
}
/// Encrypt session key with RSA public key
@@ -200,11 +199,11 @@ class EncryptionFlutterService {
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));
final encryptedBytes = cipher.process(utf8.encode(sessionKey));
return base64Encode(encryptedBytes);
} catch (e) {
@@ -220,11 +219,11 @@ class EncryptionFlutterService {
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));
final decryptedBytes = cipher.process(base64Decode(encryptedSessionKey));
return utf8.decode(decryptedBytes);
} catch (e) {
@@ -243,30 +242,27 @@ class EncryptionFlutterService {
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),
);
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);
final data = base64Encode(combined);
return EncryptedMessageResult(
round: round,
data: data,
);
return EncryptedMessageResult(round: round, data: data);
} catch (e) {
throw Exception('Failed to encrypt message: $e');
}
@@ -281,25 +277,25 @@ class EncryptionFlutterService {
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),
);
final decrypted = encryptor.decrypt(
encrypt_pkg.Encrypted(encBytes),
iv: encrypt_pkg.IV(iv),
);
return decrypted;
} catch (e) {
throw Exception('Failed to decrypt message: $e');
@@ -316,36 +312,34 @@ class EncryptionFlutterService {
String? _aesSecret;
/// Decrypt push notification (AES-GCM)
String decryptPushNotification({
required String encryptedData,
}) {
String decryptPushNotification({required String encryptedData}) {
try {
final secret = _aesSecret;
if (secret == null) {
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),
);
final decrypted = encryptor.decrypt(
encrypt_pkg.Encrypted(encBytes),
iv: encrypt_pkg.IV(iv),
);
return decrypted;
} catch (e) {
throw Exception('Failed to decrypt push notification: $e');
@@ -375,10 +369,10 @@ class EncryptionFlutterService {
Uint8List _deriveKeyForRound(String sessionKey, int targetRound) {
// Base64 decode session key
final keyBytes = base64Decode(sessionKey);
// Apply MD5 for the round (simplified version)
final hash = md5.convert(keyBytes).bytes as Uint8List;
return hash;
}
@@ -390,19 +384,19 @@ class EncryptionFlutterService {
.replaceAll('\n', '')
.trim();
final bytes = base64Decode(base64);
// Parse ASN.1 DER format
final asn1Parser = ASN1Parser(Uint8List.fromList(bytes));
final topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
final subjectPublicKeyInfo = topLevelSeq.elements[1] as ASN1BitString;
final keyBytes = subjectPublicKeyInfo.contentBytes();
final keyParser = ASN1Parser(Uint8List.fromList(keyBytes));
final keySeq = keyParser.nextObject() as ASN1Sequence;
final modulus = keySeq.elements[0] as ASN1Integer;
final publicExponent = keySeq.elements[1] as ASN1Integer;
return RSAPublicKey(
modulus.valueAsBigInteger,
publicExponent.valueAsBigInteger,
@@ -417,11 +411,11 @@ class EncryptionFlutterService {
.replaceAll('\n', '')
.trim();
final bytes = base64Decode(base64);
// Parse ASN.1 DER format
final asn1Parser = ASN1Parser(Uint8List.fromList(bytes));
final keySeq = asn1Parser.nextObject() as ASN1Sequence;
final modulus = keySeq.elements[1] as ASN1Integer;
final privateExponent = keySeq.elements[3] as ASN1Integer;
final p = keySeq.elements[4] as ASN1Integer;
@@ -440,7 +434,9 @@ class EncryptionFlutterService {
final len = hex.length;
final data = Uint8List(len ~/ 2);
for (var i = 0; i < len; i += 2) {
data[i ~/ 2] = (int.parse(hex[i], radix: 16) << 4) + int.parse(hex[i + 1], radix: 16);
data[i ~/ 2] =
(int.parse(hex[i], radix: 16) << 4) +
int.parse(hex[i + 1], radix: 16);
}
return data;
}
@@ -468,4 +464,3 @@ class EncryptedMessageResult {
EncryptedMessageResult({required this.round, required this.data});
}