使用 DPAPI 更新 XDocument 不起作用?

updating XDocument with DPAPI not working?

我是 C# 和密码学的新手,但我想保护一些数据,例如在 C# 项目中使用 DPAPI 的帐户。 我尝试了一些方法来做到这一点,但传递的数据是 XDocument 并且必须保持原样。

我尝试传递一个字符串并修改它没有问题,但是当涉及到 XML 数据时它被破坏了。

我正在使用 MS dotnet 标准的示例。

此代码有效(文件初始化)

        byte[] toEncrypt = null;
        
        byte[] entropy = CreateRandomEntropy();

        FileStream fStream = new FileStream("Data.dat", FileMode.OpenOrCreate);
        var length = new System.IO.FileInfo("Data.dat").Length;
        if (length == 0)
        {
            XDocument doc =
              new XDocument(
                new XElement("data",
                  new XElement("global"),
                  new XElement("accounts")
                )
              );
            toEncrypt = UnicodeEncoding.ASCII.GetBytes(doc.ToString());

            EncryptDataToStream(toEncrypt, entropy, DataProtectionScope.CurrentUser, fStream);
        }
        fStream.Close();

然后我用一些数据更新了之前的示例:

fStream = new FileStream("Data.dat", FileMode.OpenOrCreate);

        byte[] decryptData = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, 2);

        string xml = UnicodeEncoding.ASCII.GetString(decryptData);

        XDocument xmlData = XDocument.Parse(xml);

        int maxId = 0;

        if (xmlData.Descendants("account").Any())
        {
            maxId = xmlData.Descendants("account")
               .Max(x => (int)x.Attribute("id"));
        }

        maxId++;

        var compteElement = new XElement("account",
            new XAttribute("id", maxId),
            new XElement("login", "monemail@home.fr"),
            new XElement("label", "compte TEST")
            );

        xmlData.Element("data").Element("accounts").Add(compteElement);

        MemoryStream ms = new MemoryStream();
        var settings = new XmlWriterSettings()
        {
            Indent = true
        };
        using (var writer = XmlWriter.Create(ms, settings))
        {
            xmlData.WriteTo(writer);
            writer.Flush();

            StreamReader sr = new StreamReader(ms);
            ms.Seek(0, SeekOrigin.Begin);
            String content = sr.ReadToEnd();

            byte[] BytedxmlData = UnicodeEncoding.ASCII.GetBytes(content);
            int bytesWritten = EncryptDataToStream(BytedxmlData, entropy, DataProtectionScope.CurrentUser, fStream);
        }

        fStream.Flush();

        fStream.Close();

然后我尝试读取数据:

fStream = new FileStream("Data.dat", FileMode.Open);

        byte[] decryptData2 = DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, 2);

        Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(decryptData2));

        fStream.Close();

Data.dat 每次更新时添加的字节都会增长。有些我认为它被正确填充但是当我阅读它时,我只得到第一条记录初始化文件和任何更新。

加解密方法如下:

public static int EncryptDataToStream(byte[] Buffer, byte[] Entropy, DataProtectionScope Scope, Stream S)
{
    if (Buffer == null)
        throw new ArgumentNullException("Buffer");
    if (Buffer.Length <= 0)
        throw new ArgumentException("Buffer");
    if (Entropy == null)
        throw new ArgumentNullException("Entropy");
    if (Entropy.Length <= 0)
        throw new ArgumentException("Entropy");
    if (S == null)
        throw new ArgumentNullException("S");

    int length = 0;

    byte[] encryptedData = ProtectedData.Protect(Buffer, Entropy, Scope);

    if (S.CanWrite && encryptedData != null)
    {
        S.Write(encryptedData, 0, encryptedData.Length);

        length = encryptedData.Length;
    }

    return length;
}

public static byte[] DecryptDataFromStream(byte[] Entropy, DataProtectionScope Scope, Stream S, int Length)
{
    if (S == null)
        throw new ArgumentNullException("S");
    if (Length <= 0)
        throw new ArgumentException("Length");
    if (Entropy == null)
        throw new ArgumentNullException("Entropy");
    if (Entropy.Length <= 0)
        throw new ArgumentException("Entropy");

    byte[] inBuffer = new byte[S.Length];
    byte[] outBuffer;

    if (S.CanRead)
    {
        S.Read(inBuffer, 0, inBuffer.Length);

        outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope);
    }
    else
    {
        throw new IOException("Could not read the stream.");
    }

    return outBuffer;
}

感谢@jdweng 我来自编码。 必须将 UnicodeEncoding.ASCII 更改为 Encoding.UTF-8