Flutter非对称加密算法插件asymmetric_crypto_primitives的使用
Flutter非对称加密算法插件asymmetric_crypto_primitives的使用
特性
- 为Android、iOS和MacOS提供了EDDSA加密原语,因为这些平台没有原生支持。
- 将来会支持在设备上未有原生支持的新一代非对称加密算法。
- 允许预旋转密钥,因为它默认生成两组密钥对。
开始使用
Android
生成密钥和数据签名需要设备屏幕锁定已启用。可以通过checkIfDeviceSecure
方法轻松检查:
isDeviceSecure = await AsymmetricCryptoPrimitives.checkIfDeviceSecure(); // 返回true如果屏幕锁定已设置
不检查屏幕锁定是否设置而直接使用RSA算法可能会导致抛出DeviceNotSecuredException
异常。
要开始使用插件,需要初始化signer
对象以用于Ed25519或RSA方法:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
var isDeviceSecure = await AsymmetricCryptoPrimitives.checkIfDeviceSecure();
if (isDeviceSecure) {
var signer = await AsymmetricCryptoPrimitives.establishForRSA();
runApp(MyApp(signer: signer));
}
}
大多数插件方法都可以通过signer
对象访问。
Android版本特性:
- RSA密钥由KeyStore生成并存储。
- Ed25519密钥使用Libsodium生成并存储在SharedPreferences中。
- 存储在SharedPreferences中的密钥使用AES加密。
- AES密钥由KeyStore生成并存储。
- 签名消息受本地身份验证保护。
writeData()
方法将加密后的数据存储在SharedPreferences中。- 可以在不进行本地身份验证的情况下签名消息。
iOS
当前仅支持Ed25519算法。RSA可用,但工作仍在进行中,某些功能可能无法正常工作。
默认认证方式是PIN。为了激活FaceID,需要编辑你的app的Info.plist
文件并添加以下行:
<key>NSFaceIDUsageDescription</key>
<string>iOS</string>
其余设置与Android类似。
iOS版本特性:
- Ed25519密钥使用Libsodium生成并存储在NSUserDefaults中。
- 存储在NSUserDefaults中的密钥使用EC密钥加密。
- EC密钥由Secure Enclave生成并存储。
- 签名消息受本地身份验证保护。
writeData()
方法将加密后的数据存储在NSUserDefaults中。
MacOS
当前仅支持Ed25519算法。RSA尚未可用。由于数据签名受用户密码保护,插件会检查设备上是否可以进行身份验证。因此,如Android一样,需要使用checkIfDeviceSecure()
以避免后续错误。
MacOS版本特性:
- Ed25519密钥使用Libsodium生成并存储在KeyChain中。
- 由于KeyChain原生使用AES加密数据,无需其他密钥。
- 签名消息受本地身份验证保护。
writeData()
方法将数据存储在NSUserDefaults中,未加密,因为没有密钥存储在其中。
Windows
警告:Windows版本的插件仍在开发中。目前密钥存储在公共目录中且无加密!
当前仅支持Ed25519算法。RSA尚未可用。Sodium功能通过Rust插件实现。
Windows版本特性:
- Ed25519密钥使用Libsodium生成并通过Rust插件存储在
Roaming AppData
目录下的passFile.txt
文件中。 - 签名消息受本地身份验证保护(通过插件而非原生支持)。
writeData()
方法将数据存储在Roaming AppData
目录中,未加密。
使用
签名数据
String strToSign = 'Sign me!';
signature = await signer.sign(strToSign);
获取密钥
String currentKey = '';
String nextKey = '';
currentKey = await signer.getCurrentPubKey();
nextKey = await signer.getNextPubKey();
旋转密钥
String currentKey = 'current key here!';
String nextKey = 'next key here!';
await signer.rotateForEd25519();
// 查看旋转结果
currentKey = await signer.getCurrentPubKey();
nextKey = await signer.getNextPubKey();
警告:旋转当前不适用于RSA算法。正在进行中。
获取signer
的唯一UUID
String uuid = '';
uuid = await signer.getUuid();
获取之前使用的signer
对象
void main() async {
WidgetsFlutterBinding.ensureInitialized();
var signer = await AsymmetricCryptoPrimitives.getEd25519SignerFromUuid('ecd886f1-1af6-4e62-a6b2-825e2b15ebd2');
// 或者 getRSASignerFromUuid()
runApp(MyApp(signer: signer));
}
此方法如果找不到与输入UUID关联的密钥,将抛出IncorrectUuidException
异常。
清理
await AsymmetricCryptoPrimitives.cleanUp(signer);
移除与该signer
对象关联的所有密钥。
数据存储函数
写入数据
String _data = 'Data';
String _key = 'Key';
var result = await AsymmetricCryptoPrimitives.writeData(_key, _data); // 如果一切顺利返回true。可能会抛出SharedPreferencesException或DeviceNotSecuredException
读取数据
String _key = 'Key';
var result = await AsymmetricCryptoPrimitives.readData(_key); // 如果一切顺利返回写入的数据。可能会抛出InvalidSignatureException、DeviceNotSecuredException或NoKeyInStorageException
删除数据
String _key = 'Key';
var result = await AsymmetricCryptoPrimitives.deleteData(_key); // 如果一切顺利返回true。可能会抛出SharedPreferencesException或DeviceNotSecuredException
编辑数据
String _data = 'Data';
String _key = 'Key';
var result = await AsymmetricCryptoPrimitives.editData(_key, _data); // 如果一切顺利返回true。可能会抛出SharedPreferencesException或DeviceNotSecuredException
完整示例代码
import 'package:flutter/material.dart';
import 'package:asymmetric_crypto_primitives/asymmetric_crypto_primitives.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
var signer = await AsymmetricCryptoPrimitives.establishForEd25519();
runApp(MyApp(
signer: signer,
));
}
class MyApp extends StatefulWidget {
final signer;
const MyApp({Key? key, this.signer}) : super(key: key);
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TextEditingController writeKeyController = TextEditingController();
TextEditingController writeDataController = TextEditingController();
TextEditingController readKeyController = TextEditingController();
TextEditingController deleteKeyController = TextEditingController();
TextEditingController editKeyController = TextEditingController();
TextEditingController editDataController = TextEditingController();
TextEditingController signDataController = TextEditingController();
String writeResult = '';
String readResult = '';
String deleteResult = '';
String editResult = '';
String currentKey = '';
String nextKey = '';
String signature = '';
late var signer;
[@override](/user/override)
void initState() {
signer = widget.signer;
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('storage example app'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: [
const Text(
'Signer uuid:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
Text(signer.uuid),
const Divider(),
const Text(
'Current keys:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
RawMaterialButton(
onPressed: () async {
currentKey = await signer.getCurrentPubKey();
nextKey = await signer.getNextPubKey();
setState(() {});
},
child: const Text('Get keys!'),
),
Text(currentKey),
Text(nextKey),
const Divider(),
const Text(
'Rotate keys:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
RawMaterialButton(
onPressed: () async {
await signer.rotateForEd25519();
currentKey = await signer.getCurrentPubKey();
nextKey = await signer.getNextPubKey();
setState(() {});
},
child: const Text('Rotate!'),
),
const Divider(),
const Text(
'Sign data:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
TextFormField(
controller: signDataController,
decoration: const InputDecoration(hintText: "data"),
),
RawMaterialButton(
onPressed: () async {
signature = await signer.sign(signDataController.text);
setState(() {});
},
child: const Text('Sign!'),
),
Text(signature),
const Divider(),
const Text(
'Clean up:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
RawMaterialButton(
onPressed: () async {
await AsymmetricCryptoPrimitives.cleanUp(signer);
setState(() {
currentKey = '';
nextKey = '';
signature = '';
});
},
child: const Text('Clean up!'),
),
const Divider(
thickness: 5,
),
const Text(
'1. Write',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
TextFormField(
controller: writeKeyController,
decoration: const InputDecoration(hintText: "key"),
),
TextFormField(
controller: writeDataController,
decoration: const InputDecoration(hintText: "data"),
),
RawMaterialButton(
onPressed: () async {
if (writeDataController.text.isNotEmpty && writeKeyController.text.isNotEmpty) {
var result = await AsymmetricCryptoPrimitives.writeData(
writeKeyController.text, writeDataController.text);
if (result == true) {
setState(() {
writeResult = 'Success!';
});
} else {
setState(() {
writeResult = 'Failure!';
});
}
}
},
child: const Text('Write!'),
),
Text(writeResult),
const Divider(),
const Text(
'2. Read',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
TextFormField(
controller: readKeyController,
decoration: const InputDecoration(hintText: "key"),
),
RawMaterialButton(
onPressed: () async {
if (readKeyController.text.isNotEmpty) {
var result = await AsymmetricCryptoPrimitives.readData(
readKeyController.text);
if (result != false) {
setState(() {
readResult = result;
});
} else {
setState(() {
readResult = 'Failure!';
});
}
}
},
child: const Text('Read!'),
),
Text(readResult),
const Divider(),
const Text(
'3. Delete',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
TextFormField(
controller: deleteKeyController,
decoration: const InputDecoration(hintText: "key"),
),
RawMaterialButton(
onPressed: () async {
if (deleteKeyController.text.isNotEmpty) {
var result = await AsymmetricCryptoPrimitives.deleteData(
deleteKeyController.text);
if (result == true) {
setState(() {
deleteResult = "Deleted!";
});
} else {
setState(() {
deleteResult = "Failure!";
});
}
}
},
child: const Text('Delete!'),
),
Text(deleteResult),
const Divider(),
const Text(
'4. Edit',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 25),
),
TextFormField(
controller: editKeyController,
decoration: const InputDecoration(hintText: "key"),
),
TextFormField(
controller: editDataController,
decoration: const InputDecoration(hintText: "data"),
),
RawMaterialButton(
onPressed: () async {
if (editDataController.text.isNotEmpty && editKeyController.text.isNotEmpty) {
var result = await AsymmetricCryptoPrimitives.editData(
editKeyController.text, editDataController.text);
if (result == true) {
setState(() {
editResult = 'Success!';
});
} else {
setState(() {
editResult = 'Failure!';
});
}
}
},
child: const Text('Edit!'),
),
Text(editResult),
const Divider(),
],
)),
),
),
);
}
}
更多关于Flutter非对称加密算法插件asymmetric_crypto_primitives的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter非对称加密算法插件asymmetric_crypto_primitives的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
asymmetric_crypto_primitives
是一个 Flutter 插件,用于实现非对称加密算法的基本操作。它支持诸如 RSA、ECC(椭圆曲线加密)等非对称加密算法。使用该插件,你可以在 Flutter 应用中实现加密、解密、签名和验证签名等操作。
安装插件
首先,你需要在 pubspec.yaml
文件中添加 asymmetric_crypto_primitives
插件的依赖:
dependencies:
flutter:
sdk: flutter
asymmetric_crypto_primitives: ^0.1.0 # 请使用最新的版本号
然后运行 flutter pub get
来安装插件。
使用插件
1. 生成密钥对
import 'package:asymmetric_crypto_primitives/asymmetric_crypto_primitives.dart';
void generateKeyPair() async {
final keyPair = await AsymmetricCryptoPrimitives.generateRSAKeyPair();
print('Public Key: ${keyPair.publicKey}');
print('Private Key: ${keyPair.privateKey}');
}
2. 加密和解密
void encryptDecrypt() async {
final keyPair = await AsymmetricCryptoPrimitives.generateRSAKeyPair();
final publicKey = keyPair.publicKey;
final privateKey = keyPair.privateKey;
final plainText = 'Hello, World!';
final encrypted = await AsymmetricCryptoPrimitives.encryptRSA(publicKey, plainText);
print('Encrypted: $encrypted');
final decrypted = await AsymmetricCryptoPrimitives.decryptRSA(privateKey, encrypted);
print('Decrypted: $decrypted');
}
3. 签名和验证签名
void signVerify() async {
final keyPair = await AsymmetricCryptoPrimitives.generateRSAKeyPair();
final privateKey = keyPair.privateKey;
final publicKey = keyPair.publicKey;
final message = 'Hello, World!';
final signature = await AsymmetricCryptoPrimitives.signRSA(privateKey, message);
print('Signature: $signature');
final isValid = await AsymmetricCryptoPrimitives.verifyRSA(publicKey, message, signature);
print('Is Signature Valid: $isValid');
}
常见操作总结
- 生成密钥对:
generateRSAKeyPair
- 加密:
encryptRSA
- 解密:
decryptRSA
- 签名:
signRSA
- 验证签名:
verifyRSA
注意事项
- 性能: 非对称加密算法(如 RSA)通常比对称加密算法(如 AES)慢,因此在处理大量数据时,建议结合使用对称和非对称加密。
- 密钥管理: 私钥必须妥善保管,避免泄露。
- 兼容性: 确保你的应用与不同的加密标准和协议兼容。
示例代码
以下是一个完整的示例,展示了如何使用 asymmetric_crypto_primitives
插件进行密钥生成、加密、解密、签名和验证签名操作。
import 'package:asymmetric_crypto_primitives/asymmetric_crypto_primitives.dart';
void main() async {
// 生成密钥对
final keyPair = await AsymmetricCryptoPrimitives.generateRSAKeyPair();
final publicKey = keyPair.publicKey;
final privateKey = keyPair.privateKey;
print('Public Key: $publicKey');
print('Private Key: $privateKey');
// 加密和解密
final plainText = 'Hello, World!';
final encrypted = await AsymmetricCryptoPrimitives.encryptRSA(publicKey, plainText);
print('Encrypted: $encrypted');
final decrypted = await AsymmetricCryptoPrimitives.decryptRSA(privateKey, encrypted);
print('Decrypted: $decrypted');
// 签名和验证签名
final message = 'Hello, World!';
final signature = await AsymmetricCryptoPrimitives.signRSA(privateKey, message);
print('Signature: $signature');
final isValid = await AsymmetricCryptoPrimitives.verifyRSA(publicKey, message, signature);
print('Is Signature Valid: $isValid');
}