Flutter加密解密插件cryptography_flutter_plus的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter加密解密插件cryptography_flutter_plus的使用

概述

cryptography_flutter_plus 是一个Flutter插件,它使 cryptography_plus 能够在 Android、iOS 和 Mac OS X 上使用本地API进行加密和解密操作。这个插件提供了更高的安全性和性能,并且在无法使用操作系统API时会回退到纯Dart实现。

为什么选择 cryptography_flutter_plus

  • 安全性:操作系统API在安全方面更优。
  • 性能:操作系统API比纯Dart实现快100倍。
  • 跨平台:当操作系统不支持某些算法时,会回退到纯Dart实现。

开始使用

首先,在你的 pubspec.yaml 文件中添加依赖:

dependencies:
  cryptography_plus: ^2.7.0
  cryptography_flutter: ^2.3.2

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

示例代码

以下是一个完整的示例,展示了如何使用 cryptography_flutter_plus 插件进行加密和解密操作。

import 'dart:convert';
import 'package:cryptography_plus/cryptography_plus.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
    title: 'Cryptography demo',
    home: CipherPage(),
  ));
}

List<int> _fromHex(String s) {
  s = s.replaceAll(' ', '').replaceAll('\n', '');
  return List<int>.generate(s.length ~/ 2, (i) {
    var byteInHex = s.substring(2 * i, 2 * i + 2);
    if (byteInHex.startsWith('0')) {
      byteInHex = byteInHex.substring(1);
    }
    final result = int.tryParse(byteInHex, radix: 16);
    if (result == null) {
      throw StateError('Not valid hexadecimal bytes: $s');
    }
    return result;
  });
}

String _toHex(List<int> bytes) {
  return bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
}

class CipherPage extends StatefulWidget {
  const CipherPage({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _CipherPageState();
  }
}

class _CipherPageState extends State<CipherPage> {
  static final _aesGcm128 = AesGcm.with128bits();
  static final _chacha20Poly1305 = Chacha20.poly1305Aead();

  Cipher _cipher = _aesGcm128;
  final _secretKeyController = TextEditingController();
  final _nonceController = TextEditingController();

  List<int> _clearText = [];
  final _cipherTextController = TextEditingController();
  final _macController = TextEditingController();
  Object? _error;
  String _decryptedText = '';

  @override
  Widget build(BuildContext context) {
    final error = _error;
    final cipher = _cipher;
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Container(
            constraints: const BoxConstraints(maxWidth: 500),
            padding: const EdgeInsets.all(20),
            child: ListView(
              children: [
                InputDecorator(
                  decoration: const InputDecoration(labelText: 'Cipher'),
                  child: DropdownButton<Cipher>(
                    value: _cipher,
                    onChanged: (newValue) {
                      setState(() {
                        _cipher = newValue ?? _aesGcm128;
                        _encrypt();
                      });
                    },
                    items: [
                      DropdownMenuItem(
                        value: _aesGcm128,
                        child: const Text('AES-GCM (128-bits)'),
                      ),
                      DropdownMenuItem(
                        value: _chacha20Poly1305,
                        child: const Text('ChaCha20 + Poly1305'),
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 10),
                Row(children: [
                  Expanded(
                    child: TextField(
                      controller: _secretKeyController,
                      onChanged: (value) {
                        _encrypt();
                      },
                      minLines: 1,
                      maxLines: 16,
                      enableInteractiveSelection: true,
                      decoration: InputDecoration(
                          labelText: 'Secret key (${_cipher.secretKeyLength} bytes)'),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      final secretKey = await _cipher.newSecretKey();
                      final bytes = await secretKey.extractBytes();
                      _secretKeyController.text = _toHex(bytes);
                      await _encrypt();
                    },
                    child: const Text('Generate'),
                  ),
                ]),
                const SizedBox(height: 10),
                Row(children: [
                  Expanded(
                    child: TextField(
                      controller: _nonceController,
                      onChanged: (value) {
                        _encrypt();
                      },
                      minLines: 1,
                      maxLines: 16,
                      enableInteractiveSelection: true,
                      decoration: InputDecoration(
                          labelText: 'Nonce (${_cipher.nonceLength} bytes)'),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () async {
                      _nonceController.text = _toHex(_cipher.newNonce());
                      await _encrypt();
                    },
                    child: const Text('Generate'),
                  ),
                ]),
                const SizedBox(height: 30),
                const Text('Encrypt'),
                TextField(
                  onChanged: (newValue) {
                    try {
                      _clearText = utf8.encode(newValue);
                      _encrypt();
                    } catch (error) {
                      setState(() {
                        _error = error;
                      });
                    }
                  },
                  minLines: 1,
                  maxLines: 16,
                  enableInteractiveSelection: true,
                  decoration: const InputDecoration(labelText: 'Cleartext (text)'),
                ),
                const SizedBox(height: 10),
                const Text('Decrypted Text'),
                const SizedBox(height: 5),
                Container(
                  color: Colors.grey.shade500,
                  padding: const EdgeInsets.all(4),
                  child: Text(_decryptedText),
                ),
                const SizedBox(height: 10),
                TextField(
                  controller: _cipherTextController,
                  minLines: 1,
                  maxLines: 16,
                  enableInteractiveSelection: true,
                  decoration: const InputDecoration(labelText: 'Ciphertext (hex)'),
                ),
                const SizedBox(height: 10),
                TextField(
                  controller: _macController,
                  minLines: 1,
                  maxLines: 16,
                  enableInteractiveSelection: true,
                  decoration: const InputDecoration(
                      labelText: 'Message Authentication Code (MAC)'),
                ),
                const SizedBox(height: 10),
                if (error != null) Text(error.toString()),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Future<void> _encrypt() async {
    try {
      final cipher = _cipher;
      final secretBox = await cipher.encrypt(
        _clearText,
        secretKey: SecretKeyData(
          _fromHex(_secretKeyController.text),
        ),
        nonce: _fromHex(_nonceController.text),
      );
      _cipherTextController.text = _toHex(secretBox.cipherText);
      _macController.text = _toHex(secretBox.mac.bytes);

      _decrypt();

      setState(() {
        _error = null;
      });
    } catch (error, stackTrace) {
      setState(() {
        _error = '$error\n\n$stackTrace';
        _cipherTextController.text = '';
        _macController.text = '';
      });
      return;
    }
  }

  Future<void> _decrypt() async {
    final cipher = _cipher;

    _decryptedText = utf8.decode(await cipher.decrypt(
      SecretBox(
        _fromHex(_cipherTextController.text),
        nonce: _fromHex(_nonceController.text),
        mac: Mac(_fromHex(_macController.text)),
      ),
      secretKey: SecretKeyData(
        _fromHex(_secretKeyController.text),
      ),
    ));
  }
}

总结

通过上述步骤和示例代码,你可以轻松地在Flutter应用中集成加密和解密功能。根据你的需求选择合适的加密算法,并确保在生产环境中妥善管理密钥和敏感数据。


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

1 回复

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


当然,以下是如何在Flutter项目中使用cryptography_flutter_plus插件进行加密和解密的代码示例。这个插件支持多种加密算法,包括AES、RSA等。以下是一个简单的示例,演示如何使用AES进行加密和解密。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加cryptography_flutter_plus依赖:

dependencies:
  flutter:
    sdk: flutter
  cryptography_flutter_plus: ^x.y.z  # 请使用最新版本号

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

2. 导入插件

在你的Dart文件中导入插件:

import 'package:cryptography_flutter_plus/cryptography_flutter_plus.dart';

3. AES加密和解密示例

以下是一个使用AES算法进行加密和解密的完整示例:

import 'package:flutter/material.dart';
import 'package:cryptography_flutter_plus/cryptography_flutter_plus.dart';
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('AES Encryption/Decryption Example'),
        ),
        body: Center(
          child: AESExample(),
        ),
      ),
    );
  }
}

class AESExample extends StatefulWidget {
  @override
  _AESExampleState createState() => _AESExampleState();
}

class _AESExampleState extends State<AESExample> {
  final TextEditingController _keyController = TextEditingController();
  final TextEditingController _valueController = TextEditingController();
  String _encryptedValue = '';
  String _decryptedValue = '';

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        TextField(
          controller: _keyController,
          decoration: InputDecoration(labelText: 'Encryption Key'),
        ),
        TextField(
          controller: _valueController,
          decoration: InputDecoration(labelText: 'Value to Encrypt'),
        ),
        ElevatedButton(
          onPressed: () async {
            setState(() {
              _encryptedValue = '';
              _decryptedValue = '';
            });

            String key = _keyController.text;
            String value = _valueController.text;

            if (key.isEmpty || value.isEmpty) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Key and value cannot be empty')),
              );
              return;
            }

            // Convert the key and value to Uint8List
            Uint8List keyBytes = Uint8List.fromList(key.codeUnits);
            Uint8List valueBytes = Uint8List.fromList(value.codeUnits);

            // Encrypt
            Uint8List encryptedBytes = await Aes.encrypt(
              plainText: valueBytes,
              key: keyBytes,
            );
            String encryptedString = base64Encode(encryptedBytes);
            setState(() {
              _encryptedValue = encryptedString;
            });

            // Decrypt
            Uint8List decryptedBytes = await Aes.decrypt(
              cipherText: encryptedBytes,
              key: keyBytes,
            );
            String decryptedString = String.fromCharCodes(decryptedBytes);
            setState(() {
              _decryptedValue = decryptedString;
            });
          },
          child: Text('Encrypt/Decrypt'),
        ),
        Text('Encrypted Value: $_encryptedValue'),
        Text('Decrypted Value: $_decryptedValue'),
      ],
    );
  }
}

注意事项

  1. 密钥管理:在实际应用中,密钥管理非常重要。不要将密钥硬编码在应用中,应使用安全的密钥管理服务。
  2. 错误处理:在生产代码中,应添加更多的错误处理逻辑,例如捕获异常并显示适当的用户反馈。
  3. 安全性:确保你了解所选加密算法的安全性和使用场景。AES是一个广泛使用的对称加密算法,但在某些情况下可能需要使用其他算法。

这个示例展示了如何在Flutter应用中使用cryptography_flutter_plus插件进行AES加密和解密。你可以根据需要调整密钥、值和其他参数。

回到顶部