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

Unity中AES分块解密遇PKCS7填充错误的解决问询

分块解密AES加密视频时的PKCS7填充异常解决

问题背景

我在Unity项目中使用AES加密磁盘上的视频文件,解密后通过HTTP服务器流式传输。实现分块解密时触发以下异常:

CryptographicException: Bad PKCS7 padding. Invalid length 0.

异常在手动关闭CryptoStream或其被using语句自动释放时触发。用try/catch包裹关闭操作能抑制异常,但生成的解密文件存在伪影、已损坏。

触发错误的分块解密代码

public static int ServeVideoChunk(Stream encryptedStream, Stream outputStream, int offset, int chunk)
{
    var position = encryptedStream.Seek(offset, SeekOrigin.Begin);

    using var aes = Aes.Create();
    aes.Key = Key; // 预定义128位密钥
    aes.IV = Iv; // 预定义128位初始化向量

    using var cryptoStream = new CryptoStream(encryptedStream, aes.CreateDecryptor(), CryptoStreamMode.Read);

    // 对齐AES块大小
    var delta = encryptedStream.Length - position;
    var isEOF = chunk > delta;
    chunk = (int)(isEOF ? delta : chunk);
    chunk -= chunk % (aes.BlockSize / 8);

    var buffer = new byte[chunk];
    var totalReadBytes = cryptoStream.Read(buffer, 0, chunk);

    outputStream.Write(buffer, 0, totalReadBytes);

    // 强制关闭流以捕获PKCS7异常,尝试读取文件末尾
    try
    {
        cryptoStream.Close();
    }
    catch (Exception e)
    {
        Debug.Log(e);
    }

    return totalReadBytes;
}

若不用try/catch,异常会在using语句结束释放流时抛出。

补充细节

正常运行的加密代码

public static void EncryptFile(string inputFilePath, string outputFilePath)
{
    Debug.Log($"Encrypt InputPath: {inputFilePath} OutputPath: {outputFilePath}");

    using (var aes = Aes.Create())
    {
        aes.Key = Key;
        aes.IV = Iv;

        using (var fileStream = new FileStream(outputFilePath, FileMode.Create))
        using (var cryptoStream = new CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
        using (var inputFileStream = new FileStream(inputFilePath, FileMode.Open))
        {
            inputFileStream.CopyTo(cryptoStream);
        }
    }

    Debug.Log("Encryption complete.");
}

无异常的全量解密代码

一次性解密整个文件无问题,解密后的视频无伪影:

public static void DecryptFile(Stream encryptedStream, Stream outputStream)
{
    using var aes = Aes.Create();
    aes.Key = Key;
    aes.IV = Iv;

    using var cryptoStream = new CryptoStream(encryptedStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
    cryptoStream.CopyTo(outputStream);
}

但该方式不支持分块读取,无法满足HTTP流式传输的需求。

分块解密测试代码(模拟HTTP客户端)

private void Start()
{
    var videoPath = UseShortVideo ? ShortVideoPath : VideoPath;
    var encryptedVideoPath = UseShortVideo ? ShortEncryptedVideoPath : EncryptedVideoPath;

    if (Encrypt)
    {
        VideoEncryption.EncryptFile(videoPath, encryptedVideoPath);
    }

    var encryptedVideoFile = new FileInfo(encryptedVideoPath);

    using var outputStream = new FileStream($"{encryptedVideoFile.Directory.FullName}/{DecryptedMovieName}",
        FileMode.Create, FileAccess.Write);

    DecryptByChunk(encryptedVideoPath, outputStream);
}

private static void DecryptByChunk(string inputPath, Stream outputStream)
{
    var offset = 0;
    var chunk = 2 * 1024 * 1024;
    long fileSize;
    do
    {
        using var encryptedStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
        fileSize = encryptedStream.Length;

        int totalBytesRead = VideoEncryption.ServeVideoChunk(encryptedStream, outputStream, offset, chunk);

        offset += totalBytesRead;

        if (totalBytesRead == 0)
        {
            Debug.Log($"End of file i: {offset} | total: {fileSize}");
            break;
        }

        Debug.Log($"Offset: {offset} | total: {fileSize}");
    } while (offset < fileSize);
}

已尝试的方案

  • 验证加密和解密的Key与IV完全一致
  • 确认加密流长度是AES-128块大小(16字节)的整数倍
  • 用try/catch抑制异常,生成的文件存在伪影损坏

核心问题

如何可靠实现AES加密数据的分块解密,避免PKCS7填充异常且保证输出文件完整无损坏?


编辑于2025/03/28

感谢@Topaco的评论,问题已解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:20:56