简体   繁体   English

使用 IXmlSerializable (c#) 时加密的 XML 文件

[英]Encrypted XML file when using IXmlSerializable (c#)

How can I write a XML-File to which I serialize using IXmlSerializable in an encrypted way?如何以加密方式编写使用 IXmlSerializable 序列化的 XML 文件?

I (de-)serialize my data (a structure of nodes containig nodes, just like filesystemfolders) into a xml-File:我将我的数据(包含节点的节点结构,就像文件系统文件夹一样)(反)序列化为 xml 文件:

public class DataNodeCollection : List<DataNode>, IXmlSerializable
{
    internal void Serialize()
    {
        string sFilename = getFilename();
        using (var writer = new StreamWriter(sFilename, false, Encoding.Unicode))
        {
            var serializer = new XmlSerializer(this.GetType(), new XmlRootAttribute("SystemNodes"));
            serializer.Serialize(writer, this);
            writer.Flush();
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("FileFormatVersion", CurrentFormatVersion.ToString(CultureInfo.InvariantCulture));

        foreach (DataNode elem in this)
        {
            var innerSerializer = new XmlSerializer(typeof(DataNode), new XmlRootAttribute(elem.Name));
            innerSerializer.Serialize(writer, elem);
        }
    }
}

public class DataNode : IXmlSerializable
{
        private IDictionary<string, string> _mapAttributes = new Dictionary<string, string>();
        private IList<DataNode> _subNodes = new List<DataNode>();

        public string Name { get; protected set; }

        public void WriteXmlXmlWriter writer)
        {
            foreach (string sKey in _mapAttributes.Keys)
            {
                writer.WriteAttributeString(sKey, _mapAttributes[sKey]);
            }

            foreach (DataNode node in _subNodes)
            {
                var innerSerializer = new XmlSerializer(typeof(DataNode), new XmlRootAttribute(node.Name));
                innerSerializer.Serialize(writer, node);
            }
        }
}

The code above shows the serialilzation-code, deserialisation is omitted because I don't think its needed to get the problem.上面的代码显示了序列化代码,省略了反序列化,因为我认为不需要它来解决问题。

So how can I write the file encrypted and decrypt it before deserialising?那么如何在反序列化之前编写加密和解密的文件呢? The encryption/decryption should happen in memory (I don't want to write an unencrypted file first and read it back to encrypt it)加密/解密应该发生在 memory (我不想先写一个未加密的文件然后再读回加密它)

edit: With "encryption" I mean the file should not be human readable or parseable by other programs without knowing how to decrypt it (symmetric key)编辑:使用“加密”我的意思是该文件不应该是人类可读或不知道如何解密它的其他程序解析(对称密钥)

UPDATE 1:更新 1:

Here is the same implementation but as two methods supporting Unicode encoding and probably mitigating the code analysis issues.这是相同的实现,但有两种方法支持 Unicode 编码并可能缓解代码分析问题。

static void SerializeToEncryptedXmlFile(object graph, string filePath)
{
    using (FileStream encryptedFileStream = File.Create(filePath))
    {
        using (AesManaged aesManaged = CreateAesManaged())
        {
            using
            (
                CryptoStream cryptoStream = new CryptoStream
                (
                    encryptedFileStream, CreateAesManaged().CreateEncryptor(), CryptoStreamMode.Write
                )
            )
            {
                using (StreamWriter unicodeStreamWriter = new StreamWriter(cryptoStream, Encoding.Unicode))
                {
                    {
                        new XmlSerializer(typeof(CharacterData)).Serialize(unicodeStreamWriter, CharacterData.RandomInstance);
                        // If you dont use a using statement for the cryptoStream,
                        // Don't forget to call FlushFinalBlock yourself
                        // Or you will have padding problems.
                        // cryptoStream.FlushFinalBlock();
                    }
                }
            }
        }
    }
}

public static TResult DeserializeFromEncryptedXmlFile<TResult>(string filePath)
{
    using (FileStream encryptedFileStream = File.OpenRead(filePath))
    {
        using (AesManaged aesManaged = CreateAesManaged())
        {
            using
            (
                CryptoStream cryptoStream = new CryptoStream
                (
                    encryptedFileStream, aesManaged.CreateDecryptor(), CryptoStreamMode.Read
                )
            )
            {
                using (StreamReader unicodeStreamReader = new StreamReader(cryptoStream))
                {
                    return (TResult)new XmlSerializer(typeof(CharacterData)).Deserialize(unicodeStreamReader);
                }
            }
        }
    }
}

And the usage is as follows:用法如下:

SerializeToEncryptedXmlFile(CharacterData.RandomInstance, "c:\\temp\\enc.xml");
CharacterData instance = DeserializeFromEncryptedXmlFile<CharacterData>("c:\\temp\\enc.xml");

ORIGINAL ANSWER:原始答案:

To achieve complete encryption, pass a CryptoStream instance to the XmlSerializer.要实现完全加密,请将CryptoStream实例传递给 XmlSerializer。

Here is a sample using AesManaged covering both encryption and decryption.这是一个使用 AesManaged 的示例,涵盖了加密和解密。

Note: CharacterData is some XML serializable class which is not relevant here.注意:CharacterData 是一些 XML 可序列化 class ,这里不相关。

// Returns AesManaged with 256 bit key, 128 bit IV, PKCS7 padding and using CBC mode
private static AesManaged CreateAesManaged()
{
    return new AesManaged()
    {
        Key = Encoding.ASCII.GetBytes("This is the key%This is the key%"),
        IV = Encoding.ASCII.GetBytes("This is the IV%%")
    };
}

static void Main(string[] args)
{
    // Serialization / Encryption:
    using (FileStream encryptedFileStream = File.Create("C:\\temp\\enc.xml"))
    {
        using
        (
            CryptoStream cryptoStream = new CryptoStream
            (
                encryptedFileStream, CreateAesManaged().CreateEncryptor(), CryptoStreamMode.Write
            )
        )
        {
            new XmlSerializer(typeof(CharacterData)).Serialize(cryptoStream, CharacterData.RandomInstance);
            // If you dont use a using statement for the cryptoStream,
            // Don't forget to call FlushFinalBlock yourself
            // Or you will have padding problems.
            // cryptoStream.FlushFinalBlock();
        }
    }

    // De-Serialization / Decryption:
    using (FileStream encryptedFileStream = File.OpenRead("C:\\temp\\enc.xml"))
    {
        using
        (
            CryptoStream cryptoStream = new CryptoStream
            (
                encryptedFileStream, CreateAesManaged().CreateDecryptor(), CryptoStreamMode.Read
            )
        )
        {
            CharacterData instance = (CharacterData)new XmlSerializer(typeof(CharacterData)).Deserialize(cryptoStream);
        }
    }

    Console.ReadLine();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM