Flutter加密解密插件cryptography_flutter的使用
Flutter加密解密插件cryptography_flutter的使用
概述
cryptography_flutter
是一个Flutter插件,它允许在Android、iOS和Mac OS X上使用原生API进行加密操作。该插件由gohilla.com维护,并且遵循Apache License 2.0开源协议。
使用理由
- 安全性:操作系统API从安全角度来看是更优的选择。
- 性能优越:与纯Dart实现相比,操作系统API可以快至100倍。
- 跨平台支持:当操作系统API不可用时,会回退到
package:cryptography
的实现。
通用行为
- 包含了两种类型的类:
- 如
FlutterChacha20
,在Android/iOS/Mac OS X上使用操作系统API;如果操作系统不支持,则使用背景实现(如BackgroundChacha20
)或纯Dart实现(如DartChacha20
)。 - 类似
BackgroundChacha20
,通过Flutter SDK中的compute
函数将长时间计算移动到后台隔离区。
- 如
- 对于非常小或过大的输入,避免跨隔离区传递消息开销,直接在同一隔离区内完成计算。
- 设有队列机制防止并发请求过多导致内存耗尽。
快速开始
在项目的pubspec.yaml
文件中添加依赖:
dependencies:
cryptography: ^2.7.0
cryptography_flutter: ^2.3.2
更多API文档请参阅pub.dev/packages/cryptography。
算法行为
AES-GCM
FlutterAesGcm
用于Android、iOS和Mac OS X,性能比纯Dart实现高约50倍。BackgroundAesGcm
用于Windows和Linux处理足够大的输入。
ChaCha20-Poly1305-AEAD
FlutterChacha20
适用于Android和Apple系统,性能提升显著。BackgroundChacha20
为Windows和Linux准备。
NIST ECDH / ECDSA
FlutterEcdh
和FlutterEcdsa
仅限Apple系统。
Ed25519 和 X25519
- 分别有
FlutterEd25519
/BackgroundEd25519
及FlutterX25519
/BackgroundX25519
,均针对Apple系统。
HMAC 和 PBKDF2
FlutterHmac
和FlutterPbkdf2
分别适用于Android,而BackgroundPbkdf2
则覆盖Apple、Windows和Linux。
示例代码
下面是一个简单的示例应用,演示如何使用AES-GCM算法进行加密解密操作:
import 'dart:convert';
import 'package:cryptography/cryptography.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
title: 'Cryptography demo',
home: CipherPage(),
));
}
class CipherPage extends StatefulWidget {
const CipherPage({Key? key}) : super(key: key);
@override
State<CipherPage> createState() => _CipherPageState();
}
class _CipherPageState extends State<CipherPage> {
static final _aesGcm128 = AesGcm.with128bits();
Cipher _cipher = _aesGcm128;
final _secretKeyController = TextEditingController();
final _nonceController = TextEditingController();
List<int> _clearText = [];
final _cipherTextController = TextEditingController();
final _macController = TextEditingController();
Object? _error;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 500),
padding: const EdgeInsets.all(20),
child: ListView(
children: [
// Cipher选择器
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)'),
),
// 其他Cipher选项...
],
),
),
const SizedBox(height: 10),
Text('Class: ${_cipher.runtimeType}'),
const SizedBox(height: 10),
// Secret Key输入框
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),
// Nonce输入框
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),
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);
setState(() {
_error = null;
});
} catch (error, stackTrace) {
setState(() {
_error = '$error\n\n$stackTrace';
_cipherTextController.text = '';
_macController.text = '';
});
return;
}
}
String _toHex(List<int> bytes) {
return bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
}
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;
});
}
}
此代码片段展示了如何创建一个简单的Flutter应用程序界面,用户可以选择不同的加密算法并输入密钥、随机数(nonce),然后输入明文进行加密。加密后的密文和MAC会被显示出来。同时提供了生成随机密钥和随机数的功能按钮。
更多关于Flutter加密解密插件cryptography_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter加密解密插件cryptography_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用cryptography_flutter
插件进行加密和解密的示例代码。这个插件提供了对称加密(如AES)和非对称加密(如RSA)的功能。
首先,你需要在你的pubspec.yaml
文件中添加cryptography_flutter
依赖:
dependencies:
flutter:
sdk: flutter
cryptography_flutter: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
以下是一个简单的示例,展示如何使用AES进行加密和解密:
import 'package:flutter/material.dart';
import 'package:cryptography_flutter/cryptography_flutter.dart';
import 'dart:typed_data';
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: EncryptDecryptDemo(),
),
),
);
}
}
class EncryptDecryptDemo extends StatefulWidget {
@override
_EncryptDecryptDemoState createState() => _EncryptDecryptDemoState();
}
class _EncryptDecryptDemoState extends State<EncryptDecryptDemo> {
final TextEditingController _textController = TextEditingController();
late Uint8List _key;
late Uint8List _nonce;
String? _encryptedText;
String? _decryptedText;
@override
void initState() {
super.initState();
// 初始化密钥和nonce(nonce在AES-GCM模式下需要)
_key = Uint8List.fromList(List.generate(32, (i) => (i % 256).toByte()));
_nonce = Uint8List.fromList(List.generate(12, (i) => (i % 256).toByte()));
}
void _encrypt() async {
String? text = _textController.text;
if (text == null || text.isEmpty) return;
Uint8List plaintext = Uint8List.fromList(text.codeUnits);
AesGcm aesGcm = AesGcm(_key);
Ciphertext ciphertext = await aesGcm.encrypt(plaintext, _nonce);
setState(() {
_encryptedText = base64.encode(ciphertext.bytes);
_decryptedText = null;
});
}
void _decrypt() async {
if (_encryptedText == null) return;
Uint8List encryptedBytes = base64.decode(_encryptedText!);
Ciphertext ciphertext = Ciphertext.fromBytes(encryptedBytes);
AesGcm aesGcm = AesGcm(_key);
Uint8List plaintext = await aesGcm.decrypt(ciphertext, _nonce);
setState(() {
_decryptedText = String.fromCharCodes(plaintext);
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _textController,
decoration: InputDecoration(labelText: 'Enter text to encrypt'),
maxLines: 5,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _encrypt,
child: Text('Encrypt'),
),
SizedBox(height: 20),
if (_encryptedText != null)
Text(
'Encrypted Text (Base64): $_encryptedText',
style: TextStyle(color: Colors.grey),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _decrypt,
child: Text('Decrypt'),
),
SizedBox(height: 20),
if (_decryptedText != null)
Text(
'Decrypted Text: $_decryptedText',
style: TextStyle(color: Colors.green),
),
],
);
}
}
在这个示例中:
- 我们初始化了一个AES密钥(32字节)和一个nonce(12字节),这些是在AES-GCM模式下加密必需的。
_encrypt
函数将用户输入的文本加密,并将结果以Base64编码的形式显示出来。_decrypt
函数将Base64编码的加密文本解密,并显示解密后的文本。
注意:
- 在实际应用中,密钥和nonce的管理非常重要,不要将它们硬编码在代码中。
- 使用AES-GCM模式时,nonce必须是唯一的,并且不能重复使用,以确保加密的安全性。
希望这个示例能够帮助你理解如何在Flutter项目中使用cryptography_flutter
插件进行加密和解密。