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

Flutter中使用pointycastle实现AES解密时出现RangeError求助

问题:Flutter中使用PointyCastle实现AES解密时出现RangeError

我是密码学领域的新手,正在尝试在Flutter中使用pointycastle(不打算更换包)实现AES加解密功能,但解密时出现问题。以下是我的代码:

Future<String> aesEncrypt(String plainText, key, iv) async {
    final convertedText = utf8.encode(plainText);
    final keyBytes = base64Decode(key);
    final ivbytes = base64Decode(iv);

    final keyParams = KeyParameter(keyBytes);
    final params = ParametersWithIV(keyParams, ivbytes);

    final cipher = BlockCipher('AES/CBC')..init(true, params);

    final paddedData = _padData(convertedText);
    final encryptedBytes = cipher.process(paddedData);
    return base64Encode(encryptedBytes);
  }

  Future<String> aesDecrypt(String encryptedText, key, iv) async {
    final data = base64Decode(encryptedText);
    
    final keyBytes = base64Decode(key);
    final ivbytes = base64Decode(iv);

    final keyParams = KeyParameter(keyBytes);
    final params = ParametersWithIV(keyParams, ivbytes);

    final cipher = BlockCipher('AES/CBC')..init(false, params);

    final decryptedBytes = cipher.process(data);
    final unpaddedData = _unpadData(decryptedBytes);

    return utf8.decode(unpaddedData);
  }

  Uint8List _padData(Uint8List data) {
    final blockSize = 16;
    final padLength = blockSize - (data.length % blockSize);
    final paddedData = Uint8List(data.length + padLength)..setAll(0, data);
    for (int i = data.length; i < paddedData.length; i++) {
      paddedData[i] = padLength;
    }
    return paddedData;
  }

  Uint8List _unpadData(Uint8List data){
    final padLength = data[data.length - 1];
    return Uint8List.sublistView(data, 0, data.length - padLength);
  }

  String generateKey(){
    final random = math.Random.secure();

    //Generate random key
    final keyBytes = Uint8List(16);
    for(int i = 0; i < keyBytes.length; i++){
      keyBytes[i] = random.nextInt(256);
    }

    return base64Encode(keyBytes);
  }

  String generateIV(){
    final random = math.Random.secure();

    //Generate random key
    final ivBytes = Uint8List(16);
    for(int i = 0; i < ivBytes.length; i++){
      ivBytes[i] = random.nextInt(256);
    }

    return base64Encode(ivBytes);
  }

(忽略生成密钥和IV的函数重复这一点),错误出现在_unpadData函数的return Uint8List.sublistView(data, 0, data.length - padLength);行,错误信息为:

Exception has occurred.
RangeError (RangeError (end): Invalid value: Not in inclusive range 0..16: -89)


原因分析

这个错误的核心是解密后的字节数据已损坏,导致读取到的padLength是异常值(比如超出1-16的合法范围),计算data.length - padLength时得到负数,超出了sublistView的合法索引范围。具体可能的诱因:

  • Cipher实例化错误:直接用BlockCipher('AES/CBC')字符串构造器可能没有正确初始化CBC模式,导致加解密的块处理逻辑不一致,解密出乱码数据。
  • 密钥/IV不匹配:解密时使用的key或iv和加密时不一致,包括base64解码后的字节长度(AES密钥必须是16/24/32字节对应AES-128/192/256,IV必须是16字节)。
  • 填充校验缺失:没有验证填充字节的合法性,当解密数据损坏时,直接使用异常的padLength计算索引。

解决方案

  1. 修正Cipher实例化方式
    改用PointyCastle的标准构造方式初始化CBC模式的AES加密器,避免字符串构造器的潜在问题:

    // 加密时
    final cipher = CbcBlockCipher(AesEngine())..init(true, params);
    // 解密时
    final cipher = CbcBlockCipher(AesEngine())..init(false, params);
    
  2. 验证密钥和IV的一致性与合法性
    确保加解密使用完全相同的key和iv,且解码后的字节长度符合要求:

    // 加密和解密时都可以添加校验
    assert(keyBytes.length == 16 || keyBytes.length == 24 || keyBytes.length == 32, "Invalid AES key length");
    assert(ivbytes.length == 16, "Invalid IV length");
    
  3. 添加填充合法性校验
    在_unpadData中先校验填充长度和填充字节的合法性,避免异常值导致的索引错误:

    Uint8List _unpadData(Uint8List data){
      final padLength = data[data.length - 1];
      // 校验填充长度是否在合法范围(1-16,AES块大小为16)
      if (padLength < 1 || padLength > 16 || padLength > data.length) {
        throw ArgumentError('Invalid padding length');
      }
      // 校验所有填充字节是否等于padLength(符合PKCS7标准)
      for (int i = data.length - padLength; i < data.length; i++) {
        if (data[i] != padLength) {
          throw ArgumentError('Invalid padding bytes');
        }
      }
      return Uint8List.sublistView(data, 0, data.length - padLength);
    }
    
  4. 确认填充逻辑正确性
    你的_padData实现是标准的PKCS7填充,当原数据长度为块大小整数倍时,会填充整个块的字节(16个0x10),这符合规范,无需修改。


内容的提问来源于stack exchange,提问作者Nick Haimovich

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:34:55