Flutter加密插件flutter_chacha20_poly1305的使用

Flutter加密插件flutter_chacha20_poly1305的使用

要求

  1. 参考提供的内容和示例代码回答问题。
  2. 提供关于“Flutter加密插件flutter_chacha20_poly1305的使用”的完整示例demo。
  3. 内容中有图片的地方显示图片,内容中没有图片的地方不要添加图片。
  4. 内容中的英文介绍转换为简体中文,代码部分保持不变。
  5. 内容中的代码不需要翻译,代码部分尽量加上注释。

目录


需求

  • iOS >= 13.0
  • Android >= 26

安装

pubspec.yaml文件中添加以下依赖:

flutter pub add flutter_chacha20_poly1305

作者

Hayr Hotoca | @1limxapp
该插件被用于我的跨平台应用1LimX


许可

MIT


使用

加密
Future<Map?> encrypt(List<int> data, List<int> key)

此方法返回包含以下键的Map:
- encrypted: List<int>
- tag: List<int>
- nonce: List<int>

// tag: 认证标签或MAC(消息认证码),算法用它来验证密文(加密数据)和/或关联数据是否已被修改。

// nonce: (或“初始化向量”,“IV”,“盐”)是大多数密码算法所需的唯一非秘密数据序列,使得即使使用相同的密钥,密文(加密数据)也是唯一的。
加密字符串
Future<Map?> encryptString(String string, String key, String keyEncoding, String outputEncoding)

此方法接受UTF8字符串作为输入,密钥可以是base64或hex编码的字符串,具体取决于keyEncoding。

此方法返回包含以下键的Map:
- encrypted: String(根据outputEncoding的不同,可能是base64或hex编码的字符串)
- tag: String(根据outputEncoding的不同,可能是base64或hex编码的字符串)
- nonce: String(根据outputEncoding的不同,可能是base64或hex编码的字符串)
解密
Future<List<int>?> decrypt(List<int> encrypted, List<int> key, List<int> nonce, List<int> tag)

此方法返回List<int>
解密字符串
Future<String?> decryptString(String inputEncoding, String encryptedString, String key, String nonce, String tag)

此方法接受base64或hex编码的字符串作为输入,具体取决于inputEncoding。

此方法返回UTF8字符串

示例代码

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_chacha20_poly1305/flutter_chacha20_poly1305.dart';
import 'package:flutter_key_generator/flutter_key_generator.dart';

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void encryptAndDecrypt() async {
    try {
      final key = await FlutterKeyGenerator.generateSymmetricKey(256);

      print("256 bit key: ${key}");
      // 每次运行generateSymmetricKey时都会生成一个新的唯一密钥
      // [116, 89, 78, 246, 24, 145, 69, 153, 89, 21, 182, 39, 208, 83, 28, 190, 10, 254, 168, 181, 192, 9, 37, 129, 186, 197, 78, 107, 111, 196, 119, 250]

      if (key != null) {
        /*
        / 数据以字节形式加密:
        */
        print("=================================================================================================================================================");
        print("数据以字节形式加密:");
        final data = [1, 2, 3];
        final sealedBox = await FlutterChacha20Poly1305.encrypt(data, key);

        print("加密后的数据: ${sealedBox}");
        // 每次运行FlutterChacha20Poly1305.encrypt(data, key);时,此对象中的数据都是唯一的
        // {
        //   encrypted: [48, 140, 193],
        //   tag: [2, 233, 22, 168, 82, 89, 110, 176, 158, 180, 147, 83, 250, 56, 15, 97],
        //   nonce: [186, 194, 249, 80, 235, 2, 210, 108, 23, 3, 133, 172]
        // }

        final encrypted = [48, 140, 193];
        final uniqueKey = [116, 89, 78, 246, 24, 145, 69, 153, 89, 21, 182, 39, 208, 83, 28, 190, 10, 254, 168, 181, 192, 9, 37, 129, 186, 197, 78, 107, 111, 196, 119, 250];
        final nonce = [186, 194, 249, 80, 235, 2, 210, 108, 23, 3, 133, 172];
        final tag = [2, 233, 22, 168, 82, 89, 110, 176, 158, 180, 147, 83, 250, 56, 15, 97];

        final decryptedData = await FlutterChacha20Poly1305.decrypt(encrypted, uniqueKey, nonce, tag);
        print("解密后的字节: ${decryptedData} \n\n");
        // 解密后的字节: [1, 2, 3]

        /*
        / 以字符串形式加密数据,并且密钥、nonce、tag使用base64或hex编码:
        */

        print("=================================================================================================================================================");
        print("以字符串形式加密数据,并且密钥、nonce、tag使用base64或hex编码:");

        final jsonString = "{ x: 1, y: 2, z: 3 }";
        final keyInBase64 = "LAnIp48R+r525MH9kme671+2Z2sta+yRGGmA783KBl8=";
        final keyEncoding = "base64";
        final outputEncoding = "base64"; // 或 "hex"

        final encryptStringObject = await FlutterChacha20Poly1305.encryptString(jsonString, keyInBase64, keyEncoding, outputEncoding);
        print("加密后的字符串对象: ${encryptStringObject}");
        // 每次运行FlutterChacha20Poly1305.encryptString(jsonString, keyInBase64, keyEncoding, outputEncoding)时,此对象中的数据都是唯一的
        // {
        //   tag: T/dbBWayYCdN+yvOvGU61Q==,
        //   encrypted: +OxmNIVA6gvwOCoQJAalHQS4Baw=,
        //   nonce: j43/wSHX6Dh6jIAF
        // }

        final inputEncoding = "base64"; // 所有参数都必须是base64编码的字符串
        final encryptedString = "+OxmNIVA6gvwOCoQJAalHQS4Baw=";
        final tagBase64 = "T/dbBWayYCdN+yvOvGU61Q==";
        final nonceBase64 = "j43/wSHX6Dh6jIAF";

        final decryptedJSONString = await FlutterChacha20Poly1305.decryptString(inputEncoding, encryptedString, keyInBase64, nonceBase64, tagBase64);
        print("解密后的JSON字符串: ${decryptedJSONString}");
        // { x: 1, y: 2, z: 3 }
      }
    } catch (e) {
      print(e);
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例应用'),
        ),
        body: Center(
          child: Text('正在运行中'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: encryptAndDecrypt,
          tooltip: '加密和解密',
          child: const Icon(Icons.add),
        ), // 这个逗号使自动格式化更美观
      ),
    );
  }
}

更多关于Flutter加密插件flutter_chacha20_poly1305的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter加密插件flutter_chacha20_poly1305的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用flutter_chacha20_poly1305插件进行加密和解密的示例代码。这个插件基于ChaCha20-Poly1305算法,用于提供安全的加密和解密功能。

首先,确保你已经在你的pubspec.yaml文件中添加了flutter_chacha20_poly1305依赖项:

dependencies:
  flutter:
    sdk: flutter
  flutter_chacha20_poly1305: ^x.y.z  # 请替换为最新的版本号

然后运行flutter pub get来安装依赖项。

以下是一个完整的Flutter应用示例,展示如何使用flutter_chacha20_poly1305进行加密和解密:

import 'package:flutter/material.dart';
import 'package:flutter_chacha20_poly1305/flutter_chacha20_poly1305.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter ChaCha20-Poly1305 Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  final _key = Uint8List.fromList(List.generate(32, (i) => (i % 256).toByte())); // 256-bit key
  final _nonce = Uint8List.fromList(List.generate(12, (i) => (i % 256).toByte())); // 96-bit nonce
  String? _encryptedText;
  String? _decryptedText;

  void _encrypt() async {
    setState(() {
      _encryptedText = null;
      _decryptedText = null;
    });

    String plainText = _controller.text;
    Uint8List plainTextBytes = Uint8List.fromList(plainText.codeUnits);

    try {
      Uint8List encryptedBytes = await FlutterChacha20Poly1305.encrypt(
        plainTextBytes,
        _key,
        _nonce,
      );
      setState(() {
        _encryptedText = encryptedBytes.toBase64();
      });
    } catch (e) {
      print("Encryption error: $e");
    }
  }

  void _decrypt() async {
    if (_encryptedText == null) return;

    Uint8List encryptedBytes = Uint8List.fromList(
      base64Decode(_encryptedText!),
    );

    try {
      Uint8List decryptedBytes = await FlutterChacha20Poly1305.decrypt(
        encryptedBytes,
        _key,
        _nonce,
      );
      setState(() {
        _decryptedText = String.fromCharCodes(decryptedBytes);
      });
    } catch (e) {
      print("Decryption error: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter ChaCha20-Poly1305 Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: 'Plain Text',
              ),
              maxLines: 10,
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: _encrypt,
              child: Text('Encrypt'),
            ),
            SizedBox(height: 16),
            if (_encryptedText != null)
              Text(
                'Encrypted Text (Base64): $_encryptedText',
                style: TextStyle(color: Colors.grey),
              ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: _decrypt,
              child: Text('Decrypt'),
            ),
            SizedBox(height: 16),
            if (_decryptedText != null)
              Text(
                'Decrypted Text: $_decryptedText',
                style: TextStyle(color: Colors.green),
              ),
          ],
        ),
      ),
    );
  }
}

解释

  1. 依赖项:在pubspec.yaml中添加flutter_chacha20_poly1305
  2. 密钥和随机数:生成一个256位的密钥和一个96位的随机数(nonce)。在实际应用中,这些值应该安全地生成和存储。
  3. 加密:使用FlutterChacha20Poly1305.encrypt方法对明文进行加密,并将结果转换为Base64编码字符串以便于显示。
  4. 解密:使用FlutterChacha20Poly1305.decrypt方法对加密后的数据进行解密,并将结果转换回明文。

注意

  • 密钥和随机数的管理非常重要,不要将它们硬编码在代码中,尤其是在生产环境中。
  • 加密和解密操作是异步的,因此使用asyncawait来处理这些操作。
  • 加密后的数据以Base64编码显示,以便于阅读和传输。

希望这个示例能帮助你理解如何在Flutter项目中使用flutter_chacha20_poly1305插件进行加密和解密。

回到顶部