Flutter端AES-256加密实现(适配Java后端解密)
Flutter端适配Java AES加解密的加密实现
实现说明
- 现有两端解密逻辑的核心参数已经完全对齐,只需要按照Java端加密的输出格式补全Flutter加密逻辑即可实现双向互通
- 加密逻辑完全对齐Java端规则:20字节随机盐 + 16字节随机IV + AES/CBC模式加密 + 密钥通过PBKDF2WithHmacSHA1派生(迭代次数65556,密钥长度256位)
- 填充规则使用PKCS7Padding,和Java端的PKCS5Padding在AES块大小为16字节的场景下完全兼容
- 随机数使用Dart安全随机生成器,和Java端
SecureRandom安全等级一致 - 最终输出为「盐+IV+密文」拼接后的Base64字符串,和Java端加密输出格式完全一致,Java端无需修改任何代码即可正常解密
前置依赖
现有解密逻辑已经依赖pointycastle加密库,确保项目中已经引入该依赖即可,无需额外引入其他包。
完整实现代码
import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; import 'package:pointycastle/export.dart'; class EncryptionHelper { /// 加密方法,输出密文可直接被Java端decrypt方法解密 static String encrypt(String plaintext, {String password = "Hello"}) { final secureRandom = Random.secure(); // 生成20字节随机盐,和Java端盐长度一致 final saltBytes = Uint8List.fromList( List.generate(20, (_) => secureRandom.nextInt(256)) ); // 生成16字节IV,对应AES块大小 final ivBytes = Uint8List.fromList( List.generate(16, (_) => secureRandom.nextInt(256)) ); // 复用现有密钥生成逻辑,派生256位AES密钥 final key = generateKey(password, saltBytes); // 初始化AES/CBC/PKCS7加密器 final cipher = CBCBlockCipher(AESFastEngine()); final cipherParams = ParametersWithIV<KeyParameter>( KeyParameter(key), ivBytes ); final paddingParams = PaddedBlockCipherParameters< ParametersWithIV<KeyParameter>, Null >(cipherParams, null); final paddedCipher = PaddedBlockCipherImpl(PKCS7Padding(), cipher); // 传入true表示初始化为加密模式 paddedCipher.init(true, paddingParams); // 明文转UTF-8字节数组后执行加密 final plainBytes = Uint8List.fromList(utf8.encode(plaintext)); final encryptedBytes = paddedCipher.process(plainBytes); // 按 盐 + IV + 密文 的顺序拼接字节数组,和Java端拼接逻辑完全一致 final resultBuffer = Uint8List( saltBytes.length + ivBytes.length + encryptedBytes.length ); resultBuffer.setAll(0, saltBytes); resultBuffer.setAll(saltBytes.length, ivBytes); resultBuffer.setAll(saltBytes.length + ivBytes.length, encryptedBytes); // 最终Base64编码返回 return base64.encode(resultBuffer); } /// 原有解密方法,无需修改 static String decrypt( String ciphertext, ) { Uint8List ciphertextlist = base64.decode(ciphertext); var salt = ciphertextlist.sublist(0, 20); var iv = ciphertextlist.sublist(20, 20 + 16); var encrypted = ciphertextlist.sublist(20 + 16); Uint8List key = generateKey("Hello", salt); CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine()); ParametersWithIV<KeyParameter> params = new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv); PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null> paddingParams = new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>( params, null); PaddedBlockCipherImpl paddingCipher = new PaddedBlockCipherImpl(new PKCS7Padding(), cipher); paddingCipher.init(false, paddingParams); var val = paddingCipher.process(encrypted); return new String.fromCharCodes(val); } /// 原有密钥生成方法,无需修改 static Uint8List generateKey(String passphrase, Uint8List salt) { Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits); KeyDerivator derivator = PBKDF2KeyDerivator(HMac(SHA1Digest(), 64)); // 64 byte block size Pbkdf2Parameters params = Pbkdf2Parameters(salt, 65556, 32); // 32 byte key size derivator.init(params); return derivator.process(passphraseInt8List); } }
验证说明
- 该方法加密输出的密文,可以直接传入现有Java端
decrypt方法解密得到正确明文 - 该方法加密输出的密文,也可以直接传入现有Flutter端
decrypt方法解密得到正确明文 - 两端加解密完全双向互通,不需要修改现有Java端和Flutter端的原有解密逻辑
内容的提问来源于stack exchange,提问作者yong ho
相关产品推荐
相关产品推荐

