【问题标题】:C# Encrypt an XML FileC# 加密 XML 文件
【发布时间】:2010-11-08 08:00:58
【问题描述】:

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

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

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

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

【问题讨论】:

  • 请发布您的代码的简短示例,以及究竟是什么不起作用(例如,'在第 12 行我得到一个编译器错误 12345',或'在运行时我在第 15 行得到一个 SecurityException') .
  • 加密类抛出的错误数据啊很好
  • 您需要加密数据以隐藏它,还是仅仅保护数据不被更改?
  • 我需要加密整个文件,这样人们就不会搞砸了。
  • 防止人们使用它符合“保护数据免受更改”的想法。无论如何,如果您选择加密整个文件,请确保您没有将用于加密数据的密钥嵌入到您的程序中,或者它是免费的(使用反射器)知识。

标签: c# encryption


【解决方案1】:

如果您希望使用相同的密钥进行加密和解密,您应该使用对称方法(这就是定义,真的)。这是与您的样本最接近的样本(相同来源)。 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?

【讨论】:

  • 我试过那个示例,如果我只注释掉解密,然后加密,然后注释掉加密,解密不起作用?为什么?
  • 就像我有时间了解所有这些复杂的加密内容。事实上,我试图通过阅读 MSDN 来理解,但如果他们不能正确解释,那么还有谁可以。你不需要了解整个加密文件的密码理论。嗯.net 有类,我只需要使用它们来节省我的时间!我他们给你一个例子,然后至少它应该在不同的机器上工作!
  • 如果您有兴趣,在空闲时间,MSDN 不是学习理论的好地方。我将从维基百科开始 - en.wikipedia.org/wiki/Symmetric-key_algorithm 。如果您非常感兴趣并且想要一些友好的英语内容,Simon Singh 的 The Code Book 可能是您的最佳选择。
  • @Ofir - 谢谢。我编辑了代码以便编译(它是由其他人编辑的,谁破坏了它,或者可能是 API 改变了)。我不知道Rfc2898DeriveBytes 的最佳参数是什么,但我添加了一个链接来回答这个问题(不幸的是,不是数字)。默认值为 1000。
  • @Kobi Microsoft API(任何 API)的问题在于它们没有被指定。最好使用 byte[] password, byte[] salt, int iterations 构造函数(编辑的答案中缺少迭代计数)。问题在于,使用 API 无法知道密码 salt 的字符编码。默认迭代计数也是如此。对于任何类型的互操作性(甚至可能在两个不同的 .NET 运行时之间),使用其他构造函数充其量都是危险的。
【解决方案2】:

首先,如果你想使用相同的密钥进行加密和解密,你应该看看对称加密。非对称加密是指加密和解密的密钥不同。只是让您知道 - RSA 是不对称的,TripleDES 和 Rijndael 是对称的。还有其他的,但 .NET 没有它们的默认实现。

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

  • CryptoStream
  • PasswordDeriveBytes
  • RijndaelManaged

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

【讨论】:

    【解决方案3】:

    如果您使用私钥对 元素进行签名并将结果添加到文件中(也许在 元素中)会更酷。这将使每个人都可以阅读 xml 文件,以防您的支持人员需要知道许可证号或到期日期,但他们无法在没有私钥的情况下更改任何值。

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

    澄清
    签署您的代码只会保护它免受更改,它不会隐藏其中的任何信息。您最初的问题提到了加密,但我不确定是否需要隐藏数据,或者只是保护它不被修改。

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

    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()); }
            }
        }
    }
    

    【讨论】:

    • 我尝试了来自 msdn 的两个示例,但是..问题是我可以让它在 diff 机器上正确解密。
    【解决方案4】:

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    相关资源
    最近更新 更多