Проблема с расшифровкой XML-документа - PullRequest
1 голос
/ 13 сентября 2010

Я написал некоторый код, который зашифровал 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;

    }

Любая помощь будет оценена. Спасибо, Даррен

Ответы [ 3 ]

1 голос
/ 21 октября 2014

Я изменил вашу функцию Encrypt, чтобы не передавать RSA Alg, а вместо этого создать RSACryptoServiceProvider rsaAlg, используя строку Keyname param, это должна быть та же строка, что и в Decrypt для KeyContainerName, "XML_RSA_FTP_KEY"

Причиной того, что функции расшифровки выдают исключение «неверные данные» при попытке расшифровки на другом ПК, является то, что CspParameters связан с сеансом на ПК, на котором было запущено шифрование.

Объект cspParams должен быть встроен и зашифрован в XML, чтобы включить дешифрование на другом ПК. К счастью, для этого мы можем использовать 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.

0 голосов
/ 13 декабря 2013

Я получил ту же ошибку при использовании класса EncryptedXml, сертификатов X.509, и я забыл предоставить доступ к закрытому ключу сертификата владельцу процесса / задачи процесса дешифрования.Поэтому не забудьте предоставить доступ к закрытому ключу!

Я знаю, что когда вы делитесь файлами web.config на всех серверах веб-фермы, которые зашифрованы с помощью специального / общего ключа RSA-CSPВы также должны предоставить ключ в контейнере всем серверам, которые должны будут расшифровать зашифрованный текст в вашем файле web.config.После того как вы импортируете ключ из контейнера на каждом сервере в ферме, вам нужно предоставить доступ к идентификатору пула приложений, который запускается вашим приложением asp.net, как в IIS.Посмотрите аргументы -pc, -px, -pi и -pa для инструмента aspnet_regiis.exe, чтобы узнать, как создать, экспортировать, импортировать и разрешить доступ к ключам RSA соответственно (http://msdn.microsoft.com/en-us/library/k6h9cz8h.ASPX). Это еще один хороший ресурс: http://msdn.microsoft.com/en-us/library/2w117ede.aspx.

Чтобы сделать это на практике более детерминированным, я запустил свое приложение в IIS под учетной записью службы домена, создал настраиваемый общий ключ RSA, импортированный через мою веб-ферму, и предоставил доступ к ключу.в учетную запись службы домена, а затем зашифровали важные части файла web.config с помощью специального ключа (см. аргументы -pef и -pdf для aspnet_regiis.exe).

Если вы шифруете настройки приложения, вы можетехотите создать собственный раздел app.config / web.config (если вы не заинтересованы в шифровании всех «appSettings»). Затем зашифруйте его с помощью ключа Right с помощью aspnet_regiis.exe. Наконец, распространите защищенную сеть.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 и настольных приложений, если вы правильно предоставляете доступ к закрытым ключам.

0 голосов
/ 13 сентября 2010

Очевидный вопрос в том, как вы переместили закрытый ключ XML_RSA_FTP_KEY на сервер.

Если вы ничего не сделали, метод decrypt() сгенерирует новую пару ключей в контейнере XML_RSA_FTP_KEY.Этот ключ не сможет расшифровать данные, которые были зашифрованы другим ключом, и дать исключение «неверные данные».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...