C# Encrypt an XML File

前端 未结 4 1727
暗喜
暗喜 2020-12-13 23:30

I need two methods one to encrypt and one to decrypt an xml file with a key= \"hello world\",the key hello world should be used to encrypt and decrypt the xml file.These met

相关标签:
4条回答
  • 2020-12-13 23:32

    Would be cooler if you used a private key to sign the <lic> element and added the result to the file (in a <hash> element perhaps). This would make it possibly for everyone to read the xml file in case your support needs to know the license number, or the date of expiry, but they can not change any values without the private key.

    The public key needed to verify the signature would be common knowledge.

    Clarification
    Signing your code will only protect it against changes, it will not keep any information in it hidden. Your original question mentions encryption, but I am not sure that it is a requirement to hide the data, or just protect it from modification.

    Example code: (Never publish PrivateKey.key. ServerMethods are only needed when signing the xml file, ClientMethods are only needed when verifying the xml file.)

    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()); }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 23:41

    this is how you digitally sign and verify XML documents Sign XML Documents

    0 讨论(0)
  • 2020-12-13 23:53

    If you want the same key for encrypting and decrypting you should use a symmetric method (that's the definition, really). Here's the closest one to your sample (same source). http://msdn.microsoft.com/en-us/library/sb7w85t6.aspx

    The posted sample isn't working because they aren't using the same keys. Not only on different machines: running the program on the same machine twice should not work either (didn't work for me), because they use different random keys every time.
    try adding this code after creating your key:

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

    Now the program is using the same key and initial vector, and Encrypt and Decrypt should work on all machines.
    Also, consider renaming key to algorithm, otherwise this is very misleading. I'd say it's a bad, not-working-well example from MSDN.

    NOTE: PasswordDeriveBytes.GetBytes() has been deprecated because of serious (security) issues within the PasswordDeriveBytes class. The code above has been rewritten to use the safer Rfc2898DeriveBytes class instead (PBKDF2 instead of PBKDF1). Code generated with the above using PasswordDeriveBytes may be compromised.

    See also: Recommended # of iterations when using PKBDF2-SHA256?

    0 讨论(0)
  • 2020-12-13 23:56

    First of all, if you want to use the same key for encrypting and decrypting, you should look at symmetric cryptography. Asymmetric cryptography is when the keys for encrypting and decrypting are different. Just so that you know - RSA is asymmetric, TripleDES and Rijndael are symmetric. There are others too, but .NET does not have default implementations for them.

    I'd advise studying the System.Security.Cryptography namespace. And learning a bit about all that stuff. It has all you need to encrypt and decrypt files, as well as generate a password. In particular, you might be interested in these classes:

    • CryptoStream
    • PasswordDeriveBytes
    • RijndaelManaged

    There are also examples for usage in MSDN for each of them. You can use these classes to encrypt any file, not just XML. If however you want to encrypt just a select few elements, you can take a look at System.Security.Cryptography.Xml namespace. I see you've already found one article about it. Keep following the links on that page and you will learn more about those classes.

    0 讨论(0)
提交回复
热议问题