Flutter实现兼容Java的AES CBC-128自定义密钥加解密
Flutter 实现与Java逻辑完全一致的AES CBC-128加解密
核心规则对齐(此前实现不匹配的根本原因)
必须1:1对齐Java代码的自定义逻辑,否则加密结果无法匹配:
- 密钥预处理:将输入密钥转为UTF-8字节数组,新建固定长度16的空字节数组(默认值全0),将原密钥字节复制到该数组,若原密钥长度超过16则截断,不足16则剩余位置保留0值
- IV取值:直接使用预处理后的16位密钥字节作为IV向量,不生成随机IV
- 算法配置:AES算法,CBC模式,PKCS5填充(AES块长固定为16字节时,PKCS5与PKCS7填充逻辑完全一致)
- 编解码规则:加密结果做Base64编码输出,解密前先将输入密文做Base64解码得到原始字节
具体实现步骤
- 引入依赖
在pubspec.yaml的dependencies节点添加以下依赖,该库支持自定义密钥与IV,适配灵活度更高:
dependencies: pointycastle: ^3.7.3
执行flutter pub get完成依赖安装,Dart内置dart:convert库原生支持Base64编解码,无需额外引入编解码相关依赖。
- 加解密工具代码
import 'dart:convert'; import 'dart:typed_data'; import 'package:pointycastle/export.dart'; class AesCbc128Util { /// 对齐Java逻辑的密钥预处理 static Uint8List _processKeyBytes(String key) { final originKeyBytes = utf8.encode(key); // 初始化16字节全0数组 final processedKey = Uint8List(16); final copyLength = originKeyBytes.length > 16 ? 16 : originKeyBytes.length; // 复制原密钥字节,不足16位的位置保持0值 processedKey.setRange(0, copyLength, originKeyBytes); return processedKey; } /// 对齐Java Encrypt方法的加密逻辑 static String encrypt(String plainText, String key) { final keyBytes = _processKeyBytes(key); // IV直接复用处理后的密钥字节 final ivBytes = keyBytes; // 初始化AES/CBC加密器 final cipher = PaddedBlockCipherImpl( PKCS7Padding(), CBCBlockCipher(AESEngine()), )..init( true, PaddedBlockCipherParameters( ParametersWithIV(KeyParameter(keyBytes), ivBytes), null, ), ); final plainBytes = Uint8List.fromList(utf8.encode(plainText)); final cipherBytes = cipher.process(plainBytes); // Base64编码输出密文 return base64Encode(cipherBytes); } /// 对齐Java Decrypt方法的解密逻辑 static String decrypt(String cipherText, String key) { final keyBytes = _processKeyBytes(key); final ivBytes = keyBytes; // 初始化AES/CBC解密器 final cipher = PaddedBlockCipherImpl( PKCS7Padding(), CBCBlockCipher(AESEngine()), )..init( false, PaddedBlockCipherParameters( ParametersWithIV(KeyParameter(keyBytes), ivBytes), null, ), ); // 先Base64解码密文再解密 final cipherBytes = base64Decode(cipherText); final plainBytes = cipher.process(cipherBytes); return utf8.decode(plainBytes); } }
用例验证
使用给定测试参数调用方法即可得到与Java完全一致的结果:
void main() { const testPlain = "This is plain text"; const testKey = "sahtojetrout2"; final encrypted = AesCbc128Util.encrypt(testPlain, testKey); print(encrypted); // 输出 8FmSMnDsFJVyNUXunhJLSmhFnRq89fl5DyTp0wdYfgk=,与Java结果完全匹配 final decrypted = AesCbc128Util.decrypt(encrypted, testKey); print(decrypted); // 输出 This is plain text }
之前使用cryptography库实现失败的核心原因是:该库默认会自动生成随机IV,且默认密钥校验逻辑不支持自动截断长密钥、自动补0对齐短密钥,和Java的自定义处理逻辑不兼容,替换为上述实现即可完全对齐两端结果。
内容的提问来源于stack exchange,提问作者Munsif Ali
相关产品推荐
相关产品推荐

