Flutter Dart中AES解密后JWT解码遇FormatException无效字符问题
问题原因分析
- JWT解码填充逻辑错误:当JWT payload的base64url编码长度为4的倍数时,原代码错误添加了4个
=填充,违反base64编码规则,直接导致解码失败。 - AES解密未处理PKCS7填充:CryptoJS默认使用PKCS7填充,而你的Dart代码仅用基础
BlockCipher解密,未自动去除填充字节,导致解密后的JWT末尾带有多余填充字符,进一步引发解码异常。
修复方案
1. 修正JWT解码的填充计算
修改decodeJWT方法,确保只添加符合规则的填充:
static String decodeJWT(String jwt) { final parts = jwt.split('.'); if (parts.length != 3) { return 'Invalid JWT format'; } final encodedPayload = parts[1]; // 正确计算填充数:长度为4的倍数时填充0个= final missingPadding = (4 - (encodedPayload.length % 4)) % 4; final paddedPayload = encodedPayload + '=' * missingPadding; try { final decodedPayload = String.fromCharCodes(base64Url.decode(paddedPayload)); print("payload $decodedPayload"); return decodedPayload; } catch (e) { print('JWT解码失败: $e'); print('原始payload编码: $encodedPayload'); return 'JWT解码失败: $e'; } }
2. 对齐CryptoJS的AES填充规则
使用PaddedBlockCipher处理PKCS7填充,确保解密结果无多余字符:
import 'package:pointycastle/padded_block_cipher/padded_block_cipher.dart'; import 'package:pointycastle/paddings/pkcs7.dart'; import 'package:pointycastle/block/modes/cbc.dart'; import 'package:pointycastle/block/aes_fast.dart'; static String decryptAES(String encryptedText, String password) { final keyBytes = Uint8List.fromList(utf8.encode(password)); final iv = Uint8List(16); // 注意:需和CryptoJS使用的IV完全一致,若对方用随机IV需从密文中提取 // 使用PKCS7填充的AES/CBC解密器 final cipher = PaddedBlockCipher("AES/CBC/PKCS7") ..init(false, ParametersWithIV(KeyParameter(keyBytes), iv)); final encryptedBytes = base64.decode(encryptedText); final decryptedBytes = cipher.process(encryptedBytes); final decryptedText = utf8.decode(decryptedBytes); print("解密后的JWT: $decryptedText"); // 打印结果排查格式问题 return decryptedText; }
额外注意事项
- IV一致性:如果CryptoJS加密时用的是随机生成的IV(而非全0),你需要从加密数据中提取IV(通常IV会附加在密文头部),不能硬编码全0IV,否则解密结果会损坏。
- 密钥匹配:确认CryptoJS是否直接用password作为AES密钥,还是通过PBKDF2等算法派生密钥。若为派生密钥,需在Dart中实现相同的派生逻辑(可借助
pointycastle的PBKDF2工具类)。
内容的提问来源于stack exchange,提问作者Nns_ninteyFIve
相关产品推荐
相关产品推荐

