2010-09-13 3 views
1

J'ai écrit du code qui a crypté un fichier de configuration XML contenant les informations d'identification de l'utilisateur, ainsi que le code pour déchiffrer ce fichier. Lorsque je lance le chiffrement et le décryptage ensemble sur ma machine locale, cela fonctionne comme prévu. Cependant, lorsque je déploie le programme, avec uniquement le code décrypté, le fichier xml ne décrypte pas. Je reçois une exception cryptographique: Bad Data? Voici mon code:Problème avec le document XML de décryptage

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; 

    } 

Toute aide serait appréciée. Merci, Darren

Répondre

0

La question évidente est de savoir comment vous avez déplacé la clé privée XML_RSA_FTP_KEY sur le serveur.

Si vous n'avez rien fait, la méthode decrypt() aura généré une nouvelle paire de clés dans le conteneur XML_RSA_FTP_KEY. Cette clé échouera à déchiffrer les données qui ont été chiffrées avec une clé différente et donnera l'exception "Bad data".

+0

Merci pour la réponse. Je n'ai rien fait avec la clé privée autre que ce qui est dans mon code. C'est la première fois que j'ai utilisé le chiffrement/décryptage et je me bats avec cette dernière partie. Je vous serais reconnaissant si vous pouviez me diriger dans la bonne direction de ce qui doit faire? Fondamentalement, le fichier XMl et le code décrypté seront regroupés dans le cadre d'un système plus grand à 7 sites distants différents. Chaque site doit pouvoir déchiffrer le fichier en utilisant le code. Comment pourrais-je obtenir la clé privée pour eux? Merci encore. –

+0

Vous faites maintenant face au même problème que tous les autres éditeurs de logiciels dans le monde. C'est le dilemme où DRM est sorti: P Je suis vraiment intéressé de voir quelle réponse en ressort. – Adkins

+0

Une façon de le vérifier pour créer un harnais de test tel qu'un formulaire Windows avec une zone de texte et un bouton déchiffrer/chiffrer, cela vous permettra de tester à distance les chiffrements sur le serveur d'une manière facile à tester ... Pas grand chose aider mais pourrait vous diriger dans la bonne direction. – Xander

0

J'ai reçu la même erreur lors de l'utilisation de la classe EncryptedXml, X.509 certs, et j'ai oublié d'accorder l'accès à la clé privée d'un cert au processus/tâche propriétaire du processus de déchiffrement. Alors, n'oubliez pas d'accorder l'accès à la clé privée! Je sais que lorsque vous partagez des fichiers web.config sur tous les serveurs d'une batterie de serveurs Web cryptés avec une clé RSA-CSP personnalisée/partagée, vous devez également partager la clé dans un conteneur vers tous les serveurs. devra déchiffrer le texte chiffré dans votre web.config. Une fois que vous avez importé la clé du conteneur sur chaque serveur de la batterie, vous devez autoriser l'accès à l'identité du pool d'applications que vous exécutez comme dans IIS. Reportez-vous aux arguments -pc, -px, -pi et -pa de l'outil aspnet_regiis.exe pour savoir comment créer, exporter, importer et autoriser l'accès aux clés RSA, respectivement (http://msdn.microsoft.com/en-us/library/k6h9cz8h.ASPX). C'est une autre bonne ressource: http://msdn.microsoft.com/en-us/library/2w117ede.aspx. Pour rendre cela un peu plus déterministe en pratique, j'ai couru mon application dans IIS sous un compte de service de domaine, créé une clé RSA partagée personnalisée, importée sur ma ferme Web, accordé l'accès à la clé du compte de service de domaine, puis chiffré les parties sensibles du web.config avec la clé spécifique (voir les arguments -pef et -pdf sur aspnet_regiis.exe).

Si vous cryptez les paramètres d'application, vous pouvez envisager de créer une section app.config/web.config personnalisée (si vous ne souhaitez pas chiffrer tous les "appSettings"). Ensuite, cryptez-le avec la touche Droite en utilisant aspnet_regiis.exe. Enfin, distribuez le fichier web.config protégé dans votre processus de déploiement (vous formerez probablement le fichier web.config chiffré avec votre application). Le configProtectionProvider intégré qui crypte/décrypte de manière transparente les sections app.config et web.config est très pratique.

Voici un exemple de ce qu'une telle section cryptée dans un fichier ressemblerait à ceci:

<?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> 

Comme vous pouvez le voir, la protection de la configuration hors-the-box utilise le même cadre pour XML EncryptedData , mais fait tout le travail de crypto pour vous. Cela fonctionne de la même manière pour les services Windows et les applications de bureau, à condition que vous accordiez l'accès aux clés privées correctement.

1

j'ai changé votre fonction Crypter passe pas dans le RSA Alg, mais plutôt créer le RSACryptoServiceProvider rsaAlg, en utilisant la chaîne Keyname param, cela devrait être la même chaîne utilisée dans le Décrypter pour le KeyContainerName, « XML_RSA_FTP_KEY »

La raison pour laquelle les fonctions Decryption lancent une exception "Bad Data" lors d'une tentative de décryptage sur un autre PC est que CspParameters est lié à la session sur le PC sur lequel le chiffrement a été exécuté.

L'objet cspParams devra être intégré et crypté dans le code XML pour permettre le déchiffrement sur un autre ordinateur. Heureusement, nous pouvons utiliser EncryptionProperty pour cela.

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; 

    } 

Jetez un oeil here pour la classe RijndaelManagedEncryption.