带自定义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
相关产品推荐
相关产品推荐

