You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 12:05:32