轉 未能使用提供者 “RsaProtectedConfigurationProvider” 進行解密 的解決辦法

來源:互聯網
上載者:User

未能使用提供者 "RsaProtectedConfigurationProvider" 進行解密 的解決辦法 如何使用 Enterprise Library 3.0 的Cryptography Application Block 處理加密
本文不示範如何使用組態工具對配置區進行加密,也不示範如何匯出匯入 key 檔案,而主要解決兩個問題:
         1.我們使用組態工具對配置區進行加密後,(通常 configProtectionProvider有兩種選擇,一個是RsaProtectedConfigurationProvider,一個是DataProtectionConfigurationProvider),在本機使用正常,但是如果換到其它機器上,再用組態工具,就無法開啟。使用RsaProtectedConfigurationProvider的,報的錯誤如下:未能使用提供者"RsaProtectedConfigurationProvider" 進行解秘密。

         2.我們使用Cryptography Application Block 的加密處理塊後,建立了一個Symmetric Providers,並使用了 DESCryptoServiceProvider   提供的演算法,這個過程中產生了一個key 檔案。但是這個 key 檔案複製的其他機器是無效的(後面解釋原因)。當然,我們可以通過現在本機匯出的key的方式,然後在其他機器上匯入 key 檔案。但是這樣只解決了開發人員之間要使用相同的key檔案的問題。對於部署到用戶端,則不行。因為我們不大可能去用戶端上安裝 Enterprise Library 3.0,更不可能在安裝程式後,再來手工配置這個 key。(因為這樣明顯增加了安裝程式的複雜性,而安裝程式的人很可能就不是專業人員。)

         首先聲明一點,打算在 protectedKeyFilename 中使用相對路徑的想法不是太行的通!為什麼這麼說呢?因為key 檔案無法直接複製到其他機器上。當我們去每台機器上配置 key 檔案(包括建立新的key或者匯入key,均需要儲存 key的絕對路徑的位置),我們已經知道了絕對路徑,所以沒有必要去用相對路徑! David Hayden在回答一位網友關於為什麼不使用相對路徑中說到:I would have thought that relative paths wouldbe fine, but I pulled this from the documentation within the sectionManaging and Distributing Keys which is pretty specific about the needfor absolute paths .... The Cryptography Application Block stores eachkey in a separate file on the local computer....他的意思說:雖然我本來認為相對路徑將會是巧妙的,(實際上卻不是這樣),但是我將它從文檔中“管理和分發 key檔案”的部分移開了,並在這個部分中相當明確地說明需要使用絕對路徑 ... 加密應用程式塊為每個 key檔案在本機電腦中儲存了一個獨立的檔案。(原文見http://www.codeplex.com/entlib/Thread/View.aspx?ThreadId=9834)

         上面一大段廢話濃縮成成一句:既然是 key檔案都與本機電腦相關了,那相對路徑自然意義就不大了(不敢說絕對沒有意義).      key檔案無法直接複製到其他機器上的原因是對這個密鑰檔案又使用 DPAPI (Windows 資料保護) 進行加密。使用了 DPAPI進行加密的資料只能在特定的電腦上使用,換個機器當然就不行了!因為你加密的時候使用了當前電腦和登陸到該電腦的使用者的資訊。

         所以順便提一點:產生 key 檔案的過程中有個選擇項, 一個是使用者模式,一個是機器模式。使用者模式是登陸到該電腦的用
戶才能使用這個 key檔案,機器模式當然就是只要是這個電腦上的使用者都可以使用這個 key 檔案。比如部署 WebForms 的
WebSite 需要使用機器模式,至於WinForms的部署,如果不能確認電腦上只有一個帳戶會使用你部署的軟體,還是使用機器模式吧

         針對第一個問題的解決方案:

         如果想將一個設定檔(比如web.config, App.config)在一台電腦加密後,在其他電腦上都能使用,就達到了我們的目的。

         說到對設定檔加密,自然要提到它們兩個:

         DPAPIProtectedConfigurationProvider。使用 Windows 資料保護 API (DPAPI) (DPAPI)對資料進行加密和解密。

         RsaProtectedConfigurationProvider。使用 RSA 密碼編譯演算法對資料進行加密和解密。

         這兩個提供者都提供對資料的強加密;但是,如果打算在多台電腦上使用同一個加密設定檔,則只有使用RsaProtectedConfigurationProvider。因為這個才能匯出用於對資料進行加密的加密金鑰,並在另一台電腦上匯入它們。

         我們使用組態工具對設定檔的配置區進行加密時可以指定哪個ProtectedConfigurationProvider。很顯然,在解決這個問題上,我們只能使用RsaProtectedConfigurationProvider。由於不同的電腦上RSA密鑰容器是各不相同的,所以我們需要從一台電腦上匯出一個RSA 密鑰容器,然後匯入其他電腦上!由於匯入方式是可以用 DOS 命令實現,所以在部署上不存在問題!另外,由於.NETFramework 有個預設的RSA密鑰容器,名稱為 "NetFrameworkConfigurationKey",在machine.config檔案可以看到這個預設的參數。

         先提示以下:aspnet_regiis.exe 在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 下。C 盤是我的安裝路徑。所以使用 DOS命令要注意路徑。(可以通過 開始菜單 -> 所有程式 -> Microsoft Visual Studio 2005 ->Visual Studio Tools -> Visual Studio 2005 命令提示 來開啟使用 aspnet_regiis命令的 cmd 介面。)

         步驟如下:

         (1)在當前電腦上,匯出 RSA密鑰容器。(可以在匯出檔案前指定路徑。)

         aspnet_regiis -px "NetFrameworkConfigurationKey" D:\RSAkeys.xml -pri

         (2)在當前電腦上,用企業庫工具加密設定檔。ProtectedConfigurationProvider 只能選擇

         RsaProtectedConfigurationProvider。

         (3)在部署的電腦上, 匯入名為 "NetFrameworkConfigurationKey" 的 RSA 密鑰容器。

         aspnet_regiis -pi "NetFrameworkConfigurationKey" D:\RSAkeys.xml

         (1)和(2)可以在當前電腦直接操作,(3)的 DOS 命令可以在部署時由程式中完成。

         這樣就完成了!

         提示一下:有可能步驟(1)匯出失敗,它不能使用 -pri 這個參數,而這個參數是匯出解密使用的資訊!如果沒有它,在其他機器上只能加密新的東西。那麼解決方案如下:

         (1)在當前電腦上, 建立新的 RSA 密鑰容器,它的名稱為: CustomKeys 。(這裡有個使用者層級和電腦層級的,下面的方式是建立電腦層級的,名字按照你的要求取)

         aspnet_regiis -pc "CustomKeys" -exp

         (2) 在當前電腦上, 向帳戶授予存取權限

         aspnet_regiis -pa "CustomKeys" "NT AUTHORITY\NETWORK SERVICE"

         其他需要存取權限的帳戶也應該被授權。

         (3)在當前電腦上,匯出 RSA密鑰容器。(可以在匯出檔案前指定路徑。)

         aspnet_regiis -px "CustomKeys" D:\RSAkeys.xml -pri

         (4)在當前電腦上,將machine.config(在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG) 中keyContainerName = "NetFrameworkConfigurationKey"  替換為我們新建立的名稱:keyContainerName   = "CustomKeys"。

         (5)在當前電腦上,用企業庫工具加密設定檔。ProtectedConfigurationProvider只能選擇 RsaProtectedConfigurationProvider。

         (6)在部署的電腦上, 匯入名為 "NetFrameworkConfigurationKey" 的 RSA 密鑰容器。

         aspnet_regiis -pi "NetFrameworkConfigurationKey" D:\RSAkeys.xml

         順便提一下刪除 RSA密鑰容器 的命令:

         aspnet_regiis -pz "CustomKeys"

         當你輸入一個錯誤的命令,會顯示協助命令資訊。另外提示: 以上命令如果使用複製的方式,一定要注意檢查底線和空格的位置!

         針對第二個問題,提出兩種解決方案:

         方案一:

         前面提到過,可以使用先匯出key檔案,然後再匯入 key檔案的方法解決,僅解決開發人員之間的需要,卻不符合我們部署的實際需要!當然,如果你願意在部署的機器上安裝 Enterprise Library3.0,然後用它來重新設定加密檔案,是非常簡便的。下面提出符合實際部署需求的解決方案。

         既然可以Enterprise Library 3.0通過手工的方式可以在部署的機器上匯入 key 檔案。這也意味我們可以通過編程的方式來部署的機器上匯入 key 檔案。因為手工匯入也要通過程式來實現的。

         那麼,這部分代碼去哪裡找呢?Enterprise Library3.0不是提供了原始碼的嘛,而且包括組態工具的原始碼。在 C:\EntLib3Src\App Blocks 目錄(我的安裝目錄)下EnterpriseLibrary 解決方案件檔案,就是這個東西,我們可以從裡面尋找一些蛛絲馬跡。

         這裡舉例只針對 symmetricCryptoProviders 部署 key 檔案!

         一、部署的新的key 檔案步驟如下:

         (1)建立一個新的 key 檔案。

 

//-- 產生新的 key 檔案
             byte[] key = KeyManager.GenerateSymmetricKey(typeof(DESCryptoServiceProvider));
             byte[] encryptedKey = ProtectedData.Protect(key, null, DataProtectionScope.CurrentUser);
             Stream fs = null;
             try
             {
                 fs = new FileStream(keyFilePath, FileMode.Create);
                 KeyManager.Write(fs, encryptedKey, DataProtectionScope.CurrentUser);
                 fs.Flush();
             }
             finally
             {
                 if (fs != null)
                     fs.Close();
             }
         (2)修改設定檔中 key 檔案的路徑。就是那個 protectedKeyFilename 屬性。

 

/**//// <summary>
         /// 修改設定檔中 key 路徑,就是 protectedKeyFilename 的屬性值
         /// </summary>
         /// <param name="keyFilePath">自訂 key 檔案的路徑</param>
         private void ModifProtectedKeyFilename(string keyFilePath)
         {
             //從組節點讀取
             Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
             if (config.HasFile)
             {
                 ConfigurationSection configurationSection = config.Sections["securityCryptographyConfiguration"];
                 CryptographySettings cryptographySettings = configurationSection as CryptographySettings;
                NameTypeConfigurationElementCollection<SymmetricProviderData,CustomSymmetricCryptoProviderData> elementCollection =cryptographySettings.SymmetricCryptoProviders;
                 SymmetricProviderData symmetricProviderData = elementCollection.Get("DESCryptoServiceProvider");
                 symmetricProviderData.ElementInformation.Properties["protectedKeyFilename"].Value = keyFilePath;
                 config.Save(ConfigurationSaveMode.Minimal);
             }
         }

         但是,有人會問,用匯出的密鑰檔案可以恢複開發時的 key 檔案嗎? 雖然建立一個新的 key檔案的方式可以解決部署問題,但是就想使用通過編程的方式來恢複開發時的 key檔案,比如我,就認這個死理。因為在部署前,我已經有了一些資料用這個 key加密了!當然,可以把所以資料放在部署後來初始化加密!:)所以開了玩笑!只是想開闊一下思路!進入正題:

         二、恢複 key 檔案步驟如下:

        (1)恢複那個 key 檔案。

//-- 恢複 key 檔案
             Stream fs = null;
             //分發密鑰檔案名稱:ExportKey.txt,密碼:123456
             using (Stream fileOut = File.OpenRead("ExportKey.txt"))
             {
                 ProtectedKey protectedKey = KeyManager.RestoreKey(fileOut, "123456", DataProtectionScope.LocalMachine);
                 try
                 {
                     fs = new FileStream(keyFilePath, FileMode.Create);
                     KeyManager.Write(fs, protectedKey.EncryptedKey, DataProtectionScope.CurrentUser);
                     fs.Flush();
                 }
                 finally
                 {
                     if (fs != null)
                         fs.Close();
                 }
             }
        (2)修改設定檔中 key 檔案的路徑。就是那個 protectedKeyFilename 屬性。

        這個與(一)中的是一樣的!

        總結解決這個方案,思想很簡單:建立一個新的或是恢複 key 檔案,這樣該 key 檔案與部署的機器關聯起來了,然後修改設定檔中 key 檔案的路徑。

        我們現在來說說第二個解決方案!

        方案二:

        最初, 可能有這麼一個想法,如果產生一個 key 檔案,直接copy到任何電腦上都可以使用,那該多方便。下面,我就給出這種解決方案。

        思想是:把隨機產生的密鑰放在 xml 檔案中,然後xml檔案通過嵌入的方式加入到程式集中,然後我們可以在一個通用加密解密類中通過反射的方式把密鑰從 xml檔案讀出來,然後用來加密和解密。另外,我們可以通過一般的可逆加密方式對放在xml檔案中的密鑰進行加密解密。但是強調的是,這個方式的安全性不如上面的,畢竟放在 xml檔案的密鑰有被破解的風險。當然,這種方式在安全性要求不是特別高的系統還是可以採用的。

//-----------------------------------------------------------------------------------------
// 模組編號:
// 檔案名稱: CustomCryptography.cs
// 描述: CustomCryptography 資料對稱式加密解密類
// 作者:ChenJie
// 編寫日期:2007-5-30
// Copyright 2007
//-----------------------------------------------------------------------------------------
using System;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml;
using System.Security.Cryptography;

namespace CryptographyLib
{
     /**//// <summary>
     /// 自訂的資料對稱式加密解密類
     /// </summary>
     public class CustomCryptography : ICryptography
     {
         私人常量#region 私人常量
         /**//// <summary>
         /// 嵌入到本項目程式集中的 XML 檔案
         /// </summary>
         private const string KEY_FILE = "CryptographyLib.SystemKey.config";
         #endregion

         實現介面的方法#region 實現介面的方法

         /**//// <summary>
         /// 加密字串
         /// </summary>
         /// <param name="plainText">明文</param>
         /// <returns>密文</returns>
         public string EncryptData(string plainText)
         {
             string encryptData = string.Empty;
             //建立一個新的 DES key.
             DESCryptoServiceProvider key = new DESCryptoServiceProvider();
             //設定資料加密標準 (DES) 演算法的機密密鑰和對稱演算法的初始化向量的值
             byte[] Key = null;
             byte[] IV = null;
             GetKEYAndIV(out Key, out IV);
             key.Key = Key;
             key.IV = IV;
             return EncryptData(plainText, key);
         }

         /**//// <summary>
         /// 通過 DESCryptoServiceProvider 解密字串
         /// </summary>
         /// <param name="decryptedText">密文</param>
         /// <returns>明文</returns>
         public string DecryptData(string decryptedText)
         {
             string decryptData = string.Empty;
             //建立一個新的 DES key.
             DESCryptoServiceProvider key = new DESCryptoServiceProvider();
             //設定資料加密標準 (DES) 演算法的機密密鑰和對稱演算法的初始化向量的值
             byte[] Key = null;
             byte[] IV = null;
             GetKEYAndIV(out Key, out IV);
             key.Key = Key;
             key.IV = IV;
             return DecryptData(decryptedText, key);
         }

         /**//// <summary>
         /// 使用 MD5 加密字串
         /// </summary>
         /// <param name="plainText">明文</param>
         /// <returns>密文</returns>
         public string EncryptDataByHash(string plainText)
         {
             HashAlgorithm hashCryptoService = new SHA1Managed();
             byte[] bytIn = UTF8Encoding.UTF8.GetBytes(plainText);
             byte[] bytOut = hashCryptoService.ComputeHash(bytIn);
             return Convert.ToBase64String(bytOut);
         }

         /**//// <summary>
         /// 比較 MD5 加密字串
         /// </summary>
         /// <param name="plainText">明文</param>
         /// <param name="hashedText">要比較的 hash 值</param>
         /// <returns>是否相同,是則返回 true, 否則返回 false</returns>
         public bool CompareHash(string plainText, string hashedText)
         {
             bool compare = false;
             string encryptData = EncryptDataByHash(plainText);
             compare = encryptData.Equals(hashedText);
             return compare;
         }

         #endregion

         私人方法#region 私人方法
         /**//// <summary>
         /// 加密字串
         /// </summary>
         /// <param name="plainText">明文</param>
         /// <param name="key">對稱演算法的的抽象基類</param>
         /// <returns>密文</returns>
         private string EncryptData(string plainText, SymmetricAlgorithm key)
         {
             string encryptData = string.Empty;
             byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

             /**/////---------- 方法一 ----------------------------
             ////建立一個 MemoryStream 對象
             //MemoryStream ms = new MemoryStream();
             /**///// 建立一個加密流
             //CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
             /**///// 建立一個 StreamWriter 對象
             //StreamWriter sw = new StreamWriter(encStream);
             //sw.WriteLine(plainText);
             //sw.Close();
             //encryptData = Convert.ToBase64String(ms.ToArray());
             //ms.Close();
             /**/////---------- 方法一 結束 ----------------------------

             //---------- 方法二 ----------------------------
             MemoryStream ms = new MemoryStream();
             CryptoStream cs = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
             cs.Write(plainTextBytes, 0, plainTextBytes.Length);
             cs.FlushFinalBlock();
             encryptData = Convert.ToBase64String(ms.ToArray());
             //---------- 方法二 結束 ----------------------------

             //清空數組中的內容
             Array.Clear(plainTextBytes, 0, plainTextBytes.Length);
             return encryptData;
         }        

         /**//// <summary>
         ///   解密字串
         /// </summary>
         /// <param name="decryptedText">密文</param>
         /// <param name="key">對稱演算法的的抽象基類</param>
         /// <returns>明文</returns>
         private string DecryptData(string decryptedText, SymmetricAlgorithm key)
         {
             string decryptData = string.Empty;
             byte[] decryptedByteArray = Convert.FromBase64String(decryptedText);

             /**/////---------- 方法一 ----------------------------
             ////為解密字串建立一個 MemoryStream 對象
             //MemoryStream ms = new MemoryStream(decryptedByteArray);
             /**/////建立一個 CryptoStream 對象
             //CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
             /**///// 建立一個 StreamReader 對象
             //StreamReader sr = new StreamReader(encStream);
             //decryptData = sr.ReadLine();
             //sr.Close();
             //encStream.Close();
             //ms.Close();
             /**/////---------- 方法一 結束 ----------------------------

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.