2010-09-13 63 views
1

我已经编写了一些加密了包含用户凭证的XML配置文件的代码,以及解密该文件的代码。当我在本地计算机上一起运行加密和解密时,它会按预期工作。但是,当我部署该程序时,只有解密代码,xml文件不会解密。我得到一个加密异常:坏数据? 这里是我的代码:解密xml文档的问题

public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string Keyname) 
    { 
     if (Doc == null) 
      throw new ArgumentNullException("Doc"); 
     if (ElementToEncrypt == null) 
      throw new ArgumentNullException("Element to Encrypt"); 
     if (EncryptionElementID == null) 
      throw new ArgumentNullException("EncryptionElementID"); 
     if (Alg == null) 
      throw new ArgumentNullException("ALG"); 
     //specify which xml elements to encrypt 
     XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement; 

     if (elementToEncrypt == null) 
      throw new XmlException("The specified element was not found"); 
     try 
     { 
      //create session key 
      RijndaelManaged sessionkey = new RijndaelManaged(); 
      sessionkey.KeySize = 256; 

      //encrypt using Encrypted exml object and hold in byte array 
      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; 

      edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url); 
      //encrypt the session key and add it encrypted key 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 data reference to encrypted key 

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

      edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek)); 

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



     // 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) 
     { 
      throw e; 
     } 
    } 


    public static string Decrypt() 
    { 
      //create XML documentobject and load config file 
      XmlDocument xmlDoc = new XmlDocument(); 

      try 
      { 
       xmlDoc.Load("config.xml"); 
      } 
      catch (FileNotFoundException e) 
      { 
       Console.WriteLine(e.Message); 
       Console.ReadLine(); 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
       Console.ReadLine(); 
      } 

      //create container for key 
      CspParameters cspParam = new CspParameters(); 
      cspParam.KeyContainerName = "XML_RSA_FTP_KEY"; 
      cspParam.Flags = CspProviderFlags.UseMachineKeyStore; 
      //create key and store in container 
      RSACryptoServiceProvider ftpkey = new RSACryptoServiceProvider(cspParam); 


      //add keyname mapping qnd decrypt the document 
      EncryptedXml exml = new EncryptedXml(xmlDoc); 
      exml.AddKeyNameMapping("ftpkey", ftpkey); 
      exml.DecryptDocument(); 

      //pass decrypted document to extract credentials method 
      string details = Extract_Credentials(xmlDoc); 

      //return decrypted log in details 
      return details; 

    } 

任何帮助,将不胜感激。谢谢,Darren

回答

0

显而易见的问题是如何将XML_RSA_FTP_KEY私钥移动到服务器。

如果您没有做任何事情,decrypt() -method将在XML_RSA_FTP_KEY容器中生成一个新的密钥对。该密钥将无法解密用不同密钥加密的数据,并给出“错误数据”。

+0

感谢您的回复。除了我的代码之外,我还没有对私钥进行任何操作。这是我第一次使用加密/解密,并且我正在为这个最后的部分而努力。如果您能指出我需要做的正确方向,我将不胜感激。基本上,XMl文件和解密代码将作为更大系统的一部分捆绑到7个不同的远程站点。每个站点都可以使用代码解密文件。我将如何获得私钥给他们?再次感谢。 – 2010-09-13 13:58:53

+0

您现在面临着与世界上其他所有软件公司相同的问题。这是DRM出现的困境:P我真的很想看看这个答案是什么。 – Adkins 2010-09-13 14:10:23

+0

双重检查它的一种方法是创建一个测试工具,例如带有文本框和解密/加密按钮的Windows窗体,这将允许您以易于测试的方式远程测试服务器上的加密......并不多帮助,但可以指出你在正确的方向。 – Xander 2010-09-13 16:05:10

0

我在使用EncryptedXml类X.509证书时收到了同样的错误,并且我忘记将对证书私钥的访问权限授予解密进程的进程/任务所有者。所以,不要忘记授予访问私钥的权限!

我知道,当您共享web-farm中所有使用自定义/共享RSA-CSP密钥加密的服务器上的web.config文件时,还需要将容器中的密钥共享给所有服务器将需要解密你的web.config中的密文。一旦从服务器场中每个服务器上的容器导入密钥,就需要授予对asp.net应用程序运行的应用程序池身份的访问权限,如同在IIS中一样。有关如何分别创建,导出,导入和授权访问RSA密钥的信息,请参阅aspnet_regiis.exe工具的-pc,-px,-pi和-pa参数(http://msdn.microsoft.com/en-us/library/k6h9cz8h.ASPX)。这是另一个很好的资源:http://msdn.microsoft.com/en-us/library/2w117ede.aspx

为了在实践中确定这一点,我在IIS服务帐户下运行了我的应用程序,创建了一个定制的共享RSA密钥,通过我的Web场导入,授予对域服务帐户密钥的访问权限,然后使用特定密钥加密web.config的敏感部分(请参阅aspnet_regiis.exe上的-pef和-pdf参数)。

如果您正在加密应用程序设置,您可能需要考虑创建自定义的app.config/web.config部分(如果您不想加密所有“appSettings”)。然后,使用aspnet_regiis.exe使用右键进行加密。最后,在您的部署过程中分发受保护的web.config(您可能会将加密的web.config与您的应用程序一起打包)。内置的configProtectionProvider透明地加密/解密app.config和web.config部分非常方便。

这里是一个什么样的文件这样加密的部分看起来像一个例子:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 

<configSections> 
    <section name="secureAppSettings" type="System.Configuration.NameValueSectionHandler"/> 
</configSections> 

    <configProtectedData> 
    <providers> 
     <add name="MyKeyProvider" 
      type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" 
      keyContainerName="MyKey" 
      useMachineContainer="true" /> 
    </providers> 
    </configProtectedData> 

    <secureAppSettings configProtectionProvider="MyKeyProvider"> 
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" 
     xmlns="http://www.w3.org/2001/04/xmlenc#"> 
     <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> 
     <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
     <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> 
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> 
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
      <KeyName>Rsa Key</KeyName> 
      </KeyInfo> 
      <CipherData> 
      <CipherValue>deadbeef</CipherValue> 
      </CipherData> 
     </EncryptedKey> 
     </KeyInfo> 
     <CipherData> 
     <CipherValue>cafef00d</CipherValue> 
     </CipherData> 
    </EncryptedData> 
    </secureAppSettings> 

</configuration> 

正如你所看到的,出的现成的配置保护使用XML的EncryptedData相同的框架,但只是为你做所有的加密工作。如果您正确授予对私钥的访问权限,则对于Windows服务和桌面应用程序来说,这是一样的。

1

我改变了你的加密功能,不是在RSA ALG传球,而是创造的RSACryptoServiceProvider rsaAlg,使用字符串键名PARAM,这应该是在解密的KeyContainerName使用相同的字符串,“XML_RSA_FTP_KEY”

当试图在另一台PC上解密时,解密函数抛出“坏数据”异常的原因是CspParameters链接到运行加密的PC上的会话。

cspParams对象需要在XML中嵌入和加密才能在另一台PC上启用解密。幸运的是我们可以使用EncryptionProperty。

public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, string Keyname) 
    { 
     if (Doc == null) 
      throw new ArgumentNullException("Doc"); 
     if (ElementToEncrypt == null) 
      throw new ArgumentNullException("Element to Encrypt"); 
     if (EncryptionElementID == null) 
      throw new ArgumentNullException("EncryptionElementID"); 

     // Create a CspParameters object and specify the name of the key container. 
     var cspParams = new CspParameters { KeyContainerName = Keyname }; //"XML_RSA_FTP_KEY" 

     // 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. 
     var rsaAlg = new RSACryptoServiceProvider(cspParams); 

     //specify which xml elements to encrypt 
     XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement; 

     if (elementToEncrypt == null) 
      throw new XmlException("The specified element was not found"); 
     try 
     { 
      //create session key 
      RijndaelManaged sessionkey = new RijndaelManaged(); 
      sessionkey.KeySize = 256; 

      //encrypt using Encrypted exml object and hold in byte array 
      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; 

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

      byte[] encryptedKey = EncryptedXml.EncryptKey(sessionkey.Key, rsaAlg, 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 data reference to encrypted key 

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

      edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek)); 

      // Save some more information about the key using the EncryptionProperty element. 

      // Create a new "EncryptionProperty" XmlElement object. 
      var property = new XmlDocument().CreateElement("EncryptionProperty", EncryptedXml.XmlEncNamespaceUrl); 

      // Set the value of the EncryptionProperty" XmlElement object. 
      property.InnerText = RijndaelManagedEncryption.EncryptRijndael(Convert.ToBase64String(rsaAlg.ExportCspBlob(true)), 
          "Your Salt string here"); 

      // Create the EncryptionProperty object using the XmlElement object. 
      var encProperty = new EncryptionProperty(property); 

      // Add the EncryptionProperty object to the EncryptedKey object. 
      ek.AddProperty(encProperty); 

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



      // 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) 
     { 
      throw; 
     } 
    } 

    public static string Decrypt() 
    { 
     //create XML documentobject and load config file 
     XmlDocument xmlDoc = new XmlDocument(); 

     try 
     { 
      xmlDoc.Load("config.xml"); 
     } 
     catch (FileNotFoundException e) 
     { 
      Console.WriteLine(e.Message); 
      Console.ReadLine(); 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      Console.ReadLine(); 
     } 

     //create container for key 
     CspParameters cspParam = new CspParameters(); 
     cspParam.KeyContainerName = "XML_RSA_FTP_KEY"; 
     cspParam.Flags = CspProviderFlags.UseMachineKeyStore; 
     //create key and store in container 
     RSACryptoServiceProvider ftpkey = new RSACryptoServiceProvider(cspParam); 

     var keyInfo = xmlDoc.GetElementsByTagName("EncryptionProperty")[0].InnerText; 
     ftpkey.ImportCspBlob(
      Convert.FromBase64String(RijndaelManagedEncryption.DecryptRijndael(keyInfo, 
       "Your Salt string here"))); 

     //add keyname mapping qnd decrypt the document 
     EncryptedXml exml = new EncryptedXml(xmlDoc); 
     exml.AddKeyNameMapping("ftpkey", ftpkey); 
     exml.DecryptDocument(); 

     //pass decrypted document to extract credentials method 
     string details = Extract_Credentials(xmlDoc); 

     //return decrypted log in details 
     return details; 

    } 

拥有的RijndaelManagedEncryption类一看here