OpenHarmony + Flutter 混合开发深度实践:构建支持国密算法(SM2/SM3/SM4)与安全存储的金融级应用

引言

在金融、政务、能源等关键领域,数据安全已上升至国家战略层面。根据《商用密码管理条例》和《金融行业信息系统安全规范》,国产化应用必须:

  • 🔐 使用国家密码管理局认证的 SM2/SM3/SM4 算法
  • 📦 敏感数据不得明文存储
  • 🛡️ 密钥需通过硬件级安全环境(如 TEE/SE)保护
  • 🌐 通信链路需支持国密 SSL/TLS

然而,Flutter 官方仅支持国际通用加密算法(AES/RSA/SHA256),且其 shared_preferencessqflite 等插件默认不加密 ;而 OpenHarmony 提供了完整的 国密算法库安全存储能力(Security Level S2/S3),但缺乏跨端 UI 支持。

本文将教你如何:

在 Flutter 中调用 OpenHarmony 国密算法服务

实现 SM2 非对称加密 + SM4 对称加密混合方案

利用 RDB 安全等级(S2/S3)保护密钥与数据

构建一个"国产化移动银行"原型 ,支持 国密登录、加密交易、安全存储

所有代码基于 OpenHarmony API 10(4.1 SDK) + Flutter 3.19 + Riverpod ,已在搭载 TEE(可信执行环境) 的 RK3588 工业终端实测通过。


一、为什么不能直接用 Dart 加密库?

方案 是否支持国密 安全性 OpenHarmony 兼容性
encrypt / pointycastle ❌ 仅国际算法 软件实现,易被内存dump ✅ 可运行
自行实现 SM2/SM3/SM4(Dart) ✅ 理论可行 ⚠️ 密钥暴露在 Dart 堆栈 ❌ 不推荐
OpenHarmony @ohos.security.cryptoFramework ✅ 官方支持 ✅ 硬件级保护(若设备支持) ✅ 原生

🚫 结论必须通过 MethodChannel 调用 OpenHarmony 原生国密服务,确保密钥不出安全域。


二、整体安全架构

复制代码
┌───────────────────────┐
│     Flutter (Dart)    │
│ - UI 表单             │
│ - 调用 security_channel│ ← MethodChannel
└───────────▲───────────┘
            │
┌───────────┴───────────┐
│   OpenHarmony (ArkTS) │
│ - 封装 cryptoFramework│
│ - 安全生成/存储密钥   │
│ - 执行 SM2/SM3/SM4    │
└───────────▲───────────┘
            │
┌───────────┴───────────┐
│ OpenHarmony 安全子系统│
│ - TEE / SE(可选)    │
│ - 安全存储(S2/S3)   │
└───────────────────────┘

安全原则

  • 私钥永不离开安全环境
  • 敏感数据加密后存入 RDB S2 库
  • 通信使用 SM2 证书 + SM4 会话密钥

三、Step 1:生成并安全存储 SM2 密钥对

ArkTS:使用 cryptoFramework 生成密钥

typescript 复制代码
// service/CryptoService.ts
import cryptoFramework from '@ohos.security.cryptoFramework';

export class CryptoService {
  private keyPair: cryptoFramework.KeyPair | null = null;

  // 生成 SM2 密钥对(存储于安全环境)
  async generateSm2KeyPair(): Promise<void> {
    const sm2Generator = cryptoFramework.createAsyKeyGenerator('SM2');
    const options: cryptoFramework.AsyKeyGenSpec = {
      params: {
        curve: 'sm2p256v1' // 国密标准曲线
      }
    };
    
    this.keyPair = await sm2Generator.generateKeyPair(options);
    
    // 将公钥导出为 Base64(私钥不导出!)
    const pubKeyBlob = await this.keyPair.pubKey.getEncoded();
    console.log('公钥:', arrayBufferToBase64(pubKeyBlob.data));
  }

  // 获取公钥(用于发送给服务器)
  async getPublicKey(): Promise<string> {
    if (!this.keyPair) await this.generateSm2KeyPair();
    const blob = await this.keyPair!.pubKey.getEncoded();
    return arrayBufferToBase64(blob.data);
  }

  // 使用私钥签名(在安全环境中完成)
  async signWithSm2(data: string): Promise<string> {
    if (!this.keyPair) throw new Error('密钥未生成');
    
    const signer = cryptoFramework.createSign('SM2', 'SHA256'); // SM2 默认使用 SM3,此处兼容写法
    await signer.init(this.keyPair!.priKey);
    
    const dataUint8 = stringToUint8Array(data);
    await signer.update({ data: dataUint8 });
    
    const signature = await signer.sign();
    return arrayBufferToBase64(signature.data);
  }
}

🔒 关键点keyPair.priKeyOpaque 对象,无法导出原始字节,确保私钥安全。


四、Step 2:SM4 加密本地敏感数据

场景:加密用户身份证号、银行卡号

typescript 复制代码
// 使用 SM4 加密
async encryptWithSm4(plainText: string, keyAlias: string): Promise<string> {
  // 1. 从安全存储获取 SM4 密钥(或首次生成)
  let sm4Key = await this.loadOrCreateSm4Key(keyAlias);
  
  // 2. 创建加密器
  const cipher = cryptoFramework.createCipher('SM4_128|CBC|PKCS7');
  await cipher.init(cryptoFramework.CipherMode.ENCRYPT_MODE, sm4Key, {
    iv: new Uint8Array(16).fill(0) // 实际应使用随机 IV 并存储
  });
  
  // 3. 执行加密
  const plainData = stringToUint8Array(plainText);
  const encrypted = await cipher.doFinal({ data: plainData });
  
  return arrayBufferToBase64(encrypted.data);
}

// 安全存储 SM4 密钥(使用 RDB S2)
private async loadOrCreateSm4Key(alias: string): Promise<cryptoFramework.SymKey> {
  // 尝试从安全数据库读取
  const storedKey = await this.secureStorage.getKey(alias);
  if (storedKey) {
    return cryptoFramework.importSymKey(storedKey, 'SM4_128', 'RAW');
  }
  
  // 首次生成
  const generator = cryptoFramework.createSymKeyGenerator('SM4_128');
  const newKey = await generator.generateSymKey();
  
  // 导出并安全存储(实际应加密存储,此处简化)
  const keyBlob = await newKey.getEncoded();
  await this.secureStorage.saveKey(alias, keyBlob.data);
  
  return newKey;
}

五、Step 3:安全存储服务(RDB + Security Level S2)

typescript 复制代码
// service/SecureStorage.ts
import rdb from '@ohos.data.relationalStore';

const SECURE_STORE_CONFIG: rdb.StoreConfig = {
  name: 'secure_vault.db',
  securityLevel: rdb.SecurityLevel.S2, // 启用设备级加密
};

export class SecureStorage {
  private store: rdb.RdbStore | null = null;

  async init(context: any): Promise<void> {
    this.store = await rdb.getRdbStore(context, SECURE_STORE_CONFIG);
    await this.store.executeSql(`
      CREATE TABLE IF NOT EXISTS secure_items (
        alias TEXT PRIMARY KEY,
        encrypted_data TEXT NOT NULL,
        created_at INTEGER
      )
    `);
  }

  async saveItem(alias: string, encryptedData: string): Promise<void> {
    const values = new rdb.ValuesBucket();
    values.put('alias', alias);
    values.put('encrypted_data', encryptedData);
    values.put('created_at', Date.now());
    await this.store!.insertOrReplace('secure_items', values);
  }

  async getItem(alias: string): Promise<string | null> {
    const predicates = new rdb.RdbPredicates('secure_items')
      .equalTo('alias', alias);
    const resultSet = await this.store!.query(predicates);
    
    if (resultSet.goToFirstRow()) {
      const data = resultSet.getString(resultSet.getColumnIndex('encrypted_data'));
      resultSet.close();
      return data;
    }
    resultSet.close();
    return null;
  }
}

🔐 SecurityLevel 说明

  • S1:文件加密(依赖设备锁屏密码);
  • S2设备唯一密钥加密(即使 root 也无法解密);
  • S3TEE 内加密(最高安全等级,需硬件支持)。

六、Step 4:Flutter 端集成

定义安全通道

dart 复制代码
// lib/services/security_service.dart
class SecurityService {
  static const _channel = MethodChannel('com.example.security/crypto');

  // 获取 SM2 公钥(用于注册)
  static Future<String> getSm2PublicKey() async {
    return await _channel.invokeMethod('getPublicKey');
  }

  // 使用 SM2 私钥签名(用于登录)
  static Future<String> signLoginRequest(String requestId) async {
    return await _channel.invokeMethod('signWithSm2', requestId);
  }

  // 加密敏感字段
  static Future<String> encryptField(String field, String value) async {
    return await _channel.invokeMethod('encryptWithSm4', {
      'alias': 'user_$field',
      'plainText': value,
    });
  }

  // 解密
  static Future<String> decryptField(String field) async {
    return await _channel.invokeMethod('decryptWithSm4', 'user_$field');
  }
}

登录流程示例(国密认证)

dart 复制代码
// lib/pages/login_page.dart
Future<void> _loginWithSm2() async {
  // 1. 获取设备公钥(首次注册时上传至服务器)
  final publicKey = await SecurityService.getSm2PublicKey();

  // 2. 请求登录挑战(服务器返回 nonce)
  final nonce = await ApiService.requestLoginChallenge(publicKey);

  // 3. 用私钥签名 nonce
  final signature = await SecurityService.signWithSm2(nonce);

  // 4. 发送签名,服务器用公钥验签
  final token = await ApiService.verifySignature(signature);
  
  if (token != null) {
    // 登录成功
    ref.read(authProvider.notifier).setToken(token);
  }
}

存储银行卡号(加密)

dart 复制代码
// 保存时
final encryptedCard = await SecurityService.encryptField('bank_card', '6222********1234');
await ApiService.saveEncryptedCard(encryptedCard); // 上传至服务器(可选)

// 读取时(仅在安全页面显示)
final card = await SecurityService.decryptField('bank_card');
setState(() => _maskedCard = maskCard(card));

七、通信安全:国密 TLS(可选高级方案)

若服务器支持国密 SSL,可在 OpenHarmony 侧配置:

typescript 复制代码
// 网络请求时指定国密套件
const request = http.createHttp();
request.setCipherSuites(['ECDHE-SM2-WITH-SM4-SM3']); // 需服务器支持

⚠️ 注意 :目前主流云厂商尚未全面支持国密 TLS,通常采用 "SM2 签名 + 国际 TLS" 混合方案过渡。


八、安全审计与合规检查

  1. 禁止日志打印敏感信息

    typescript 复制代码
    // 错误:console.log('卡号:', cardNumber);
    // 正确:仅记录操作ID
  2. 内存清理

    dart 复制代码
    // Dart 层使用完立即置空
    String? sensitiveData = ...;
    // 使用后
    sensitiveData = null;
  3. 防截屏/录屏

    typescript 复制代码
    // EntryAbility.onCreate()
    window.setWindowPrivacyMode(true); // OpenHarmony 隐私模式

九、总结:打造真正自主可控的金融应用

通过本文,你已掌握:

调用 OpenHarmony 原生国密算法

实现 SM2/SM4 混合加密体系

利用 RDB S2/S3 安全存储

构建符合等保2.0/商密规范的应用

🏦 适用场景

  • 移动银行 / 证券 APP
  • 政务身份认证
  • 电力/能源工控终端
  • 医疗健康数据采集

在信创浪潮下,安全不是功能,而是底线 。只有深度融合 OpenHarmony 安全能力与 Flutter 跨端优势,才能构建真正 "自主、安全、可用" 的国产化行业应用。


https://openharmonycrossplatform.csdn.net/content

相关推荐
不能只会打代码1 小时前
蓝桥杯---垒骰子(Java实现,代码注释,图文讲解)
算法·蓝桥杯·动态规划·垒骰子
500841 小时前
鸿蒙 Flutter 接入鸿蒙系统能力:通知(本地 / 推送)与后台任务
java·flutter·华为·性能优化·架构
帅气马战的账号1 小时前
开源鸿蒙Flutter原生增强组件:7类高频场景解决方案,极致轻量+深度适配
flutter
数据门徒1 小时前
《人工智能现代方法(第4版)》 第9章 一阶逻辑中的推断 学习笔记
人工智能·笔记·学习·算法
ujainu1 小时前
Flutter与DevEco Studio协同开发:轻量化实战指南
flutter
喜欢吃燃面1 小时前
算法竞赛之排序算法
c++·学习·算法
秋深枫叶红1 小时前
嵌入式第三十篇——数据结构——哈希表
数据结构·学习·算法·哈希算法
Keep__Fighting1 小时前
【机器学习:决策树】
人工智能·算法·决策树·机器学习·scikit-learn
小白|1 小时前
OpenHarmony + Flutter 混合开发实战:深度集成 AI Kit 实现端侧图像识别与智能分析
人工智能·flutter