引入依赖
encrypt: 5.0.1
核心代码
aes.dart
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:flutter/cupertino.dart';
/// AES加密算法
class AES {
static String encryptAes({
required String plainText,
required String keyStr,
required String ivStr,
encrypt.AESMode? mode = encrypt.AESMode.cbc,
}) {
final key = encrypt.Key.fromUtf8(keyStr);
final iv = encrypt.IV.fromUtf8(ivStr);
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
final encrypted = encrypter.encrypt(plainText, iv: iv);
debugPrint(encrypted.base64); // 加密的结果
return encrypted.base64;
}
static String decryptAes(
{required String encryptedStr,
required String keyStr,
required String ivStr,
encrypt.AESMode? mode = encrypt.AESMode.cbc}) {
final key = encrypt.Key.fromUtf8(keyStr);
final iv = encrypt.IV.fromUtf8(ivStr);
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
final decrypted = encrypter.decrypt64(encryptedStr, iv: iv);
return decrypted;
}
}
测试页面
aes_test_page.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'aes.dart';
class AesEncryptTestPage extends StatefulWidget {
const AesEncryptTestPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<AesEncryptTestPage> createState() => _AesEncryptTestPageState();
}
class _AesEncryptTestPageState extends State<AesEncryptTestPage> {
String encryptedText = '';
String decryptedText = '';
final plainText = '{"a":1}';
String key = '';
String iv = '';
Widget _row(String title, String content) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title),
const SizedBox(width: 10),
Text(content),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_row('加密前:', plainText),
_row('加密key:', key),
_row('加密iv:', iv),
_row('加密后:', encryptedText),
_row('解密后', decryptedText),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () {
key = getRandomString(16);
iv = getRandomString(16);
setState(() {});
},
tooltip: '随机生成key和Iv',
child: const Icon(Icons.add),
),
FloatingActionButton(
onPressed: () {
encryptedText = AES.encryptAes(
plainText: plainText, keyStr: key, ivStr: iv);
setState(() {});
},
tooltip: '触发加密',
child: const Icon(Icons.add),
),
FloatingActionButton(
onPressed: () {
decryptedText = AES.decryptAes(
encryptedStr: encryptedText, keyStr: key, ivStr: iv);
setState(() {});
},
tooltip: '触发解密',
child: const Icon(Icons.seven_k),
),
],
) // This trailing comma makes auto-formatting nicer for build methods.
);
}
/// AES加密测试
String getRandomString(int length) {
Random random = Random();
List<String> digits =
List.generate(length, (_) => random.nextInt(10).toString());
return digits.join();
}
}
要素讲解
AES加密是典型的对称算法加密,支持正向加密和逆向解密,该算法主要有4个要素:
当使用AES加密算法进行加密或解密时,有四个要素是必须考虑的。
-
加密或解密的字符串(Plaintext or Ciphertext):这是要进行加密或解密操作的实际字符串。对于加密操作,这个字符串是明文(Plaintext),它将被转换为加密后的密文(Ciphertext)。对于解密操作,这个字符串是密文(Ciphertext),它将被还原为原始的明文。
-
加密密钥(Encryption Key):加密密钥是用于进行AES加密和解密的关键组成部分。它是一个固定长度的二进制值,如128位、192位或256位。密钥长度的选择取决于所使用的AES算法变体(例如AES-128、AES-192或AES-256)。密钥必须保密,并且加密和解密操作必须使用相同的密钥。
-
初始化向量(Initialization Vector, IV):初始化向量是一个固定长度的随机值,它被用作AES加密算法的额外输入。它的长度通常与AES区块大小相同,即128位。如果使用相同的密钥对不同的明文进行加密,则每个明文都需要使用不同的IV。IV的作用是确保相同的明文在不同加密过程中生成的密文是不同的,增加了密码的安全性。
-
加密模式(Encryption Mode):加密模式决定了AES算法如何处理长度超过一个区块大小的数据。常见的加密模式包括ECB、CBC、CFB和OFB等。以下是一些常用的加密模式:
- 电子密码本模式(Electronic Codebook Mode, ECB):每个明文块都被独立加密,相同的明文块将生成相同的密文块。
- 密码分组链接模式(Cipher Block Chaining Mode, CBC):每个明文块在加密之前都会与前一个密文块进行异或操作,增加了加密过程的随机性。
- 密文反馈模式(Cipher Feedback Mode, CFB):使用前一次加密的密文作为下一次加密的输入,可以支持加密和解密过程的流式处理。
- 输出反馈模式(Output Feedback Mode, OFB):将前一次的输出作为下一次的输入,可以支持加密和解密过程的流式处理。
选择适当的加密模式以及正确使用加密密钥和初始化向量(IV)是确保AES算法安全和可靠运行的重要因素。