Files
customer-im-client-dev/packages/cipher_guard_sdk
pp-bot 52a3f0f45c
Some checks failed
CI / Lint (push) Has been cancelled
feat(e2e): 端对端加密完全对齐老项目 — cipher_guard_sdk 修正 + EncryptionManager 集成
修正 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>
2026-04-14 21:44:00 +09:00
..
2026-03-07 19:29:18 +08:00
2026-03-06 15:05:53 +08:00
2026-03-07 19:29:18 +08:00
2026-03-06 15:05:53 +08:00
2026-03-06 15:05:53 +08:00
2026-03-06 15:05:53 +08:00
2026-03-06 15:05:53 +08:00
2026-03-06 15:05:53 +08:00
2026-03-06 15:05:53 +08:00

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 的範例應用程式截圖,展示各種功能設定介面:

CipherGuard SDK Example

圖片說明:

  • 生成 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+ CapabilityApp 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'),
                    ),
                  ],
                ),
        ),
      ),
    );
  }
}

安全性說明

金鑰管理

  1. RSA 私鑰保護:私鑰必須使用強密碼加密後存儲
  2. 會話金鑰:每個聊天室應使用獨立的會話金鑰
  3. 金鑰輪換:透過 round 值實現金鑰輪換

加密算法

功能 算法 模式 說明
RSA 金鑰生成 RSA - 支援 1024/2048 位元
私鑰加密 AES CBC 使用 MD5(password) 作為金鑰
會話金鑰加密 RSA PKCS1 標準 RSA 加密
訊息加密 AES CTR 高效流式加密
推送解密 AES GCM 帶認證的加密

版本歷史

版本 日期 說明
0.0.1 01/30/2026 相關金鑰生成

許可協議

MIT License