使用 IXmlSerializable (c#) 时加密 XML 文件
Encrypted XML file when using IXmlSerializable (c#)
如何编写一个 XML- 文件,并使用 IXmlSerializable 以加密方式对其进行序列化?
我将我的数据(包含节点的节点结构,就像文件系统文件夹)(反)序列化为 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);
}
}
}
上面的代码显示了序列化代码,省略了反序列化,因为我认为不需要它来解决问题。
那么如何在反序列化之前写入加密文件并解密呢? encryption/decryption 应该发生在内存中(我不想先写一个未加密的文件然后读回来加密它)
编辑:使用 "encryption" 我的意思是该文件不应该是人类可读的或其他程序在不知道如何解密(对称密钥)的情况下无法解析的文件
更新 1:
这是相同的实现,但作为支持 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);
}
}
}
}
}
而用法如下:
SerializeToEncryptedXmlFile(CharacterData.RandomInstance, "c:\temp\enc.xml");
CharacterData instance = DeserializeFromEncryptedXmlFile<CharacterData>("c:\temp\enc.xml");
原始答案:
要实现完全加密,将 CryptoStream
实例传递给 XmlSerializer。
这是一个使用 AesManaged 的示例,涵盖了加密和解密。
注意: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();
}
如何编写一个 XML- 文件,并使用 IXmlSerializable 以加密方式对其进行序列化?
我将我的数据(包含节点的节点结构,就像文件系统文件夹)(反)序列化为 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);
}
}
}
上面的代码显示了序列化代码,省略了反序列化,因为我认为不需要它来解决问题。
那么如何在反序列化之前写入加密文件并解密呢? encryption/decryption 应该发生在内存中(我不想先写一个未加密的文件然后读回来加密它)
编辑:使用 "encryption" 我的意思是该文件不应该是人类可读的或其他程序在不知道如何解密(对称密钥)的情况下无法解析的文件
更新 1:
这是相同的实现,但作为支持 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);
}
}
}
}
}
而用法如下:
SerializeToEncryptedXmlFile(CharacterData.RandomInstance, "c:\temp\enc.xml");
CharacterData instance = DeserializeFromEncryptedXmlFile<CharacterData>("c:\temp\enc.xml");
原始答案:
要实现完全加密,将 CryptoStream
实例传递给 XmlSerializer。
这是一个使用 AesManaged 的示例,涵盖了加密和解密。
注意: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();
}