好的,所以我有了将播放器对象序列化为 XML 文件的方法, 在将对象写入文件之前,我一直试图找到一种加密数据的方法。 这里和互联网上有很多关于这个主题的帖子,我试图合并所有数据,以便它适用于我的应用程序,结果是这样的:
public static async Task SaveAsync<T>(Player player)
{
IRandomAccessStream sessionRandomAccess = null;
string strAlgName = SymmetricAlgorithmNames.AesCbc;
UInt32 keyLength = 32;
CryptographicKey key;
SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
IBuffer keyMaterial = CryptographicBuffer.GenerateRandom(keyLength);
key = objAlg.CreateSymmetricKey(keyMaterial);
IBuffer iv = null;
if (strAlgName.Contains("CBC"))
{
iv = CryptographicBuffer.GenerateRandom(objAlg.BlockLength);
}
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("Data.xml", CreationCollisionOption.ReplaceExisting);
sessionRandomAccess = await sessionFile.OpenAsync(FileAccessMode.ReadWrite);
IBuffer buffEncrypt = CryptographicEngine.Encrypt(key, ReadFully(sessionRandomAccess.AsStream()).AsBuffer(), iv);
DataContractSerializer sessionSerializer = new DataContractSerializer(typeof(Player), new Type[] { typeof(T) });
Stream stream = buffEncrypt.AsStream();
sessionSerializer.WriteObject(stream, player);
await stream.FlushAsync();
}
以及将流转换为字节数组的方法:
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
现在一切正常,直到 WriteObject 方法被调用然后我会得到这个异常:
An exception of type 'System.NotSupportedException' occurred in mscorlib.ni.dll but was not handled in user code
Additional information: Unable to expand length of this stream beyond its capacity.
任何人都知道如何解决这个问题以及它为什么会发生? 谢谢
更新: 我想我可以将对我有用的解密方法添加到包含 Jay Zuo - MSFT 的加密部分的伟大答案中。
所以这里是:
public static async Task<Player> LoadAsync<T>()
{
try
{
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("Data.xml", CreationCollisionOption.OpenIfExists);
if (sessionFile == null)
{
return null;
}
IBuffer buffEncrypt = await FileIO.ReadBufferAsync(sessionFile);
String strAlgName = SymmetricAlgorithmNames.AesCbcPkcs7;
CryptographicKey key; // Symmetric key
// Open a symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
key = objAlg.CreateSymmetricKey(keyMaterial);
IBuffer buffMsg=CryptographicEngine.Decrypt(key, buffEncrypt, iv);
DataContractSerializer sessionSerializer = new DataContractSerializer(typeof(Player));
return (Player)sessionSerializer.ReadObject(buffMsg.AsStream());
}
catch (Exception e)
{
}
return null;
}
请注意两件事,即 iv IBuffer 和 keyMaterial,它们按照 Jay Zuo - MSFT 的建议从数据库中存储和加载。 希望这对某些人有所帮助:)
最佳答案
要加密序列化对象,我们可以得到 IBuffer首先表示序列化对象。
IBuffer buffMsg;
DataContractSerializer sessionSerializer = new DataContractSerializer(typeof(Player));
using (var stream = new MemoryStream())
{
sessionSerializer.WriteObject(stream, player);
buffMsg = stream.ToArray().AsBuffer();
}
然后我们可以像下面这样加密缓冲区:
IBuffer iv; // Initialization vector
CryptographicKey key; // Symmetric key
UInt32 keyLength = 32; // Length of the key, in bytes
String strAlgName = SymmetricAlgorithmNames.AesCbc;
// Initialize the initialization vector.
iv = null;
// Open a symmetric algorithm provider for the specified algorithm.
SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);
// Determine whether the message length is a multiple of the block length.
// This is not necessary for PKCS #7 algorithms which automatically pad the
// message to an appropriate length.
if (!strAlgName.Contains("PKCS7"))
{
if ((buffMsg.Length % objAlg.BlockLength) != 0)
{
throw new Exception("Message buffer length must be multiple of block length.");
}
}
// Create a symmetric key.
IBuffer keyMaterial = CryptographicBuffer.GenerateRandom(keyLength);
key = objAlg.CreateSymmetricKey(keyMaterial);
// CBC algorithms require an initialization vector. Here, a random
// number is used for the vector.
if (strAlgName.Contains("CBC"))
{
iv = CryptographicBuffer.GenerateRandom(objAlg.BlockLength);
}
// Encrypt the data and return.
IBuffer buffEncrypt = CryptographicEngine.Encrypt(key, buffMsg, iv);
一旦我们有了加密缓冲区,我们就可以将它写入文件:
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("Data.xml", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBufferAsync(sessionFile, buffEncrypt);
请注意SymmetricAlgorithmNames.AesCbc是 no padding algorithm .使用此算法时,我们要加密的消息缓冲区长度必须是 block 长度的倍数。由于序列化对象的缓冲区长度是可变的,我建议使用 PKCS #7 算法,例如 SymmetricAlgorithmNames.AesCbcPkcs7而不是 SymmetricAlgorithmNames.AesCbc
。而对于解密,您可能还需要存储对称 key 和初始化向量。
关于c# - 在 UWP 应用程序中使用加密将对象序列化为文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40688780/