C#加密XML文件

时间:2009-07-06 08:46:10

标签: c# encryption

我需要两个方法来加密,一个用密钥=“hello world”来解密xml文件,密钥hello world应该用于加密和解密xml文件。这些方法应该适用于所有机器! !任何加密方法都可以。 XML文件内容如下:

<root>
    <lic>
        <number>19834209</number>
        <expiry>02/02/2002</expiry>
    </lic>
</root>

有些人可以给我一个示例吗?问题是msdn示例encyptions使得xml文件被加密但是当我在另一台机器上解密时它不起作用。例如

我试过这个样本: How to: Encrypt XML Elements with Asymmetric Keys, 但这里有一些有点会话,在另一台机器上,它说坏数据phewf!

4 个答案:

答案 0 :(得分:13)

如果你想要相同的密钥进行加密和解密,你应该使用对称方法(这就是定义,真的)。这是与您的样本最接近的一个(相同的来源)。 http://msdn.microsoft.com/en-us/library/sb7w85t6.aspx

发布的示例无效,因为他们没有使用相同的密钥。不仅在不同的机器上:在同一台机器上运行两次程序也不应该工作(对我来说不起作用),因为它们每次都使用不同的随机键。
尝试在创建密钥后添加此代码:

key = new RijndaelManaged();

string password = "Password1234"; //password here
byte[] saltBytes = Encoding.UTF8.GetBytes("Salt"); // salt here (another string)
var p = new Rfc2898DeriveBytes(password, saltBytes); //TODO: think about number of iterations (third parameter)
// sizes are devided by 8 because [ 1 byte = 8 bits ]
key.IV = p.GetBytes(key.BlockSize / 8);
key.Key = p.GetBytes(key.KeySize / 8);

现在程序使用相同的密钥和初始向量,加密和解密应该适用于所有计算机 另外,请考虑将key重命名为algorithm,否则这会产生误导。我说这是来自MSDN的一个糟糕的,不好用的例子。

<子> 注意PasswordDeriveBytes.GetBytes()由于PasswordDeriveBytes类中的严重(安全)问题而被弃用。上面的代码已被重写为使用更安全的Rfc2898DeriveBytes类(PBKDF2而不是PBKDF1)。上述使用PasswordDeriveBytes生成的代码可能会受到影响

另请参阅:Recommended # of iterations when using PKBDF2-SHA256?

答案 1 :(得分:4)

如果您使用私钥对&lt; lic&gt;进行签名,会更酷吗? element并将结果添加到文件中(可能在&lt; hash&gt;元素中)。如果您的支持需要知道许可证编号或到期日期,这将使每个人都可以阅读xml文件,但如果没有私钥,他们就无法更改任何值。

验证签名所需的公钥是常识。

<强>澄清
对代码进行签名只会保护代码免受更改,并且不会隐藏其中的任何信息。您的原始问题提到加密,但我不确定是否需要隐藏数据,或者只是保护数据不被修改。

示例代码:(从不发布PrivateKey.key。只有在签署xml文件时才需要ServerMethods,只有在验证xml文件时才需要ClientMethods。)

using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml;

public static class Program {
    public static void Main() {
        if (!File.Exists("PublicKey.key")) {
            // Assume first run, generate keys and sign document.
            ServerMethods.GenerateKeyPair();

            var input = new XmlDocument();
            input.Load("input.xml");
            Debug.Assert(input.DocumentElement != null);

            var licNode = input.DocumentElement["lic"];
            Debug.Assert(licNode != null);

            var licNodeXml = licNode.OuterXml;
            var signedNode = input.CreateElement("signature");
            signedNode.InnerText = ServerMethods.CalculateSignature(licNodeXml);
            input.DocumentElement.AppendChild(signedNode);

            input.Save("output.xml");
        }

        if (ClientMethods.IsValidLicense("output.xml")) {
            Console.WriteLine("VALID");
        } else {
            Console.WriteLine("INVALID");
        }
    }

    public static class ServerMethods {
        public static void GenerateKeyPair() {
            var rsa = SharedInformation.CryptoProvider;

            using (var keyWriter = File.CreateText("PublicKey.key"))
                keyWriter.Write(rsa.ToXmlString(false));

            using (var keyWriter = File.CreateText("PrivateKey.key"))
                keyWriter.Write(rsa.ToXmlString(true));
        }

        public static string CalculateSignature(string data) {
            var rsa = SharedInformation.CryptoProvider;
            rsa.FromXmlString(File.ReadAllText("PrivateKey.key"));

            var dataBytes = Encoding.UTF8.GetBytes(data);
            var signatureBytes = rsa.SignData(dataBytes, SharedInformation.HashAlgorithm);
            return Convert.ToBase64String(signatureBytes);
        }
    }

    public static class ClientMethods {
        public static bool IsValid(string data, string signature) {
            var rsa = SharedInformation.CryptoProvider;
            rsa.FromXmlString(File.ReadAllText("PublicKey.key"));

            var dataBytes = Encoding.UTF8.GetBytes(data);
            var signatureBytes = Convert.FromBase64String(signature);
            return rsa.VerifyData(dataBytes, SharedInformation.HashAlgorithm, signatureBytes);
        }

        public static bool IsValidLicense(string filename) {
            var doc = new XmlDocument();
            doc.Load(filename);

            var licNode = doc.SelectSingleNode("/root/lic") as XmlElement;
            var signatureNode = doc.SelectSingleNode("/root/signature") as XmlElement;
            if (licNode == null || signatureNode == null) return false;

            return IsValid(licNode.OuterXml, signatureNode.InnerText);
        }
    }

    public static class SharedInformation {
        public static int KeySize {
            get { return 1024; }
        }

        public static string HashAlgorithm {
            get { return "SHA512"; }
        }

        public static RSACryptoServiceProvider CryptoProvider {
            get { return new RSACryptoServiceProvider(KeySize, new CspParameters()); }
        }
    }
}

答案 2 :(得分:3)

首先,如果要使用相同的密钥进行加密和解密,则应查看对称加密。非对称加密是指用于加密和解密的密钥不同的时候。只是让你知道 - RSA是不对称的,TripleDES和Rijndael是对称的。还有其他一些,但.NET没有默认的实现。

我建议研究System.Security.Cryptography namespace。并学习一点所有的东西。它拥有加密和解密文件以及生成密码所需的一切。特别是,您可能对这些类感兴趣:

  • CryptoStream
  • PasswordDeriveBytes
  • RijndaelManaged

在MSDN中也有使用它们的示例。您可以使用这些类来加密任何文件,而不仅仅是XML。但是,如果您只想加密少数几个元素,可以查看System.Security.Cryptography.Xml命名空间。我看到你已经找到了一篇关于它的文章。请继续关注该页面上的链接,您将了解有关这些课程的更多信息。

答案 3 :(得分:2)

这是您对XML文档进行数字签名和验证的方式Sign XML Documents