基于最新版的flutter pointycastle: ^3.9.1的AES加密
自己添加pointycastle: ^3.9.1库
config.dart
import 'dart:convert';
import 'dart:typed_data';
class Config {
static String password = '成都推理计算科技';
static Uint8List iv = Uint8List.fromList([
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
]);
static int aesSize = 128;
static String aesSalt=latin1.decode([10, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
}
aes_encrypt.dart
import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/src/platform_check/platform_check.dart';
import 'config.dart';
class AesEncrypt {
final iv = Config.iv;
final password = Config.password;
final aesSize = Config.aesSize;
final aesSalt = Config.aesSalt;
AesEncrypt();
Uint8List aesCbcEncrypt(Uint8List key, Uint8List iv, Uint8List paddedPlaintext) {
if (![128, 192, 256].contains(key.length * 8)) {
throw ArgumentError.value(key, 'key', 'invalid key length for AES');
}
if (iv.length * 8 != 128) {
throw ArgumentError.value(iv, 'iv', 'invalid IV length for AES');
}
if (paddedPlaintext.length * 8 % 128 != 0) {
throw ArgumentError.value(paddedPlaintext, 'paddedPlaintext', 'invalid length for AES');
}
final cbc = BlockCipher('AES/CBC')..init(true, ParametersWithIV(KeyParameter(key), iv));
final cipherText = Uint8List(paddedPlaintext.length);
var offset = 0;
while (offset < paddedPlaintext.length) {
offset += cbc.processBlock(paddedPlaintext, offset, cipherText, offset);
}
assert(offset == paddedPlaintext.length);
return cipherText;
}
Uint8List aesCbcDecrypt(Uint8List key, Uint8List iv, Uint8List cipherText) {
if (![128, 192, 256].contains(key.length * 8)) {
throw ArgumentError.value(key, 'key', 'invalid key length for AES');
}
if (iv.length * 8 != 128) {
throw ArgumentError.value(iv, 'iv', 'invalid IV length for AES');
}
if (cipherText.length * 8 % 128 != 0) {
throw ArgumentError.value(cipherText, 'cipherText', 'invalid length for AES');
}
final cbc = BlockCipher('AES/CBC')..init(false, ParametersWithIV(KeyParameter(key), iv));
final paddedPlainText = Uint8List(cipherText.length);
var offset = 0;
while (offset < cipherText.length) {
offset += cbc.processBlock(cipherText, offset, paddedPlainText, offset);
}
assert(offset == cipherText.length);
return paddedPlainText;
}
String bin2hex(Uint8List bytes, {String? separator, int? wrap}) {
var len = 0;
final buf = StringBuffer();
for (final b in bytes) {
final s = b.toRadixString(16);
if (buf.isNotEmpty && separator != null) {
buf.write(separator);
len += separator.length;
}
if (wrap != null && wrap < len + 2) {
buf.write('\n');
len = 0;
}
buf.write('${(s.length == 1) ? '0' : ''}$s');
len += 2;
}
return buf.toString();
}
Uint8List hex2bin(String hexStr) {
if (hexStr.length % 2 != 0) {
throw const FormatException('not an even number of hexadecimal characters');
}
final result = Uint8List(hexStr.length ~/ 2);
for (var i = 0; i < result.length; i++) {
result[i] = int.parse(hexStr.substring(2 * i, 2 * (i + 1)), radix: 16);
}
return result;
}
Uint8List pad(Uint8List bytes, int blockSizeBytes) {
final padLength = blockSizeBytes - (bytes.length % blockSizeBytes);
final padded = Uint8List(bytes.length + padLength)..setAll(0, bytes);
Padding('PKCS7').addPadding(padded, bytes.length);
return padded;
}
Uint8List unpad(Uint8List padded) => padded.sublist(0, padded.length - Padding('PKCS7').padCount(padded));
Uint8List passphraseToKey(String passPhrase, {String salt = '', int iterations = 30000, required int bitLength}) {
if (![128, 192, 256].contains(bitLength)) {
throw ArgumentError.value(bitLength, 'bitLength', 'invalid for AES');
}
final numBytes = bitLength ~/ 8;
final kd = KeyDerivator('SHA-256/HMAC/PBKDF2')..init(Pbkdf2Parameters(utf8.encode(salt), iterations, numBytes));
return kd.process(utf8.encode(passPhrase));
}
Uint8List? generateRandomBytes(int numBytes) {
if (_secureRandom == null) {
_secureRandom = SecureRandom('Fortuna');
_secureRandom!.seed(KeyParameter(Platform.instance.platformEntropySource().getBytes(32)));
}
final iv = _secureRandom!.nextBytes(numBytes);
return iv;
}
SecureRandom? _secureRandom;
Uint8List encrypt(String textToEncrypt) {
final cipherText = aesCbcEncrypt(
passphraseToKey(password, salt: aesSalt, bitLength: aesSize), iv, pad(utf8.encode(textToEncrypt), 16));
return cipherText;
}
String decrypt(List<int> cipherListInt) {
Uint8List cipherText = Uint8List.fromList(cipherListInt);
final paddedDecryptedBytes =
aesCbcDecrypt(passphraseToKey(password, salt: aesSalt, bitLength: aesSize), iv, cipherText);
final decryptedBytes = unpad(paddedDecryptedBytes);
final decryptedText = utf8.decode(decryptedBytes);
return decryptedText;
}
}