如何在单个XML文档中加密XML元素的多个副本

时间:2010-01-28 05:01:23

标签: xml encryption

我有一个基于MSDN文章http://msdn.microsoft.com/en-us/library/sb7w85t6.aspx

的XML加密例程

我的代码在这里

public static void Encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
        {
            ////////////////////////////////////////////////
            // Check the arguments.  
            ////////////////////////////////////////////////
            if (Doc == null || (Doc.ToString() == string.Empty))
                throw new ArgumentNullException("The XML document was not given or it is empty");

            if (ElementName == null || ElementName == string.Empty)
                throw new ArgumentNullException("The XML element was not given or it is empty");

            if (Key == null || Key.ToString() == string.Empty)
                throw new ArgumentNullException("The encryption algorithm was not given or it is empty");

            try
            {
                ////////////////////////////////////////////////
                // Find the specified element in the XmlDocument
                // object and create a new XmlElemnt object.
                ////////////////////////////////////////////////
                foreach (XmlElement elementToEncrypt in Doc.GetElementsByTagName("schema"))
                {
                    //XmlElement elementToEncrypt = Doc.GetElementsByTagName("schema")[0] as XmlElement;
                    // Throw an XmlException if the element was not found.
                    if (elementToEncrypt == null || elementToEncrypt.ToString() == string.Empty)
                    {
                        throw new XmlException("The specified element was not found or it is empty");
                    }

                    //////////////////////////////////////////////////
                    // 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;
                    }
                    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
                    {
                        // 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);
                }
            }
            catch (XmlException xexc)
            {
                throw new Exception(xexc.Message);
            }
            catch (Exception exc)
            {
                throw new XmlException("The XML document could not be used to encrypt the elements given: " + exc.Message);
            }
            finally
            {
                ////////////////////////////////////////////////////
                // Replace the XML file with the encrypted version
                ////////////////////////////////////////////////////
                Doc.Save("testMIPS.config");
            }
        }

这适用于它找到的第一个“schema”元素,我可以看到显示已加密的第一个元素的Doc.XML字符串。

但是当循环遍历到所谓的加密下一个“schema”元素时,程序会抛出此异常...

“元素列表已更改。枚举操作无法继续。”

但我还没有真正保存过Doc.XML文件。

为什么会这样?

提前感谢您的时间。

2 个答案:

答案 0 :(得分:0)

Doc.GetElementsByTagName("schema") 

返回节点的迭代器,它也是一个惰性求值器。当更改XmlElement迭代变为无效bcz时,您已经更改了迭代器正在工作的数据。尝试在GetElementsByTagName()中添加List<XmlElement>中的结果元素,然后枚举该列表并加密每个元素。

添加了更多信息

如果你有列表

,这很简单
    List<int> n =new List<int>(new int{1,2,3}); 
   //now if iterate it 
    foreach(int i in n){ 
      n.Add(i)
    } 

循环正在更改其枚举的列表,因此它将给出类似于您的情况中给出的错误。您可以通过执行

来解决问题
    foreach(int i in n.ToArray()){
        n.Add(i)
     } 

因为在这种情况下,n的静止图像是在循环之前捕获的,我可以在循环内自由地改变它。当你枚举它时,你的循环在树上迭代。那不对,会给你例外。您必须首先收集要在List中更改的所有元素,然后枚举此列表并加密它们。这也将更新原始的xml文档。

答案 1 :(得分:0)

我遇到了同样的问题,并提出了以下代码。它对我有用。

的test.xml:

$mysql = mysqli_connect($host, $user, $password, $databaseName);

C#:

<root>
    <creditcard id="1">
        <number>19834209</number>
        <expiry>02/02/2002</expiry>
    </creditcard>
    <creditcard id="2">
        <number>34834210</number>
        <expiry>03/03/2003</expiry>
    </creditcard>
    <creditcard id="3">
        <number>34834211</number>
        <expiry>04/04/2003</expiry>
    </creditcard>
</root>