Flutter for OpenHarmony实现 RSA 加密:从数学原理到可视化演示

Flutter for OpenHarmony实现 RSA 加密:从数学原理到可视化演示

RSA 是现代密码学的基石之一,支撑着 HTTPS、数字签名、安全通信等无数关键应用。然而,其背后的数学原理------大数分解、模幂运算、欧拉定理------常令人望而生畏。本文将通过一段完整的 Flutter 代码,带你亲手构建一个交互式 RSA 加密演示器。它不仅实现了核心算法,还以直观的 UI 展示了"公钥加密、私钥解密"的全过程。这是一次从抽象数学到具体代码的精彩转化。

🌐 加入社区 欢迎加入 开源鸿蒙跨平台开发者社区 ,获取最新资源与技术支持: 👉 开源鸿蒙跨平台开发者社区


完整效果展示

一、整体架构:教学导向的设计

该应用围绕 RSA 的五步核心流程 构建:

  1. 输入两个质数 p 和 q
  2. 计算模数 n = p × q 和欧拉函数 φ(n) = (p-1)(q-1)
  3. 选择公钥指数 e(与 φ(n) 互质)
  4. 计算私钥指数 d(e 关于 φ(n) 的模逆元)
  5. 执行加密(c = m^e mod n)与解密(m = c^d mod n)

💡 设计目标:所有步骤在客户端完成,无需网络,确保教学纯粹性;UI 实时响应,输入即计算。


二、核心数学工具:纯 Dart 实现

1. 质数判断 _isPrime()

dart 复制代码
bool _isPrime(int n) {
  if (n < 2) return false;
  if (n == 2) return true;
  if (n % 2 == 0) return false;
  for (int i = 3; i <= sqrt(n); i += 2) {
    if (n % i == 0) return false;
  }
  return true;
}
  • 效率优化 :跳过偶数,仅检查至 √n;
  • 教学用途:适用于小质数(如 61, 53),真实场景需米勒-拉宾等概率算法。

2. 扩展欧几里得算法 _modInverse()

dart 复制代码
int _modInverse(int a, int m) {
  // 求 x 使得 (a * x) % m == 1
  int m0 = m, y = 0, x = 1;
  while (a > 1) {
    int q = a ~/ m;
    (a, m) = (m, a % m);
    (x, y) = (y, x - q * y);
  }
  return x < 0 ? x + m0 : x;
}
  • 关键作用 :计算私钥 d = e⁻¹ mod φ(n);
  • 数学基础 :贝祖等式 ax + my = gcd(a, m),当 gcd=1 时 x 即为模逆元。

3. 快速模幂运算 _modExp()

dart 复制代码
int _modExp(int base, int exp, int mod) {
  int result = 1;
  base = base % mod;
  while (exp > 0) {
    if (exp % 2 == 1) result = (result * base) % mod; // 奇数次幂
    exp >>= 1; // exp /= 2
    base = (base * base) % mod; // 平方底数
  }
  return result;
}
  • 防溢出 :避免直接计算 base^exp(会迅速超出整数范围);
  • 时间复杂度:O(log exp),使大指数运算可行。

三、RSA 核心逻辑:五步实现

1. 密钥生成

dart 复制代码
// 用户输入 p=61, q=53
int n = p * q; // 3233
int phi = (p - 1) * (q - 1); // 3120

// 选择 e(常用 65537,若太大则用 3)
int e = _gcd(65537, phi) == 1 ? 65537 : 3;

// 计算 d = e⁻¹ mod φ(n)
int d = _modInverse(e, phi); // 如 e=17 → d=2753
  • 公钥 :(e, n)
  • 私钥 :(d, n)

2. 加密与解密

dart 复制代码
// 加密 "Hello" → [72, 101, 108, 108, 111]
List<int> encrypted = messageBytes.map((b) => _modExp(b, e, n)).toList();

// 解密
List<int> decrypted = encrypted.map((c) => _modExp(c, d, n)).toList();
String result = String.fromCharCodes(decrypted); // "Hello"
  • 逐字节处理:将字符串转为 ASCII 码列表;
  • 完美还原 :验证 m = (m^e)^d mod n 成立。

四、用户界面:玻璃拟态 + 教学友好

1. 深色渐变背景

dart 复制代码
decoration: BoxDecoration(
  gradient: LinearGradient(
    colors: [Colors.deepPurple.shade900, Colors.blue.shade900, ...],
  ),
)
  • 科技感:紫→蓝渐变呼应"加密"主题;
  • 可读性:白色文字在深色背景上清晰易读。

2. 四大信息模块

▶ 输入配置区
  • 明文消息:默认 "Hello",支持任意文本;
  • 质数 P/Q:默认 61/53(经典教学组合),实时校验是否为质数;
  • 即时反馈:任一输入变化,自动重新计算。
▶ 密钥信息区
  • 模数 (n) :动态显示 p × q;
  • 公钥/私钥 :格式化为 (e, n) 和 (d, n);
  • 色彩编码 :
    • 公钥:绿色(公开、安全)
    • 私钥:橙色(私有、敏感)
▶ 加密结果区
  • 密文 :以逗号分隔的整数列表(如 2790, 1234, ...);
  • 解密后:还原的原始消息;
  • 字体 :使用等宽字体 Courier,便于对齐数字。
▶ 安全提示区

⚠️ 注意:此演示使用小质数,仅用于教学。实际应用使用 2048 位以上的大质数。

  • 明确边界:防止用户误以为可投入生产环境。

3. 交互细节

  • 玻璃拟态卡片:半透明背景 + 白色边框,层次分明;
  • 聚焦高亮:输入框获得焦点时边框变青色;
  • 可选中文本:密钥和密文支持长按复制。

五、教育价值:揭开非对称加密的面纱

这个演示器精准传达了 RSA 的三大核心思想:

概念 本应用体现
单向陷门函数 已知 p,q 易算 n;但已知 n 难分解 p,q(小数例外)
公私钥分离 公钥 (e,n) 可公开用于加密;私钥 (d,n) 必须保密用于解密
数学之美 欧拉定理保证 m^(ed) ≡ m mod n,使加解密可逆

正如 Rivest、Shamir 和 Adleman 在 1977 年所展示的:数论可以成为守护信息安全的盾牌。本应用正是这一伟大思想的微型重现。


六、局限性与改进方向

当前限制:

  1. 仅支持 ASCII 字符:无法处理 Unicode(如中文);
  2. 小整数限制 :Dart int 在 Web 上为 53 位,p*q 过大会溢出;
  3. 无填充方案:真实 RSA 使用 OAEP/PKCS#1 填充防攻击。

改进建议:

  • 引入 BigInt:支持任意精度整数,突破 53 位限制;
  • Base64 编码:将密文转为可读字符串;
  • 密钥导出:允许保存/加载密钥对;
  • 攻击演示:展示小质数如何被快速分解(教学用)。

结语:人人皆可理解的密码学

这个 Flutter 应用证明了一件事:最前沿的密码学,也可以被拆解为清晰的代码和直观的界面。当你输入 "Hello",看到它变成一串神秘数字,再完美还原时,你不仅见证了 RSA 的魔力,更触摸到了现代数字信任的根基。

完整代码

bash 复制代码
import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(const CryptoApp());
}

class CryptoApp extends StatelessWidget {
  const CryptoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'RSA 加密演示',
      theme: ThemeData.dark(),
      home: const RSAScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class RSAScreen extends StatefulWidget {
  const RSAScreen({super.key});

  @override
  State<RSAScreen> createState() => _RSAScreenState();
}

class _RSAScreenState extends State<RSAScreen> {
  final TextEditingController _messageController =
      TextEditingController(text: 'Hello');
  final TextEditingController _pController = TextEditingController(text: '61');
  final TextEditingController _qController = TextEditingController(text: '53');

  String _publicKey = '';
  String _privateKey = '';
  String _encryptedMessage = '';
  String _decryptedMessage = '';

  // --- 核心数学工具 ---
  // 判断质数
  bool _isPrime(int n) {
    if (n < 2) return false;
    if (n == 2) return true;
    if (n % 2 == 0) return false;
    for (int i = 3; i <= sqrt(n); i += 2) {
      if (n % i == 0) return false;
    }
    return true;
  }

  // 生成质数 (简单版本,实际应用需要更复杂的随机生成)
  int _generatePrime(int min, int max) {
    final random = Random();
    while (true) {
      int candidate = min + random.nextInt(max - min);
      if (_isPrime(candidate)) return candidate;
    }
  }

  // 最大公约数
  int _gcd(int a, int b) {
    while (b != 0) {
      int temp = b;
      b = a % b;
      a = temp;
    }
    return a;
  }

  // 扩展欧几里得算法 (求模逆元)
  int _modInverse(int a, int m) {
    int m0 = m;
    int y = 0, x = 1;
    if (m == 1) return 0;

    while (a > 1) {
      int q = a ~/ m;
      int t = m;
      m = a % m;
      a = t;
      t = y;
      y = x - q * t;
      x = t;
    }

    if (x < 0) x += m0;
    return x;
  }

  // 快速模幂运算 (防止溢出)
  int _modExp(int base, int exp, int mod) {
    int result = 1;
    base = base % mod;
    while (exp > 0) {
      if (exp % 2 == 1) {
        result = (result * base) % mod;
      }
      exp = exp >> 1;
      base = (base * base) % mod;
    }
    return result;
  }

  // --- RSA 核心逻辑 ---
  void _performRSA() {
    try {
      // 1. 获取用户输入的 p 和 q
      int p = int.parse(_pController.text);
      int q = int.parse(_qController.text);
      String message = _messageController.text;

      if (!_isPrime(p) || !_isPrime(q)) {
        throw Exception('P 和 Q 必须是质数');
      }

      // 2. 计算 n = p * q
      int n = p * q;

      // 3. 计算欧拉函数 φ(n) = (p-1)*(q-1)
      int phi = (p - 1) * (q - 1);

      // 4. 选择公钥指数 e (1 < e < φ, 且 gcd(e, φ) = 1)
      int e = 65537; // 常用值
      if (e >= phi || _gcd(e, phi) != 1) {
        // 如果常用值太大,找一个较小的
        e = 3;
        while (e < phi) {
          if (_gcd(e, phi) == 1) break;
          e += 2;
        }
      }

      // 5. 计算私钥指数 d (d 是 e 关于模 φ 的乘法逆元)
      int d = _modInverse(e, phi);

      // 设置显示密钥
      setState(() {
        _publicKey = '($e, $n)';
        _privateKey = '($d, $n)';
      });

      // --- 加密过程 ---
      // 将字符串转换为字节,然后转换为整数
      List<int> messageBytes = message.codeUnits;
      List<int> encryptedInts = [];

      for (int byte in messageBytes) {
        // 加密: ciphertext = plaintext^e mod n
        int cipher = _modExp(byte, e, n);
        encryptedInts.add(cipher);
      }

      setState(() {
        _encryptedMessage = encryptedInts.join(', ');
      });

      // --- 解密过程 ---
      List<int> decryptedBytes = [];
      for (int cipher in encryptedInts) {
        // 解密: plaintext = ciphertext^d mod n
        int plain = _modExp(cipher, d, n);
        decryptedBytes.add(plain);
      }

      String decryptedStr = String.fromCharCodes(decryptedBytes);
      setState(() {
        _decryptedMessage = decryptedStr;
      });
    } catch (e) {
      setState(() {
        _publicKey = '错误';
        _privateKey = '错误';
        _encryptedMessage = '错误: $e';
        _decryptedMessage = '';
      });
    }
  }

  @override
  void initState() {
    super.initState();
    _performRSA();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        title: const Text(
          'RSA 非对称加密',
          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24),
        ),
        centerTitle: true,
        elevation: 0,
        backgroundColor: Colors.transparent,
      ),
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              Colors.deepPurple.shade900,
              Colors.blue.shade900,
              Colors.indigo.shade900,
            ],
          ),
        ),
        child: SafeArea(
          child: Padding(
            padding:
                const EdgeInsets.symmetric(horizontal: 20.0, vertical: 16.0),
            child: SingleChildScrollView(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  // 标题区域
                  Container(
                    padding: const EdgeInsets.all(20.0),
                    decoration: BoxDecoration(
                      color: Colors.white.withOpacity(0.1),
                      borderRadius: BorderRadius.circular(20),
                      border: Border.all(
                        color: Colors.white.withOpacity(0.2),
                        width: 1,
                      ),
                    ),
                    child: Column(
                      children: const [
                        Icon(
                          Icons.security_rounded,
                          size: 60,
                          color: Colors.white,
                        ),
                        SizedBox(height: 12),
                        Text(
                          'RSA 加密演示',
                          style: TextStyle(
                            fontSize: 28,
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                          ),
                        ),
                        SizedBox(height: 8),
                        Text(
                          '非对称加密算法 - 公钥加密,私钥解密',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            fontSize: 14,
                            color: Colors.white70,
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 24),

                  // 输入区域
                  _buildGlassCard(
                    title: '输入配置',
                    icon: Icons.input,
                    children: [
                      _buildTextField(
                        controller: _messageController,
                        label: '明文消息',
                        hint: '输入要加密的消息',
                        icon: Icons.message,
                      ),
                      const SizedBox(height: 16),
                      Row(
                        children: [
                          Expanded(
                            child: _buildTextField(
                              controller: _pController,
                              label: '质数 P',
                              hint: '输入质数',
                              icon: Icons.numbers,
                              keyboardType: TextInputType.number,
                            ),
                          ),
                          const SizedBox(width: 16),
                          Expanded(
                            child: _buildTextField(
                              controller: _qController,
                              label: '质数 Q',
                              hint: '输入质数',
                              icon: Icons.numbers,
                              keyboardType: TextInputType.number,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),

                  const SizedBox(height: 24),

                  // 密钥信息
                  _buildGlassCard(
                    title: '密钥信息',
                    icon: Icons.key,
                    children: [
                      _buildKeyInfoRow(
                        label: '模数 (n)',
                        value:
                            '${(int.tryParse(_pController.text) ?? 0) * (int.tryParse(_qController.text) ?? 0)}',
                        color: Colors.cyan,
                      ),
                      const SizedBox(height: 12),
                      _buildKeyInfoRow(
                        label: '公钥',
                        value: _publicKey,
                        color: Colors.green,
                      ),
                      const SizedBox(height: 12),
                      _buildKeyInfoRow(
                        label: '私钥',
                        value: _privateKey,
                        color: Colors.orange,
                      ),
                    ],
                  ),

                  const SizedBox(height: 24),

                  // 加密结果
                  _buildGlassCard(
                    title: '加密结果',
                    icon: Icons.enhanced_encryption,
                    children: [
                      _buildResultSection(
                        label: '密文',
                        value: _encryptedMessage,
                        color: Colors.redAccent,
                      ),
                      const SizedBox(height: 16),
                      const Divider(color: Colors.white24),
                      const SizedBox(height: 16),
                      _buildResultSection(
                        label: '解密后',
                        value: _decryptedMessage,
                        color: Colors.greenAccent,
                      ),
                    ],
                  ),

                  const SizedBox(height: 20),

                  // 提示信息
                  Container(
                    padding: const EdgeInsets.all(16.0),
                    decoration: BoxDecoration(
                      color: Colors.yellow.withOpacity(0.1),
                      borderRadius: BorderRadius.circular(12),
                      border: Border.all(
                        color: Colors.yellow.withOpacity(0.3),
                        width: 1,
                      ),
                    ),
                    child: Row(
                      children: const [
                        Icon(Icons.info_outline, color: Colors.yellow),
                        SizedBox(width: 12),
                        Expanded(
                          child: Text(
                            '注意:此演示使用小质数,仅用于教学。实际应用使用 2048 位以上的大质数。',
                            style: TextStyle(
                              fontSize: 12,
                              color: Colors.yellowAccent,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildGlassCard({
    required String title,
    required IconData icon,
    required List<Widget> children,
  }) {
    return Container(
      padding: const EdgeInsets.all(20.0),
      decoration: BoxDecoration(
        color: Colors.white.withOpacity(0.1),
        borderRadius: BorderRadius.circular(20),
        border: Border.all(
          color: Colors.white.withOpacity(0.2),
          width: 1,
        ),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.2),
            blurRadius: 20,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Icon(icon, color: Colors.white, size: 24),
              const SizedBox(width: 12),
              Text(
                title,
                style: const TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
            ],
          ),
          const SizedBox(height: 16),
          ...children,
        ],
      ),
    );
  }

  Widget _buildTextField({
    required TextEditingController controller,
    required String label,
    required String hint,
    required IconData icon,
    TextInputType? keyboardType,
  }) {
    return TextField(
      controller: controller,
      keyboardType: keyboardType,
      onChanged: (_) => _performRSA(),
      style: const TextStyle(color: Colors.white),
      decoration: InputDecoration(
        labelText: label,
        hintText: hint,
        hintStyle: TextStyle(color: Colors.white.withOpacity(0.5)),
        labelStyle: const TextStyle(color: Colors.white70),
        prefixIcon: Icon(icon, color: Colors.white.withOpacity(0.7)),
        filled: true,
        fillColor: Colors.white.withOpacity(0.1),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
          borderSide: BorderSide(color: Colors.white.withOpacity(0.3)),
        ),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
          borderSide: BorderSide(color: Colors.white.withOpacity(0.3)),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
          borderSide: const BorderSide(color: Colors.cyanAccent, width: 2),
        ),
      ),
    );
  }

  Widget _buildKeyInfoRow({
    required String label,
    required String value,
    required Color color,
  }) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Colors.black.withOpacity(0.3),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            decoration: BoxDecoration(
              color: color.withOpacity(0.2),
              borderRadius: BorderRadius.circular(6),
            ),
            child: Text(
              label,
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: color,
                fontSize: 12,
              ),
            ),
          ),
          const SizedBox(width: 12),
          Expanded(
            child: SelectableText(
              value,
              style: const TextStyle(
                fontFamily: 'Courier',
                fontSize: 14,
                color: Colors.white,
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildResultSection({
    required String label,
    required String value,
    required Color color,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
              decoration: BoxDecoration(
                color: color.withOpacity(0.2),
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                label,
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  color: color,
                  fontSize: 14,
                ),
              ),
            ),
          ],
        ),
        const SizedBox(height: 12),
        Container(
          width: double.infinity,
          padding: const EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: Colors.black.withOpacity(0.3),
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: color.withOpacity(0.3)),
          ),
          child: SelectableText(
            value,
            style: TextStyle(
              fontFamily: 'Courier',
              fontSize: 12,
              color: color,
              height: 1.5,
            ),
          ),
        ),
      ],
    );
  }
}
相关推荐
sell-cloud3 小时前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
Navicat中国4 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI4 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区5 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris6 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy7 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V7 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI7 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技7 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人
海宇数据7 小时前
零信任架构实战:基于海宇网上踪迹欺诈行为识别构建自动化信贷资信评估网关
运维·人工智能·架构·自动化