2010-09-13 45 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