c# - 在 UWP 应用程序中使用加密将对象序列化为文件

标签 c# encryption serialization uwp

好的,所以我有了将播放器对象序列化为 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.AesCbcno padding algorithm .使用此算法时,我们要加密的消息缓冲区长度必须是 block 长度的倍数。由于序列化对象的缓冲区长度是可变的,我建议使用 PKCS #7 算法,例如 SymmetricAlgorithmNames.AesCbcPkcs7而不是 SymmetricAlgorithmNames.AesCbc。而对于解密,您可能还需要存储对称 key 初始化向量

关于c# - 在 UWP 应用程序中使用加密将对象序列化为文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40688780/

相关文章:

c# - MVC4 EF代码在生产中首先数据库初始化不完整

c++ - 将 Botan 加密结果输出到 QDomDocument,反之亦然

c# - 这是在 Db 中加盐和存储密码的方法吗?

c# - 新添加成员后反序列化类时出现问题

kotlin - 如何(反)序列化生成的数据类的实例

java - 从 Android 中的 .ser 文件读取/解析 JSON 对象

javascript - 在 Unity 中使用的最佳容器容器是什么?

c# - 访问路径 'd:\$RECYCLE.BIN\S-1-5-21-494745725-312220573-749543506-41600' 被拒绝

c# - 单元测试 - 更新模型

java - 使用 OpenSSL (RSA-2048 Public-/Private-Key) 解密已非对称加密 (AES-256) 的 Java 文件