修正 cipher_guard_sdk 4 个关键密码学差异使其与老 Flutter 项目 (im-client-im-dev) 和 iOS
EncryptionManager 完全互操作:
1. AES: 显式 SIC/CTR 模式 + 16 zero-byte IV(原 SDK 用随机 IV + KDF 派生密钥)
2. RSA: bare RSAEngine 无 PKCS1 padding(原 SDK 用 PKCS1Encoding)
3. Session key: 32-char alphanumeric ASCII(原 SDK 用 base64 random bytes)
4. Wire format: base64(ciphertext) 无 IV 前缀
新增 EncryptionManager:
- Per-chat round-based key chain(最多 10 rounds/chat,FIFO 淘汰)
- 登录后自动 setup:RSA 密钥对生成/存储 + 公钥上传 + chat 密钥拉取解密
- API 集成:cipher/v2/key/my, key/set, chat/my
- 消息加密返回 JSON envelope {"round":N,"data":"<base64>"}
- 消息解密兼容 JSON envelope + legacy raw base64
集成到消息流:
- SendMessageUseCase: 发送前加密 content → wireContent
- WsMessageService: 收到消息后解密 content + lastMsg
- 无密钥时 fallback 到明文(对齐 iOS 行为)
注意:/app/api/cipher/v2/key/set 仍为预发布接口,仅测试阶段使用
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CipherGuard SDK API Documentation
概述
CipherGuard SDK 是一個 Flutter 外掛,提供完整的端對端加密(E2EE)解決方案。該 SDK 簡化了加密整合流程,提供 RSA 金鑰管理、AES 會話金鑰管理、訊息加解密等功能。
主要特性
- 統一 API 介面 - 簡潔的抽象類設計,易於整合和使用
- 跨平台加密 - 所有加密邏輯在 Flutter 層實現,Android 和 iOS 保持一致
- RSA 金鑰管理 - 生成、加密/解密私鑰
- AES 會話金鑰 - 每個聊天室獨立的安全會話金鑰
- 訊息加解密 - 使用 AES-CTR 模式進行高效加密
- 推送通知解密 - 支援 AES-GCM 模式解密推播通知
- 原生平台同步 - 支援 iOS App Group 同步加密金鑰
Demo螢幕截圖
以下為 CipherGuard SDK 的範例應用程式截圖,展示各種功能設定介面:
圖片說明:
- 生成 RSA 金鑰對:產生 RSA Public / Private Key
- 加密私鑰:使用使用者密碼對 RSA 私鑰進行加密
- 解密私鑰:驗證加密後私鑰是否能正確還原
- 生成會話金鑰:產生聊天室專用的 AES Session Key
- 加密會話金鑰:使用 RSA 公鑰加密 Session Key(模擬金鑰交換)
- 解密會話金鑰:使用 RSA 私鑰解密 Session Key
- 加密訊息:使用 AES-CTR 模式加密文字訊息
- 解密訊息:解密加密後的訊息內容
- 畫面中顯示 解密結果:Hello, this is a secret message!,代表端對端加解密流程成功
- 同步加密金鑰到原生:將聊天室金鑰同步至原生平台(例如 iOS App Group)
- 用於支援 Notification Service Extension 或其他原生模組存取加密金鑰
- 設定 AES_SECRET:設定用於推送通知 AES-GCM 解密的密鑰
- 對應實際 APNS 推送通知加密 / 解密使用情境
API 總覽
<style> table { font-size: 14px; } td, th { padding: 8px; } </style>方法(Methods)
| 方法 | 回傳類型 | 說明 |
|---|---|---|
platformVersion() |
Future<String?> |
獲取平台版本 |
generateRsaKeyPair({int keySize = 1024}) |
Future<RsaKeyPair> |
生成 RSA 金鑰對 |
encryptPrivateKey({required String privateKey, required String password}) |
Future<String> |
用密碼加密私鑰 |
decryptPrivateKey({required String encryptedPrivateKey, required String password}) |
Future<String> |
解密私鑰 |
generateSessionKey({int initialRound = 1}) |
Future<SessionKey> |
生成 AES 會話金鑰 |
encryptSessionKey({required String sessionKey, required String publicKey}) |
Future<String> |
用 RSA 公鑰加密會話金鑰 |
decryptSessionKey({required String encryptedSessionKey, required String privateKey}) |
Future<String> |
用 RSA 私鑰解密會話金鑰 |
encryptMessage({required String plaintext, required String sessionKey, required int round}) |
Future<EncryptedMessage> |
加密訊息 |
decryptMessage({required String encryptedData, required String sessionKey, required int round}) |
Future<String> |
解密訊息 |
syncEncryptionKey({required String chatId, required int activeRound, required int round, required String activeKeySingle}) |
, required bool is Future<void> |
同步加密金鑰到原生平台 |
syncAllEncryptionKeys({required Map<String, Map<String, dynamic>> chatMap}) |
Future<void> |
批量同步所有加密金鑰 |
setAesSecret({required String aesSecret}) |
Future<void> |
設置 AES_SECRET |
decryptPushNotification({required String encryptedData}) |
Future<String?> |
解密推送通知 |
實體類別(Entities)
| 類別 | 說明 |
|---|---|
RsaKeyPair |
RSA 金鑰對(公鑰/私鑰) |
SessionKey |
AES 會話金鑰 |
EncryptedMessage |
加密訊息 |
安裝
在 pubspec.yaml 中新增依賴:
dependencies:
cipher_guard_sdk: ^1.0.0
Flutter 安裝
執行以下命令獲取依賴:
flutter pub get
初始化
在 main.dart 中初始化 SDK:
import 'package:cipher_guard_sdk/cipher_guard_sdk.dart';
快速開始
1. 初始化 SDK
import 'package:flutter/material.dart';
import 'package:cipher_guard_sdk/cipher_guard_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final CipherGuardSdkApi cipherGuard = CipherGuardSdkApi();
@override
void initState() {
super.initState();
_testEncryption();
}
Future<void> _testEncryption() async {
try {
// 1. 生成 RSA 金鑰對
final keyPair = await cipherGuard.generateRsaKeyPair(keySize: 1024);
print('Public Key: ${keyPair.publicKey}');
print('Private Key: ${keyPair.privateKey}');
// 2. 用密碼加密私鑰
const password = 'user_password_123';
final encryptedPrivateKey = await cipherGuard.encryptPrivateKey(
privateKey: keyPair.privateKey,
password: password,
);
print('Encrypted Private Key: $encryptedPrivateKey');
// 3. 解密私鑰
final decryptedPrivateKey = await cipherGuard.decryptPrivateKey(
encryptedPrivateKey: encryptedPrivateKey,
password: password,
);
print('Decrypted Private Key: $decryptedPrivateKey');
// 4. 生成會話金鑰
final sessionKey = await cipherGuard.generateSessionKey(initialRound: 1);
print('Session Key: ${sessionKey.key}');
print('Session Round: ${sessionKey.round}');
// 5. 用 RSA 公鑰加密會話金鑰
final encryptedSessionKey = await cipherGuard.encryptSessionKey(
sessionKey: sessionKey.key,
publicKey: keyPair.publicKey,
);
print('Encrypted Session Key: $encryptedSessionKey');
// 6. 用 RSA 私鑰解密會話金鑰
final decryptedSessionKey = await cipherGuard.decryptSessionKey(
encryptedSessionKey: encryptedSessionKey,
privateKey: keyPair.privateKey,
);
print('Decrypted Session Key: $decryptedSessionKey');
// 7. 加密訊息
const message = 'Hello, this is a secret message!';
final encryptedMessage = await cipherGuard.encryptMessage(
plaintext: message,
sessionKey: sessionKey.key,
round: sessionKey.round,
);
print('Encrypted Message: ${encryptedMessage.data}');
print('Message Round: ${encryptedMessage.round}');
// 8. 解密訊息
final decryptedMessage = await cipherGuard.decryptMessage(
encryptedData: encryptedMessage.data,
sessionKey: sessionKey.key,
round: encryptedMessage.round,
);
print('Decrypted Message: $decryptedMessage');
// 9. 設置 AES_SECRET 用於推送解密
await cipherGuard.setAesSecret(aesSecret: 'your_aes_secret_key_here');
print('All encryption tests passed!');
} catch (e) {
print('Encryption test failed: $e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('CipherGuard SDK Demo')),
body: const Center(
child: Text('CipherGuard SDK Demo'),
),
),
);
}
}
CipherGuardSdkApi 介面
CipherGuardSdkApi 是 SDK 的核心抽象類,提供了所有加密相關功能。
方法
platformVersion
Future<String?> platformVersion();
描述:獲取當前平台版本。
使用範例:
final version = await cipherGuard.platformVersion();
print('Platform Version: $version');
generateRsaKeyPair
Future<RsaKeyPair> generateRsaKeyPair({int keySize = 1024});
描述:生成 RSA 金鑰對。
參數:
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
keySize |
int |
1024 | RSA 金鑰長度(支援 1024、2048) |
使用範例:
final keyPair = await cipherGuard.generateRsaKeyPair(keySize: 2048);
print('Public Key: ${keyPair.publicKey}');
print('Private Key: ${keyPair.privateKey}');
返回結果:
| 屬性 | 類型 | 說明 |
|---|---|---|
publicKey |
String |
PEM 格式的公鑰 |
privateKey |
String |
PEM 格式的私鑰 |
encryptPrivateKey
Future<String> encryptPrivateKey({
required String privateKey,
required String password,
});
描述:使用密碼對 RSA 私鑰進行加密。採用 AES-CBC 模式,使用 MD5(password) 作為金鑰。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
privateKey |
String |
是 | PEM 格式的私鑰 |
password |
String |
是 | 用於加密的密碼 |
使用範例:
final encryptedKey = await cipherGuard.encryptPrivateKey(
privateKey: keyPair.privateKey,
password: 'user_password',
);
decryptPrivateKey
Future<String> decryptPrivateKey({
required String encryptedPrivateKey,
required String password,
});
描述:使用密碼解密 RSA 私鑰。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
encryptedPrivateKey |
String |
是 | Base64 編碼的加密私鑰 |
password |
String |
是 | 用於解密的密碼 |
使用範例:
final privateKey = await cipherGuard.decryptPrivateKey(
encryptedPrivateKey: encryptedKey,
password: 'user_password',
);
generateSessionKey
Future<SessionKey> generateSessionKey({int initialRound = 1});
描述:生成 AES 會話金鑰(32 字節隨機金鑰)。
參數:
| 參數 | 類型 | 預設值 | 說明 |
|---|---|---|---|
initialRound |
int |
1 | 初始 round 值 |
使用範例:
final sessionKey = await cipherGuard.generateSessionKey(initialRound: 1);
print('Key: ${sessionKey.key}');
print('Round: ${sessionKey.round}');
返回結果:
| 屬性 | 類型 | 說明 |
|---|---|---|
key |
String |
Base64 編碼的 32 字節會話金鑰 |
round |
int |
金鑰 round 值 |
encryptSessionKey
Future<String> encryptSessionKey({
required String sessionKey,
required String publicKey,
});
描述:使用 RSA 公鑰加密會話金鑰。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
sessionKey |
String |
是 | Base64 編碼的會話金鑰 |
publicKey |
String |
是 | PEM 格式的 RSA 公鑰 |
使用範例:
final encryptedSessionKey = await cipherGuard.encryptSessionKey(
sessionKey: sessionKey.key,
publicKey: keyPair.publicKey,
);
decryptSessionKey
Future<String> decryptSessionKey({
required String encryptedSessionKey,
required String privateKey,
});
描述:使用 RSA 私鑰解密會話金鑰。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
encryptedSessionKey |
String |
是 | Base64 編碼的加密會話金鑰 |
privateKey |
String |
是 | PEM 格式的 RSA 私鑰 |
使用範例:
final decryptedKey = await cipherGuard.decryptSessionKey(
encryptedSessionKey: encryptedSessionKey,
privateKey: keyPair.privateKey,
);
encryptMessage
Future<EncryptedMessage> encryptMessage({
required String plaintext,
required String sessionKey,
required int round,
});
描述:使用 AES-CTR 模式加密訊息。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
plaintext |
String |
是 | 要加密的原始訊息 |
sessionKey |
String |
是 | Base64 編碼的會話金鑰 |
round |
int |
是 | 金鑰 round 值 |
使用範例:
final encryptedMessage = await cipherGuard.encryptMessage(
plaintext: 'Hello, World!',
sessionKey: sessionKey.key,
round: sessionKey.round,
);
print('Encrypted Data: ${encryptedMessage.data}');
返回結果:
| 屬性 | 類型 | 說明 |
|---|---|---|
round |
int |
金鑰 round 值 |
data |
String |
Base64 編碼的加密內容(IV + 加密資料) |
decryptMessage
Future<String> decryptMessage({
required String encryptedData,
required String sessionKey,
required int round,
});
描述:使用 AES-CTR 模式解密訊息。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
encryptedData |
String |
是 | Base64 編碼的加密資料 |
sessionKey |
String |
是 | Base64 編碼的會話金鑰 |
round |
int |
是 | 金鑰 round 值 |
使用範例:
final decrypted = await cipherGuard.decryptMessage(
encryptedData: encryptedMessage.data,
sessionKey: sessionKey.key,
round: encryptedMessage.round,
);
print('Decrypted: $decrypted');
syncEncryptionKey
Future<void> syncEncryptionKey({
required String chatId,
required int activeRound,
required int round,
required String activeKey,
required bool isSingle,
});
描述:同步單個聊天室的加密金鑰到原生平台(iOS App Group)。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
chatId |
String |
是 | 聊天室 ID |
activeRound |
int |
是 | 當前活躍的 round 值 |
round |
int |
是 | round 值 |
activeKey |
String |
是 | 活躍的加密金鑰 |
isSingle |
bool |
是 | 是否為單聊 |
使用範例:
await cipherGuard.syncEncryptionKey(
chatId: 'chat_123',
activeRound: 1,
round: 1,
activeKey: sessionKey.key,
isSingle: false,
);
syncAllEncryptionKeys
Future<void> syncAllEncryptionKeys({
required Map<String, Map<String, dynamic>> chatMap,
});
描述:批量同步所有加密聊天室的金鑰到原生平台。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
chatMap |
Map<String, Map<String, dynamic>> |
是 | 聊天室金鑰映射 |
使用範例:
final chatMap = {
'chat_1': {
'activeKey': sessionKey.key,
'activeRound': 1,
'round': 1,
'isSingle': false,
},
'chat_2': {
'activeKey': anotherKey.key,
'activeRound': 1,
'round': 1,
'isSingle': true,
},
};
await cipherGuard.syncAllEncryptionKeys(chatMap: chatMap);
setAesSecret
Future<void> setAesSecret({required String aesSecret});
描述:設置 AES_SECRET(用於推送通知解密)。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
aesSecret |
String |
是 | AES 密鑰(十六進制字串) |
使用範例:
await cipherGuard.setAesSecret(aesSecret: '0123456789abcdef');
decryptPushNotification
Future<String?> decryptPushNotification({required String encryptedData});
描述:解密 APNS 推送通知內容。使用 AES-GCM 模式。
參數:
| 參數 | 類型 | 必填 | 說明 |
|---|---|---|---|
encryptedData |
String |
是 | Base64 編碼的加密資料 |
使用範例:
final decrypted = await cipherGuard.decryptPushNotification(
encryptedData: pushNotificationData,
);
實體類別
RsaKeyPair
class RsaKeyPair {
final String publicKey;
final String privateKey;
const RsaKeyPair({
required this.publicKey,
required this.privateKey,
});
/// 檢查金鑰對是否有效
bool get isValid => publicKey.isNotEmpty && privateKey.isNotEmpty;
}
屬性說明:
| 屬性 | 類型 | 說明 |
|---|---|---|
publicKey |
String |
PEM 格式的 RSA 公鑰 |
privateKey |
String |
PEM 格式的 RSA 私鑰 |
isValid |
bool |
金鑰對是否有效 |
SessionKey
class SessionKey {
final String key; // Base64 編碼的 32 字節金鑰
final int round; // 金鑰輪換 round 值
const SessionKey({
required this.key,
required this.round,
});
}
屬性說明:
| 屬性 | 類型 | 說明 |
|---|---|---|
key |
String |
Base64 編碼的 32 字節 AES 會話金鑰 |
round |
int |
金鑰輪換 round 值 |
EncryptedMessage
class EncryptedMessage {
final int round; // 金鑰輪換 round 值
final String data; // Base64 編碼的加密內容
const EncryptedMessage({
required this.round,
required this.data,
});
/// 從 JSON 創建
factory EncryptedMessage.fromJson(Map<String, dynamic> json) {
return EncryptedMessage(
round: json['round'] as int,
data: json['data'] as String,
);
}
/// 轉換為 JSON
Map<String, dynamic> toJson() {
return {
'round': round,
'data': data,
};
}
}
屬性說明:
| 屬性 | 類型 | 說明 |
|---|---|---|
round |
int |
金鑰 round 值 |
data |
String |
Base64 編碼的加密內容 |
加密流程
訊息加密流程
1. 用戶 A 生成 RSA 金鑰對
├── publicKey_A (公開)
└── privateKey_A (保密,用密碼加密存儲)
2. 用戶 A 生成會話金鑰
└── sessionKey (每個聊天室獨立)
3. 用戶 A 用 RSA publicKey_B 加密會話金鑰
└── encryptedSessionKey (傳送給用戶 B)
4. 用戶 A 加密訊息
└── encryptMessage(plaintext, sessionKey, round)
└── EncryptedMessage(round, data)
訊息解密流程
1. 用戶 B 收到加密的會話金鑰
└── decryptSessionKey(encryptedSessionKey, privateKey_B)
2. 用戶 B 解密訊息
└── decryptMessage(encryptedData, sessionKey, round)
└── plaintext
iOS 設定
App Groups 設定
用於加密金鑰同步,需要設定 App Groups:
在 Xcode 中選擇你的主 Target:
- Signing & Capabilities → + Capability → App Groups
- 建立名為
group.com.example.cipherguard的 App Group
Android 設定
無需額外設定。SDK 使用 Flutter 層的加密邏輯。
完整範例
以下是一個完整的端對端加密聊天整合範例:
import 'package:flutter/material.dart';
import 'package:cipher_guard_sdk/cipher_guard_sdk.dart';
void main() {
runApp(const ChatApp());
}
class ChatApp extends StatefulWidget {
const ChatApp({super.key});
@override
State<ChatApp> createState() => _ChatAppState();
}
class _ChatAppState extends State<ChatApp> {
final CipherGuardSdkApi cipherGuard = CipherGuardSdkApi();
// 用戶的金鑰對
RsaKeyPair? _keyPair;
// 聊天室的會話金鑰
SessionKey? _sessionKey;
@override
void initState() {
super.initState();
_initializeEncryption();
}
Future<void> _initializeEncryption() async {
// 生成 RSA 金鑰對
_keyPair = await cipherGuard.generateRsaKeyPair(keySize: 2048);
// 生成會話金鑰
_sessionKey = await cipherGuard.generateSessionKey(initialRound: 1);
setState(() {});
}
Future<void> _sendMessage(String message) async {
if (_sessionKey == null) return;
// 加密訊息
final encrypted = await cipherGuard.encryptMessage(
plaintext: message,
sessionKey: _sessionKey!.key,
round: _sessionKey!.round,
);
// 發送 encrypted.round 和 encrypted.data 給對方
print('Sending encrypted message: ${encrypted.data}');
}
Future<String> _receiveMessage(String encryptedData, int round) async {
if (_sessionKey == null) return '';
// 解密訊息
final decrypted = await cipherGuard.decryptMessage(
encryptedData: encryptedData,
sessionKey: _sessionKey!.key,
round: round,
);
return decrypted;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('E2E Chat Demo')),
body: Center(
child: _keyPair == null
? const CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('RSA Key Generated: ${_keyPair!.publicKey.substring(0, 50)}...'),
const SizedBox(height: 20),
Text('Session Key: ${_sessionKey!.key.substring(0, 20)}...'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => _sendMessage('Hello, World!'),
child: const Text('Send Encrypted Message'),
),
],
),
),
),
);
}
}
安全性說明
金鑰管理
- RSA 私鑰保護:私鑰必須使用強密碼加密後存儲
- 會話金鑰:每個聊天室應使用獨立的會話金鑰
- 金鑰輪換:透過 round 值實現金鑰輪換
加密算法
| 功能 | 算法 | 模式 | 說明 |
|---|---|---|---|
| RSA 金鑰生成 | RSA | - | 支援 1024/2048 位元 |
| 私鑰加密 | AES | CBC | 使用 MD5(password) 作為金鑰 |
| 會話金鑰加密 | RSA | PKCS1 | 標準 RSA 加密 |
| 訊息加密 | AES | CTR | 高效流式加密 |
| 推送解密 | AES | GCM | 帶認證的加密 |
版本歷史
| 版本 | 日期 | 說明 |
|---|---|---|
| 0.0.1 | 01/30/2026 | 相關金鑰生成 |
許可協議
MIT License