0

我正在尝试加密 XML 文档中的 XML 元素。

我遇到了这个 MSDN DOC,它展示了如何做到这一点的方法。

如果我在本文档中“按原样”使用代码,它就可以工作。但是,这个演示代码不适合我的场景,我需要保存加密的 XML 文件,然后在另一个时间加载它,然后解密它。所以,我已经修改了演示代码来做到这一点,但现在我得到了错误:

填充无效且无法移除。

我在 SO 上的其他帖子中看到,遇到类似错误的用户设置了该类的Padding属性。RijndaelManaged我尝试使用所有的PKCS7,ZerosNone,但我仍然得到错误。我应该提到,我Padding对加密和解密方法的密钥应用了相同的值。

我做错了什么,还是有其他方法?

以下是我修改后的代码(用于控制台应用程序)。请将文件路径分配给顶部的两个常量。

明文 XML 文件:

<?xml version="1.0" encoding="utf-8" ?><root><creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry></creditcard></root>

修改后的代码:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml; 
using System.Xml;
namespace TestXMLEncryption
{
    class Program
    {
        private const string STR_EncryptedXmlFile = "Path of Encrypted.xml";
        private const string STR_PlainTextXmlFile = "Path of PlainText.xml";
        static void Main(string[] args)
        {
            PlainTextXmlToEncryptedXml();
            EncryptedXmlToPlainTextXml();
        }

        private static void EncryptedXmlToPlainTextXml()
        {
            using (var key = new RijndaelManaged())
            {
                try
                {
                    key.Padding = PaddingMode.PKCS7;
                    // Load an XML document.
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.PreserveWhitespace = true;
                    xmlDoc.Load(STR_EncryptedXmlFile);
                    Decrypt(xmlDoc, key);
                    Console.WriteLine("The element was decrypted");
                    Console.WriteLine(xmlDoc.InnerXml);
                    Console.ReadLine();
                }
                catch (Exception e)
                {
                    Console.WriteLine($"ERROR: {e.Message}");
                    Console.ReadLine();
                }
                finally
                {
                    // Clear the key.
                    if (key != null)
                    {
                        key.Clear();
                    }
                }
            }
        }

        private static void PlainTextXmlToEncryptedXml()
        {
            using (var key = new RijndaelManaged())
            {
                try
                {
                    key.Padding = PaddingMode.PKCS7;
                    // Load an XML document.
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.PreserveWhitespace = true;
                    xmlDoc.Load(STR_PlainTextXmlFile);
                    // Encrypt the "creditcard" element.
                    Encrypt(xmlDoc, "creditcard", key);
                    Console.WriteLine("The element was encrypted");
                    xmlDoc.Save(STR_EncryptedXmlFile);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    // Clear the key.
                    if (key != null)
                    {
                        key.Clear();
                    }
                }
            }
        }

        public static void Decrypt(XmlDocument Doc, SymmetricAlgorithm Alg)
        {
            // Find the EncryptedData element in the XmlDocument.
            XmlElement encryptedElement = Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
            // If the EncryptedData element was not found, throw an exception.
            if (encryptedElement == null)
            {
                throw new XmlException("The EncryptedData element was not found.");
            }
            // Create an EncryptedData object and populate it.
            EncryptedData edElement = new EncryptedData();
            edElement.LoadXml(encryptedElement);
            // Create a new EncryptedXml object.
            EncryptedXml exml = new EncryptedXml();
            // Decrypt the element using the symmetric key.
            byte[] rgbOutput = exml.DecryptData(edElement, Alg);
            // Replace the encryptedData element with the plaintext XML element.
            exml.ReplaceData(encryptedElement, rgbOutput);
        }

        public static void Encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
        {
            ////////////////////////////////////////////////
            // Find the specified element in the XmlDocument
            // object and create a new XmlElemnt object.
            ////////////////////////////////////////////////
            XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementName)[0] as XmlElement;
            // Throw an XmlException if the element was not found.
            if (elementToEncrypt == null)
            {
                throw new XmlException("The specified element was not found");
            }
            //////////////////////////////////////////////////
                // Create a new instance of the EncryptedXml class 
                // and use it to encrypt the XmlElement with the 
                // symmetric key.
                //////////////////////////////////////////////////
                EncryptedXml eXml = new EncryptedXml();
            byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Key, false);
            ////////////////////////////////////////////////
            // Construct an EncryptedData object and populate
            // it with the desired encryption information.
            ////////////////////////////////////////////////
            EncryptedData edElement = new EncryptedData();
            edElement.Type = EncryptedXml.XmlEncElementUrl;
            // Create an EncryptionMethod element so that the 
            // receiver knows which algorithm to use for decryption.
            // Determine what kind of algorithm is being used and
            // supply the appropriate URL to the EncryptionMethod element.
            string encryptionMethod = null;
            if (Key is TripleDES)
            {
                encryptionMethod = EncryptedXml.XmlEncTripleDESUrl;
            }
            else if (Key is DES)
            {
                encryptionMethod = EncryptedXml.XmlEncDESUrl;
            }
            else if (Key is Rijndael)
            {
                switch (Key.KeySize)
                {
                    case 128:
                        encryptionMethod = EncryptedXml.XmlEncAES128Url;
                        break;
                    case 192:
                        encryptionMethod = EncryptedXml.XmlEncAES192Url;
                        break;
                    case 256:
                        encryptionMethod = EncryptedXml.XmlEncAES256Url;
                        break;
                }
            }
            else if (Key is Aes)
            {
                switch (Key.KeySize)
                {
                    case 128:
                        encryptionMethod = EncryptedXml.XmlEncAES128Url;
                        break;
                    case 192:
                        encryptionMethod = EncryptedXml.XmlEncAES192Url;
                        break;
                    case 256:
                        encryptionMethod = EncryptedXml.XmlEncAES256Url;
                        break;
                }
            }
            else
            {
                // Throw an exception if the transform is not in the previous categories
                throw new CryptographicException("The specified algorithm is not supported for XML Encryption.");
            }
            edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);
            // Add the encrypted element data to the 
            // EncryptedData object.
            edElement.CipherData.CipherValue = encryptedElement;
            ////////////////////////////////////////////////////
            // Replace the element from the original XmlDocument
            // object with the EncryptedData element.
            ////////////////////////////////////////////////////
            EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
        }
    }
}
4

1 回答 1

0

您在 Encrypt 和 Decrypt 例程中都创建了一个新密钥,因为您创建了 RijndaelManaged 对象并且没有设置(或读取) Key 属性。

示例代码不需要这样做,因为它使用相同的对象进行加密和解密,因此两次操作具有相同的随机密钥。

于 2019-10-04T11:28:39.733 回答