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
相关产品推荐
相关产品推荐

