如何在Dart/Flutter中实现与PHP一致的AES-256-CBC加解密
问题根源
你之前编写的Dart代码存在两处核心逻辑和PHP端不匹配,导致加解密无法互通:
- 未显式指定AES加密模式与填充规则,依赖encrypt库的默认配置,和PHP端AES-256-CBC + 默认PKCS7填充的行为存在差异
- 返回值格式不符合PHP端约定:PHP端逻辑是将原始IV二进制字节、原始密文二进制字节直接拼接后,对整个拼接后的二进制串做一次base64编码。你之前的实现要么只返回密文的base64(缺失IV信息),要么将IV的base64字符串和密文的base64字符串直接拼接(两段编码文本拼接后,PHP端整体解码无法拿到正确的16位原始IV,密文分段完全错乱)。
对齐实现
首先在pubspec.yaml中添加依赖:
dependencies: encrypt: ^5.0.3
以下是和PHP端逻辑1:1对齐的Dart实现,可直接使用:
import 'dart:convert'; import 'package:encrypt/encrypt.dart'; class AESEncrypter { /// 对齐PHP端的密钥处理逻辑 static String _formatKey(String phrase) { if (phrase.length < 32) { while (phrase.length < 32) { phrase += phrase; } } return phrase.substring(0, 32); } /// 加密,输出格式和PHP端EncryptString完全一致 static String encryptString(String plainText, String phrase) { final key = Key.fromUtf8(_formatKey(phrase)); // 生成16位安全随机IV,和PHP端AES-256-CBC的IV长度一致 final iv = IV.fromSecureRandom(16); // 显式指定CBC模式、PKCS7填充,和PHP openssl默认行为对齐 final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7')); final encrypted = encrypter.encrypt(plainText, iv: iv); // 原始IV字节 + 原始密文字节拼接后,整体做base64编码 final combinedBytes = List<int>.from(iv.bytes)..addAll(encrypted.bytes); return base64.encode(combinedBytes); } /// 解密,可直接解密PHP端EncryptString生成的密文 static String decryptString(String cipherText, String phrase) { final key = Key.fromUtf8(_formatKey(phrase)); final combinedBytes = base64.decode(cipherText); // 前16字节为IV,剩余部分为密文 final iv = IV(combinedBytes.sublist(0, 16)); final encryptedBytes = combinedBytes.sublist(16); final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: 'PKCS7')); return encrypter.decrypt(Encrypted(encryptedBytes), iv: iv); } }
验证注意事项
- 密钥处理逻辑严格对齐:传入phrase长度不足32位时重复拼接至长度≥32后截断前32位,长度超过32位直接截断前32位
- 字节拼接顺序必须保持IV在前、密文在后,不可调换顺序
- 禁止单独对IV或密文做base64后再拼接字符串,必须拼接原始二进制字节后再统一编码
- 生产环境不要使用固定IV,保持随机生成即可,IV不需要保密,拼接在密文前传输符合安全规范
内容的提问来源于stack exchange,提问作者Ariel Soriano Vassia
相关产品推荐
相关产品推荐

