Flutter数据加密插件crypt的使用
Flutter数据加密插件crypt的使用
描述
crypt
包实现了Unix crypt格式中指定的SHA-256和SHA-512哈希算法,这些哈希算法常用于Unix和POSIX系统以及LDAP条目中作为身份验证凭据。该包可以生成类似于以下格式的字符串:
$5$xYWYo0raYwLSchAd$na8cL1H.ESWtof6DNwraE6p8WI9DYObZ3irMe01Guk6
或者带有自定义轮数(rounds)的:
$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA
字符串格式以$
符号分隔字段,依次为算法指示符、轮数(可选)、盐值(salt)和哈希值。
对于SHA-256哈希,字符串以$5$
开头;对于SHA-512哈希,字符串以$6$
开头。默认情况下,当使用SHA-256或SHA-512时,轮数设置为5000。
注意事项
不同的系统可能对crypt格式字符串有不同的使用方式。例如,在LDAP posixAccount
条目的userPassword
属性中,需要在crypt格式字符串前加上{crypt}
。
使用方法
验证密码是否匹配给定的crypt格式哈希
要测试输入的密码是否与创建crypt格式哈希时使用的密码相匹配,可以从crypt格式哈希创建一个Crypt
对象,并调用其match
方法。
bool isValid(String cryptFormatHash, String enteredPassword) =>
Crypt(cryptFormatHash).match(enteredPassword);
生成crypt格式哈希
要生成一个crypt格式哈希,可以使用Crypt.sha256
或Crypt.sha512
构造函数,并将其转换为字符串。
import 'package:crypt/crypt.dart';
void main() {
// 创建crypt字符串
// 默认轮数和随机生成的盐
final c1 = Crypt.sha256('p@ssw0rd');
// 随机生成的盐
final c2 = Crypt.sha256('p@ssw0rd', rounds: 10000);
// 默认轮数
final c3 = Crypt.sha256('p@ssw0rd', salt: 'abcdefghijklmnop');
// 不使用默认值
final c4 = Crypt.sha256('p@ssw0rd', rounds: 10000, salt: 'abcdefghijklmnop');
// SHA-512
final d1 = Crypt.sha512('p@ssw0rd');
print(c1);
print(c2);
print(c3);
print(c4);
print(d1);
// 比较输入值与crypt哈希
for (final hashString in [
r'$5$zQUCjEzs9jnrRdCK$dbo1i9WjQjbUwOC4JCRAZHpfd31Dh676vI0L6w0dZw1',
c1.toString(),
c2.toString(),
c3.toString(),
c4.toString(),
d1.toString(),
]) {
// 解析crypt字符串:这会提取类型、轮数和盐
final h = Crypt(hashString);
const correctValue = 'p@ssw0rd';
const wrongValue = '123456';
if (!h.match(correctValue)) {
print('Error: unexpected non-match: $correctValue');
}
if (h.match(wrongValue)) {
print('Error: unexpected match: $wrongValue');
}
}
}
以上示例代码将输出如下内容:
$5$jYq8PvB6hI3cLREQ$FGBjCL5NO1qSwync3LOlCWTnIBJCjVsFtst9jNnnBx9
$5$rounds=10000$wJiiNy1TwwaWhGFN$t2JsIqOgfXh/3LLQF.YA9XDlJmtpLYmSe4i9TZl7cM.
$5$abcdefghijklmnop$gUWLu9sDI2Qvs112Xb8jmgD3ySIRE5ek63jk6ybSs7D
$5$rounds=10000$abcdefghijklmnop$51muKIziT9VAyDZ2ZueAYvAwgIYx0cLxUCIAlPoWaHD
$6$LJgzW1oI9UZ5w8HO$pTL3hmFg2zBkQPqRhcej6CmY2Az0WLDVlnMGTg//71D3hDEvKCB7XqwtinHEM1rlD/YAlEjhy2Lb3LJQsNvXx.
请注意,具有随机生成盐的crypt字符串每次程序运行时都会产生不同的值,而使用固定盐的crypt字符串将始终产生相同的值。
特性和问题
随机数生成器
盐生成使用的是加密安全的随机数生成器(如果可用)。如果没有可用的加密安全随机数生成器,则会回退到使用加密不安全的随机数生成器。
可以通过设置Crypt.cryptographicallySecureSalts
为true
来防止使用加密不安全的随机数生成器。如果尝试在不支持加密安全随机数生成器的平台上生成盐,则会抛出异常。
显式地将其设置为false
可以在未来版本中允许这种回退行为。当前默认设置为false
,以保持向后兼容性。但未来版本可能会将默认值设置为true
以提高安全性。
依赖于crypto
包
当前版本依赖于Dart的crypto
包版本3.0.0,它支持SHA-512。如果您需要使用更早版本的crypto
包,请使用本包的2.0.0版本,但请注意该版本不支持SHA-512 crypt字符串且不是空安全的。
如果有任何功能请求或问题,请在GitHub issue tracker上提交。
更多关于Flutter数据加密插件crypt的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据加密插件crypt的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用crypt
插件进行数据加密和解密的示例代码。请注意,crypt
插件通常指的是pointycastle
或其他类似的库,这些库提供了加密和解密功能。由于crypt
这个名称可能不够具体,我会使用pointycastle
作为示例,这是Flutter中常用的加密库。
首先,你需要在你的pubspec.yaml
文件中添加pointycastle
依赖:
dependencies:
flutter:
sdk: flutter
pointycastle: ^3.0.1 # 请检查最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,是一个简单的示例,演示如何使用pointycastle
进行AES加密和解密:
import 'package:flutter/material.dart';
import 'package:pointycastle/export.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Encryption Example'),
),
body: Center(
child: EncryptionExample(),
),
),
);
}
}
class EncryptionExample extends StatefulWidget {
@override
_EncryptionExampleState createState() => _EncryptionExampleState();
}
class _EncryptionExampleState extends State<EncryptionExample> {
String? originalText = "Hello, Flutter!";
String? encryptedText;
String? decryptedText;
void _encrypt() {
final key = Uint8List.fromList(List.generate(32, (i) => (i % 256).toByte()));
final plainText = Uint8List.fromList(originalText!.codeUnits);
final iv = Uint8List.fromList(List.generate(16, (i) => (i % 256).toByte()));
final aes = AESFastEngine();
final cipher = CBCBlockCipher(aes);
final params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
final padder = PaddedBufferedBlockCipher(cipher);
padder.init(true, params);
final encrypted = padder.processBytes(plainText, true);
final encryptedBytes = List<int>.from(encrypted);
setState(() {
encryptedText = encryptedBytes.map((e) => e.toRadixString(16).padStart(2, '0')).join();
});
}
void _decrypt() {
if (encryptedText == null) return;
final key = Uint8List.fromList(List.generate(32, (i) => (i % 256).toByte()));
final encryptedBytes = Uint8List.fromList(
encryptedText!.matches('.{2}').map((hex) => int.parse(hex, radix: 16)).toList()
);
final iv = Uint8List.fromList(List.generate(16, (i) => (i % 256).toByte()));
final aes = AESFastEngine();
final cipher = CBCBlockCipher(aes);
final params = ParametersWithIV<KeyParameter>(KeyParameter(key), iv);
final padder = PaddedBufferedBlockCipher(cipher);
padder.init(false, params);
final decrypted = padder.processBytes(encryptedBytes, true);
final decryptedBytes = List<int>.from(decrypted);
setState(() {
decryptedText = String.fromCharCodes(decryptedBytes);
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Original Text: $originalText'),
ElevatedButton(onPressed: _encrypt, child: Text('Encrypt')),
if (encryptedText != null)
Text('Encrypted Text: $encryptedText'),
if (decryptedText != null)
Text('Decrypted Text: $decryptedText'),
ElevatedButton(onPressed: _decrypt, child: Text('Decrypt')),
],
);
}
}
这个示例展示了如何使用AES加密和解密一个简单的字符串。注意,这里的密钥和初始化向量(IV)是随机生成的,仅用于演示目的。在实际应用中,你应该使用安全的密钥管理和IV生成方法,并确保密钥和IV的保密性。
此外,加密和解密过程中涉及的数据处理(如编码和解码)也需要仔细处理,以确保数据的完整性和安全性。这个示例使用了十六进制编码来显示加密后的数据,但在实际应用中,你可能会选择其他更适合的编码方式。