1

我已将MSDN中的 XML加密解密合并到下面的同一个项目中,但出现错误

“无法检索解密密钥”。 替代文字

最奇怪的是我能够在异常前后写私钥,所以我不确定问题可能是什么。合并后的代码如下。

   public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
   {
       // Check the arguments.
       if (Doc == null)
           throw new ArgumentNullException("Doc");
       if (ElementToEncrypt == null)
           throw new ArgumentNullException("ElementToEncrypt");
       if (EncryptionElementID == null)
           throw new ArgumentNullException("EncryptionElementID");
       if (Alg == null)
           throw new ArgumentNullException("Alg");
       if (KeyName == null)
           throw new ArgumentNullException("KeyName");

       ////////////////////////////////////////////////
       // Find the specified element in the XmlDocument
       // object and create a new XmlElemnt object.
       ////////////////////////////////////////////////
       XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;

       // Throw an XmlException if the element was not found.
       if (elementToEncrypt == null)
       {
           throw new XmlException("The specified element was not found");

       }
       RijndaelManaged sessionKey = null;

       try
       {
           //////////////////////////////////////////////////
           // Create a new instance of the EncryptedXml class
           // and use it to encrypt the XmlElement with the
           // a new random symmetric key.
           //////////////////////////////////////////////////

           // Create a 256 bit Rijndael key.
           sessionKey = new RijndaelManaged();
           sessionKey.KeySize = 256;

           EncryptedXml eXml = new EncryptedXml();

           byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
           ////////////////////////////////////////////////
           // Construct an EncryptedData object and populate
           // it with the desired encryption information.
           ////////////////////////////////////////////////

           EncryptedData edElement = new EncryptedData();
           edElement.Type = EncryptedXml.XmlEncElementUrl;
           edElement.Id = EncryptionElementID;
           // Create an EncryptionMethod element so that the
           // receiver knows which algorithm to use for decryption.

           edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
           // Encrypt the session key and add it to an EncryptedKey element.
           EncryptedKey ek = new EncryptedKey();

           byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);

           ek.CipherData = new CipherData(encryptedKey);

           ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);

           // Create a new DataReference element
           // for the KeyInfo element.  This optional
           // element specifies which EncryptedData
           // uses this key.  An XML document can have
           // multiple EncryptedData elements that use
           // different keys.
           DataReference dRef = new DataReference();

           // Specify the EncryptedData URI.
           dRef.Uri = "#" + EncryptionElementID;

           // Add the DataReference to the EncryptedKey.
           ek.AddReference(dRef);
           // Add the encrypted key to the
           // EncryptedData object.

           edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
           // Set the KeyInfo element to specify the
           // name of the RSA key.

           // Create a new KeyInfo element.
           edElement.KeyInfo = new KeyInfo();

           // Create a new KeyInfoName element.
           KeyInfoName kin = new KeyInfoName();

           // Specify a name for the key.
           kin.Value = KeyName;

           // Add the KeyInfoName element to the
           // EncryptedKey object.
           ek.KeyInfo.AddClause(kin);
           // 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 (Exception e)
       {
           // re-throw the exception.
           throw e;
       }
       finally
       {
           if (sessionKey != null)
           {
               sessionKey.Clear();
           }

       }

   }
   public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
   {
       // Check the arguments.
       if (Doc == null)
           throw new ArgumentNullException("Doc");
       if (Alg == null)
           throw new ArgumentNullException("Alg");
       if (KeyName == null)
           throw new ArgumentNullException("KeyName");
       // Create a new EncryptedXml object.
       EncryptedXml exml = new EncryptedXml(Doc);

       // Add a key-name mapping.
       // This method can only decrypt documents
       // that present the specified key name.
       exml.AddKeyNameMapping(KeyName, Alg);

       // Decrypt the element throws Exception:  <--------------
       //
       // Unable to retrieve the decryption key".
       //
        exml.DecryptDocument();

   }
    static void Main(string[] args)
    {

        string containerName = "XML_ENC_RSA_KEY";

   ////////////////////////////////////////////////////////
    // Create and persist a key pair
   //  Save the Public portion of the keypair in a string we will use later

        // Create a new CspParameters object to specify
        // a key container.
        CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = containerName;

        // Create a new RSA key and save it in the container.  This key will encrypt
        // a symmetric key, which will then be encryped in the XML document.
        RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
        rsaKey.PersistKeyInCsp = true;
        Console.WriteLine(rsaKey.ToXmlString(false));
        string PublicKeyTest = rsaKey.ToXmlString(false);




  ////////////////////////////////////////////////////////
    // Encrypt using a new instance of the crypto provider and the public key string



 Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine();
       var rsaKey2 = new RSACryptoServiceProvider();
       rsaKey2.FromXmlString(PublicKeyTest);
       Console.WriteLine(rsaKey2.ToXmlString(false));
       PublicKeyTest = rsaKey2.ToXmlString(false);


        // Create an XmlDocument object.
        XmlDocument xmlDoc = new XmlDocument();

        // Load an XML file into the XmlDocument object.
        try
        {
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load("test.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        try
        {
            // Encrypt the "creditcard" element.
            Encrypt(xmlDoc, "creditcard", "EncryptedElement1", rsaKey2, "rsaKey");


            // Save the XML document.
            xmlDoc.Save("testOUT.xml");

            // Display the encrypted XML to the console.
            Console.WriteLine("Encrypted XML:");
            Console.WriteLine();
            Console.WriteLine(xmlDoc.OuterXml);

        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            // Clear the RSA key.
            rsaKey2.Clear(); 
        }


        Console.ReadLine();


 ////////////////////////////////////////////////////////
// Decrypt the output, using the internal CSP

          xmlDoc = new XmlDocument();

        // Load an XML file into the XmlDocument object.
        try
        {
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load("testOUT.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
         cspParams = new CspParameters();
        cspParams.KeyContainerName = containerName;

        // Get the RSA key from the key container.  This key will decrypt
        // a symmetric key that was imbedded in the XML document.
        var rsaKey3 = new RSACryptoServiceProvider(cspParams);
          Console.WriteLine(rsaKey3.ToXmlString(true));
        try
        {

            // Decrypt the elements, throws exception
            Decrypt(xmlDoc, rsaKey3, "rsaKey");

            // Save the XML document.
            xmlDoc.Save("test3.xml");

            // Display the encrypted XML to the console.
            Console.WriteLine();
            Console.WriteLine("Decrypted XML:");
            Console.WriteLine();
            Console.WriteLine(xmlDoc.OuterXml);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {

        }


        Console.ReadLine();

完全例外 (e)

System.Security.Cryptography.CryptographicException:无法检索解密密钥。在 System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument() 在 RemoteKey.Decrypt(XmlDocument Doc, RSA Alg, String KeyName) 在 C:\Users\me\ClientAgent\Program.cs:第 185 行在 RemoteKey.Main(String [] args) 在 C:\Users\Me\ClientAgent\Program.cs:line 286

4

1 回答 1

2

您的 Encrypt 函数正在编写不包含 KeyName 元素的 XML,因此您对 DecryptDocument 的调用无法找到密钥。

我没有进一步研究您的 Encrypt 编写不完整 XML 的原因,但您可以在 MSDN 上找到另一个示例 Encrypt 函数:AddKeyNameMapping Method

仅将您的 Encrypt 函数替换为该 MSDN 示例中的函数,仅将 Alg 的函数参数类型从 SymmetricAlgorithm 更改为 RSA,并从现有代码中对 Encrypt 的调用中删除第三个参数“EncryptedElement1”,以使其编译,它应该运行到您的解密和工作结束。

一旦你运行了那个,你可以向后看你的加密与这个例子中的那个不同,或者,如果它适合你,就保留这个。

于 2011-01-20T05:42:04.983 回答