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

带自定义XML头的3DES加密文件解密长度异常问题求助

解决加密文件XML头导致的解密长度异常问题

看起来你遇到的核心问题是XML头写入时引入了额外字节(大概率是UTF-8的字节顺序标记BOM),导致解密时读取的加密数据起始位置错误,进而触发CryptographicException。下面是具体的分析和解决步骤:

问题根源

你使用XmlDocument.Save(output)写入XML头时,.NET默认会给UTF-8编码的XML添加3字节的BOM(EF BB BF),这部分字节没有被你的readHeader方法计入position,导致解密时从错误的位置开始读取数据——把BOM或者XML末尾的部分字节当成了加密数据的一部分,破坏了ANSIX923填充要求的块大小对齐规则,最终抛出"length of the data to decrypt is invalid"异常。

解决方案

1. 移除UTF-8 BOM,避免额外字节干扰

修改setHeader方法,使用不带BOM的UTF-8编码保存XML,这样就不会产生额外的3字节:

private void setHeader(FileStream output, byte[] sal) {
    XmlDocument doc = new XmlDocument();
    XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
    doc.AppendChild(docNode);
    // ... 其他创建XML节点的代码保持不变 ...

    // 替换原来的doc.Save(output)
    var settings = new XmlWriterSettings
    {
        Encoding = new UTF8Encoding(false), // 禁用BOM的UTF-8
        Indent = false // 关闭缩进,避免额外空白字节
    };
    using (var writer = XmlWriter.Create(output, settings))
    {
        doc.Save(writer);
    }
}

2. 确保readHeader准确计算XML结束位置

你的readHeader方法需要精确记录XML头结束后的文件位置,避免因为XML解析跳过BOM或空白字符导致位置偏移。推荐使用XmlReader来读取XML,这样可以在XML结束后立即停止,获取准确的position:

private void readHeader(String inName, out int position, out Header header) {
    header = new Header();
    using (FileStream fin = new FileStream(inName, FileMode.Open, FileAccess.Read))
    {
        // 检查并跳过BOM(如果之前没移除BOM的话)
        byte[] bom = new byte[3];
        int bomRead = fin.Read(bom, 0, 3);
        bool hasBom = bomRead == 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF;
        if (!hasBom)
        {
            fin.Position = 0; // 没有BOM,回到文件开头
        }

        using (XmlReader reader = XmlReader.Create(fin))
        {
            while (reader.Read())
            {
                if (reader.IsStartElement("EncryptedFileHeader"))
                {
                    reader.ReadStartElement("EncryptedFileHeader");
                    // 读取XML中的头部信息到Header对象
                    header.Algorithm = reader.ReadElementContentAsString("Algorithm", "");
                    header.KeySize = int.Parse(reader.ReadElementContentAsString("KeySize", ""));
                    header.BlockSize = int.Parse(reader.ReadElementContentAsString("BlockSize", ""));
                    header.CipherMode = reader.ReadElementContentAsString("CipherMode", "");
                    header.IV = System.Text.Encoding.UTF8.GetBytes(reader.ReadElementContentAsString("IV", ""));
                    
                    // 跳过ApprovedUsers节点(不需要解析的话)
                    reader.ReadToFollowing("ApprovedUsers");
                    reader.Skip();
                    
                    reader.ReadEndElement(); // 结束EncryptedFileHeader节点
                    break;
                }
            }
            position = (int)fin.Position; // 记录XML结束后的位置
        }
    }
}

3. 验证解密时的长度计算

确保解密时totlen的计算是准确的:

long totlen = fin.Length - position;

这个逻辑是对的,但前提是position确实是XML头结束后的准确位置——上面的readHeader修改已经保证了这一点。

额外检查点

  • 确认加密和解密时的PaddingMode完全一致(你已经都设为ANSIX923,没问题)。
  • 加密时,setHeader执行后,fout的Position会自动停在XML末尾,后续CryptoStream写入加密数据的逻辑是正确的,不需要额外调整。

按照以上步骤修改后,应该就能解决解密时的长度异常问题了。

内容的提问来源于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 06:57:46