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

C# TripleDES分块加密解密报‘Bad data’异常排查求助

解密时“Bad data”异常的排查与修复方案

嘿,我帮你揪出了两个核心问题——这就是你分块处理时解密失败的根源,而用TransformFinalBlock能正常运行,是因为它自动帮你处理了这些收尾步骤:

问题1:加密时错误使用GetBuffer()获取数据

MemoryStream.GetBuffer()返回的是流的底层缓冲区,这个缓冲区的长度会大于等于实际写入的有效数据(因为MemoryStream会预分配空间)。你把整个缓冲区转成Base64字符串,相当于给解密端传递了一堆无效的额外字节,TripleDES解密时识别到这些不属于加密数据的内容,直接抛出“Bad data”异常。

正确的做法是用MemoryStream.ToArray(),它只返回实际写入流的有效字节。

问题2:CryptoStream未调用FlushFinalBlock()处理收尾

分块加密/解密时,CryptoStream内部会维护一个缓冲区,最后一批数据可能还留在缓冲区里没写入目标流,尤其是PKCS7 padding的场景下,必须明确调用FlushFinalBlock()来处理最后的padding字节(加密时添加padding,解密时移除padding)。虽然Close()会间接触发这个操作,但手动调用更可靠,能确保所有数据都被正确处理。


修正后的加密代码

public string EncryptData(byte[] fileData, byte[] tdesKey, byte[] tdesIV)
{
    using (MemoryStream msInput = new MemoryStream(fileData))
    using (MemoryStream msOutput = new MemoryStream())
    {
        byte[] bin = new byte[100];
        long rdlen = 0;
        long totlen = msInput.Length;
        int len;

        using (TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider())
        {
            switch (mw.cmb_encryption_mode.Text)
            {
                case "ECB":
                    tdes.Mode = CipherMode.ECB;
                    break;
                case "CBC":
                    tdes.Mode = CipherMode.CBC;
                    break;
                case "CFB":
                    tdes.Mode = CipherMode.CFB;
                    break;
                case "OFB":
                    tdes.Mode = CipherMode.OFB;
                    break;
                default:
                    break;
            }
            tdes.Padding = PaddingMode.PKCS7;
            tdes.Key = tdesKey;
            // ECB模式不需要IV,跳过无效赋值
            if (tdes.Mode != CipherMode.ECB)
            {
                tdes.IV = tdesIV;
            }

            using (CryptoStream encStream = new CryptoStream(msOutput, tdes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                mw.encryption_progress_bar.Maximum = totlen;
                while (rdlen < totlen)
                {
                    len = msInput.Read(bin, 0, 100);
                    encStream.Write(bin, 0, len);
                    rdlen += len;
                    mw.encryption_progress_bar.Dispatcher.Invoke(() => 
                        mw.encryption_progress_bar.Value = rdlen, 
                        System.Windows.Threading.DispatcherPriority.Background);
                }
                // 关键:手动触发收尾处理,确保padding和缓冲区数据写入完成
                encStream.FlushFinalBlock();
            }
            // 仅返回有效加密数据
            return Convert.ToBase64String(msOutput.ToArray());
        }
    }
}

修正后的解密代码

public byte[] DecryptData(byte[] encryptedData, byte[] tdesKey, Header header, byte[] tdesIV)
{
    using (MemoryStream msInput = new MemoryStream(encryptedData))
    using (MemoryStream msOutput = new MemoryStream())
    {
        byte[] bin = new byte[100];
        long rdlen = 0;
        long totlen = msInput.Length;
        int len;

        using (TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider())
        {
            switch (header.cipherMode)
            {
                case "ECB":
                    tdes.Mode = CipherMode.ECB;
                    break;
                case "CBC":
                    tdes.Mode = CipherMode.CBC;
                    break;
                case "CFB":
                    tdes.Mode = CipherMode.CFB;
                    break;
                case "OFB":
                    tdes.Mode = CipherMode.OFB;
                    break;
                default:
                    break;
            }
            tdes.Padding = PaddingMode.PKCS7;
            tdes.Key = tdesKey;
            if (tdes.Mode != CipherMode.ECB)
            {
                tdes.IV = tdesIV;
            }

            using (CryptoStream decStream = new CryptoStream(msOutput, tdes.CreateDecryptor(), CryptoStreamMode.Write))
            {
                mw.decryption_progress_bar.Maximum = totlen;
                while (rdlen < totlen)
                {
                    len = msInput.Read(bin, 0, 100);
                    decStream.Write(bin, 0, len);
                    rdlen += len;
                    mw.decryption_progress_bar.Dispatcher.Invoke(() => 
                        mw.decryption_progress_bar.Value = rdlen, 
                        System.Windows.Threading.DispatcherPriority.Background);
                }
                // 关键:手动处理收尾,确保padding被正确移除
                decStream.FlushFinalBlock();
            }
            // 仅返回有效解密数据
            return msOutput.ToArray();
        }
    }
}

额外优化提示

  • 我给代码加上了using语句,确保所有实现IDisposable的对象(流、加密服务、加密流)都能被正确释放,避免资源泄漏。
  • TripleDESCryptoServiceProvider已被标记为过时,推荐使用TripleDES.Create()来创建加密实例,不过这是次要问题,先解决当前解密失败的核心需求更优先。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:08:46