使用Dart Encrypt包可加密但解密失败,报填充块损坏错误
问题:AES CBC解密时触发"Invalid or corrupted pad block"错误
我使用以下代码将用户密码加密后存储到Firestore数据库:
Future<String> _encryptPassword(String password, Uint8List key) async { final keyUint8List = key.sublist(0, 32); final iv = IV.fromLength(16); final encrypter = Encrypter(AES(Key(keyUint8List), mode: AESMode.cbc, padding: 'PKCS7')); final encryptedPassword = encrypter.encrypt(password, iv: iv); return base64Encode(encryptedPassword.bytes); }
从数据库获取密文后,用以下代码解密时,在执行final decryptedBytes = encrypter.decryptBytes(Encrypted(encryptedBytes), iv: iv);步骤触发错误:I/flutter (14298): Error decrypting passwords: Invalid argument(s): Invalid or corrupted pad block
已确认加密和解密使用的AES密钥一致,求解决该问题。
解决方案
1. 核心问题:IV不匹配(最可能原因)
CBC模式下,加密和解密必须使用完全相同的IV。当前代码中,加密和解密都调用IV.fromLength(16),这会生成随机的16字节IV——加密用的随机IV没有和密文一起存储,解密时生成新的随机IV,必然导致解密失败。
修改方案:
- 加密时将IV和密文一起存储到Firestore
- 解密时取出对应的IV进行解密
修改后的加密代码:
Future<Map<String, String>> _encryptPassword(String password, Uint8List key) async { final keyUint8List = key.sublist(0, 32); final iv = IV.fromLength(16); // 生成随机IV final encrypter = Encrypter(AES(Key(keyUint8List), mode: AESMode.cbc, padding: 'PKCS7')); final encryptedPassword = encrypter.encrypt(password, iv: iv); // 返回密文和对应的IV,一起存储到Firestore return { 'encrypted_password': base64Encode(encryptedPassword.bytes), 'iv': base64Encode(iv.bytes), }; }
修改后的解密代码:
Future<List<String>?> decryptPasswords( List<Map<String, dynamic>> passwordDataList, Uint8List aesKey) async { try { final List<String> decryptedPasswords = []; for (final passwordData in passwordDataList) { final encryptedPassword = passwordData['encrypted_password']; final ivBase64 = passwordData['iv']; // 取出存储的IV if (aesKey != null && ivBase64 != null) { final keyUint8List = aesKey.sublist(0, 32); final iv = IV.fromBase64(ivBase64); // 使用加密时的原始IV final encrypter = Encrypter( AES(Key(keyUint8List), mode: AESMode.cbc, padding: 'PKCS7')); final encryptedBytes = base64Decode(encryptedPassword); final decryptedBytes = encrypter.decryptBytes(Encrypted(encryptedBytes), iv: iv); final decryptedPassword = utf8.decode(decryptedBytes); decryptedPasswords.add(decryptedPassword); } } return decryptedPasswords; } catch (e) { print('Error decrypting passwords: $e'); return null; } }
2. 其他排查方向
- 密钥完整性检查:确认加密和解密时
key.sublist(0,32)获取的32字节完全一致,避免原始密钥长度不足或转码错误(比如字符串转Uint8List时编码不一致)。 - 密文完整性检查:打印加密后生成的base64字符串,与从Firestore取出的密文对比,确保没有被截断、添加额外字符(如空格、换行)。
- 依赖版本一致性:确认加密和解密环境使用的
encrypt包版本一致,避免版本差异导致的填充/模式实现变化。
内容的提问来源于stack exchange,提问作者Anubhav Sinha
相关产品推荐
相关产品推荐

