如何使用 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 would be fine, but I pulled this from the documentation within the section Managing and Distributing Keys which is pretty specific about the need for absolute paths .... The Cryptography Application Block stores each key 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)对数据进行加密和解密。

        RsaProtectedConfigurationProvider。使用 RSA 加密算法对数据进行加密和解密。

        这两个提供程序都提供对数据的强加密;但是,如果打算在多台计算机上使用同一个加密配置文件,则只有使用 RsaProtectedConfigurationProvider。因为这个才能导出用于对数据进行加密的加密密钥,并在另一台计算机上导入它们。

        我们使用配置工具对配置文件的配置区进行加密时可以指定哪个 ProtectedConfigurationProvider。很显然,在解决这个问题上,我们只能使用RsaProtectedConfigurationProvider。由于不同的计算机上RSA密钥容器是各不相同的,所以我们需要从一台计算机上导出一个RSA 密钥容器,然后导入其他计算机上!由于导入方式是可以用 DOS 命令实现,所以在部署上不存在问题!另外,由于.NET Framework 有个默认的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 Library 3.0,然后用它来重新配置加密文件,是非常简便的。下面提出符合实际部署需求的解决方法。

        既然可以Enterprise Library 3.0通过手工的方式可以在部署的机器上导入 key 文件。这也意味我们可以通过编程的方式来部署的机器上导入 key 文件。因为手工导入也要通过程序来实现的。

        那么,这部分代码去哪里找呢?Enterprise Library 3.0不是提供了源代码的嘛,而且包括配置工具的源代码。在 C:\EntLib3Src\App Blocks 目录(我的安装目录)下 EnterpriseLibrary 解决方案件文件,就是这个东西,我们可以从里面寻找一些蛛丝马迹icon17.gif

        这里举例只针对 symmetricCryptoProviders 部署 key 文件!

        一、部署的新的key 文件步骤如下:

        (1)创建一个新的 key 文件。

None.gif // -- 产生新的 key 文件
None.gif
             byte [] key  =  KeyManager.GenerateSymmetricKey( typeof (DESCryptoServiceProvider));
None.gif            
byte [] encryptedKey  =  ProtectedData.Protect(key,  null , DataProtectionScope.CurrentUser);
None.gif            Stream fs 
=   null ;
None.gif            
try
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                fs 
= new FileStream(keyFilePath, FileMode.Create);
InBlock.gif                KeyManager.Write(fs, encryptedKey, DataProtectionScope.CurrentUser);
InBlock.gif                fs.Flush();
ExpandedBlockEnd.gif            }

None.gif            
finally
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                
if (fs != null)
InBlock.gif                    fs.Close();
ExpandedBlockEnd.gif            }

        (2)修改配置文件中 key 文件的路径。就是那个 protectedKeyFilename 属性。

 

ExpandedBlockStart.gif ContractedBlock.gif   /**/ /// <summary>
InBlock.gif        
/// 修改配置文件中 key 路径,就是 protectedKeyFilename 的属性值
InBlock.gif        
/// </summary>
ExpandedBlockEnd.gif        
/// <param name="keyFilePath">自定义 key 文件的路径</param>

None.gif          private   void  ModifProtectedKeyFilename( string  keyFilePath)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            
//从组节点读取
InBlock.gif
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
InBlock.gif            
if (config.HasFile)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                ConfigurationSection configurationSection 
= config.Sections["securityCryptographyConfiguration"];
InBlock.gif                CryptographySettings cryptographySettings 
= configurationSection as CryptographySettings;
InBlock.gif                NameTypeConfigurationElementCollection
<SymmetricProviderData, CustomSymmetricCryptoProviderData> elementCollection = cryptographySettings.SymmetricCryptoProviders;
InBlock.gif                SymmetricProviderData symmetricProviderData 
= elementCollection.Get("DESCryptoServiceProvider");
InBlock.gif                symmetricProviderData.ElementInformation.Properties[
"protectedKeyFilename"].Value = keyFilePath;
InBlock.gif                config.Save(ConfigurationSaveMode.Minimal);
ExpandedSubBlockEnd.gif            }

ExpandedBlockEnd.gif        }


        但是,有人会问,用导出的密钥文件可以恢复开发时的 key 文件吗? 虽然创建一个新的 key 文件的方式可以解决部署问题,但是就想使用通过编程的方式来恢复开发时的 key 文件,比如我,就认这个死理。因为在部署前,我已经有了一些数据用这个 key 加密了!当然,可以把所以数据放在部署后来初始化加密!:)所以开了玩笑!只是想开阔一下思路!进入正题:

        二、恢复 key 文件步骤如下:

       (1)恢复那个 key 文件。

None.gif // -- 恢复 key 文件
None.gif
            Stream fs  =   null ;
None.gif            
// 分发密钥文件名称:ExportKey.txt,密码:123456
None.gif
             using  (Stream fileOut  =  File.OpenRead( " ExportKey.txt " ))
ExpandedBlockStart.gifContractedBlock.gif            
dot.gif {
InBlock.gif                ProtectedKey protectedKey 
= KeyManager.RestoreKey(fileOut, "123456", DataProtectionScope.LocalMachine);
InBlock.gif                
try
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    fs 
= new FileStream(keyFilePath, FileMode.Create);
InBlock.gif                    KeyManager.Write(fs, protectedKey.EncryptedKey, DataProtectionScope.CurrentUser);
InBlock.gif                    fs.Flush();
ExpandedSubBlockEnd.gif                }

InBlock.gif                
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
if (fs != null)
InBlock.gif                        fs.Close();
ExpandedSubBlockEnd.gif                }

ExpandedBlockEnd.gif            }

       (2)修改配置文件中 key 文件的路径。就是那个 protectedKeyFilename 属性。

       这个与(一)中的是一样的!

       总结解决这个方案,思想很简单:创建一个新的或是恢复 key 文件,这样该 key 文件与部署的机器关联起来了,然后修改配置文件中 key 文件的路径。

       我们现在来说说第二个解决方案!

       方案二:

       最初, 可能有这么一个想法,如果生成一个 key 文件,直接copy到任何计算机上都可以使用,那该多方便。下面,我就给出这种解决方案。

       思想是:把随机生成的密钥放在 xml 文件中,然后xml 文件通过嵌入的方式加入到程序集中,然后我们可以在一个通用加密解密类中通过反射的方式把密钥从 xml 文件读出来,然后用来加密和解密。另外,我们可以通过一般的可逆加密方式对放在 xml文件中的密钥进行加密解密。但是强调的是,这个方式的安全性不如上面的,毕竟放在 xml 文件的密钥有被破解的风险。当然,这种方式在安全性要求不是特别高的系统还是可以采用的。

None.gif // -----------------------------------------------------------------------------------------
None.gif
//  模块编号:
None.gif
//  文件名: CustomCryptography.cs
None.gif
//  描述: CustomCryptography 数据对称加密解密类
None.gif
//  作者:ChenJie 
None.gif
//  编写日期:2007-5-30
None.gif
//  Copyright 2007
None.gif
// -----------------------------------------------------------------------------------------
None.gif
using  System;
None.gif
using  System.Text;
None.gif
using  System.Reflection;
None.gif
using  System.IO;
None.gif
using  System.Xml;
None.gif
using  System.Security.Cryptography;
None.gif
None.gif
namespace  CryptographyLib
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 自定义的数据对称加密解密类
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class CustomCryptography : ICryptography
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
私有常量#region 私有常量
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 嵌入到本项目程序集中的 XML 文件
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        private const string KEY_FILE = "CryptographyLib.SystemKey.config";
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
实现接口的方法#region 实现接口的方法
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 加密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="plainText">明文</param>
ExpandedSubBlockEnd.gif        
/// <returns>密文</returns>

InBlock.gif        public string EncryptData(string plainText)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string encryptData = string.Empty;
InBlock.gif            
//创建一个新的 DES key.
InBlock.gif
            DESCryptoServiceProvider key = new DESCryptoServiceProvider();
InBlock.gif            
//设置数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量的值
InBlock.gif
            byte[] Key = null;
InBlock.gif            
byte[] IV = null;
InBlock.gif            GetKEYAndIV(
out Key, out IV);
InBlock.gif            key.Key 
= Key;
InBlock.gif            key.IV 
= IV;
InBlock.gif            
return EncryptData(plainText, key);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 通过 DESCryptoServiceProvider 解密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="decryptedText">密文</param>
ExpandedSubBlockEnd.gif        
/// <returns>明文</returns>

InBlock.gif        public string DecryptData(string decryptedText)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string decryptData = string.Empty;
InBlock.gif            
//创建一个新的 DES key.
InBlock.gif
            DESCryptoServiceProvider key = new DESCryptoServiceProvider();
InBlock.gif            
//设置数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量的值
InBlock.gif
            byte[] Key = null;
InBlock.gif            
byte[] IV = null;
InBlock.gif            GetKEYAndIV(
out Key, out IV);
InBlock.gif            key.Key 
= Key;
InBlock.gif            key.IV 
= IV;
InBlock.gif            
return DecryptData(decryptedText, key);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 使用 MD5 加密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="plainText">明文</param>
ExpandedSubBlockEnd.gif        
/// <returns>密文</returns>

InBlock.gif        public string EncryptDataByHash(string plainText)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            HashAlgorithm hashCryptoService 
= new SHA1Managed();
InBlock.gif            
byte[] bytIn = UTF8Encoding.UTF8.GetBytes(plainText);
InBlock.gif            
byte[] bytOut = hashCryptoService.ComputeHash(bytIn);
InBlock.gif            
return Convert.ToBase64String(bytOut);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 比较 MD5 加密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="plainText">明文</param>
InBlock.gif        
/// <param name="hashedText">要比较的 hash 值</param>
ExpandedSubBlockEnd.gif        
/// <returns>是否相同,是则返回 true, 否则返回 false</returns>

InBlock.gif        public bool CompareHash(string plainText, string hashedText)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
bool compare = false;
InBlock.gif            
string encryptData = EncryptDataByHash(plainText);
InBlock.gif            compare 
= encryptData.Equals(hashedText);
InBlock.gif            
return compare;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
私有方法#region 私有方法
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 加密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="plainText">明文</param>
InBlock.gif        
/// <param name="key">对称算法的的抽象基类</param>
ExpandedSubBlockEnd.gif        
/// <returns>密文</returns>

InBlock.gif        private string EncryptData(string plainText, SymmetricAlgorithm key)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string encryptData = string.Empty;
InBlock.gif            
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
/**/////---------- 方法一 ----------------------------
ExpandedSubBlockEnd.gif            
////创建一个 MemoryStream 对象

InBlock.gif            //MemoryStream ms = new MemoryStream();
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**///// 创建一个加密流
InBlock.gif            //CryptoStream encStream = new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**///// 创建一个 StreamWriter 对象
InBlock.gif            //StreamWriter sw = new StreamWriter(encStream);
InBlock.gif            
//sw.WriteLine(plainText);
InBlock.gif            
//sw.Close();
InBlock.gif            
//encryptData = Convert.ToBase64String(ms.ToArray());
InBlock.gif            
//ms.Close();
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**/////---------- 方法一 结束 ----------------------------
InBlock.gif
InBlock.gif            
//---------- 方法二 ----------------------------
InBlock.gif
            MemoryStream ms = new MemoryStream();
InBlock.gif            CryptoStream cs 
= new CryptoStream(ms, key.CreateEncryptor(), CryptoStreamMode.Write);
InBlock.gif            cs.Write(plainTextBytes, 
0, plainTextBytes.Length);
InBlock.gif            cs.FlushFinalBlock();
InBlock.gif            encryptData 
= Convert.ToBase64String(ms.ToArray());
InBlock.gif            
//---------- 方法二 结束 ----------------------------
InBlock.gif
InBlock.gif            
//清空数组中的内容
InBlock.gif
            Array.Clear(plainTextBytes, 0, plainTextBytes.Length);
InBlock.gif            
return encryptData;
ExpandedSubBlockEnd.gif        }
        
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
///  解密字符串
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="decryptedText">密文</param>
InBlock.gif        
/// <param name="key">对称算法的的抽象基类</param>
ExpandedSubBlockEnd.gif        
/// <returns>明文</returns>

InBlock.gif        private string DecryptData(string decryptedText, SymmetricAlgorithm key)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string decryptData = string.Empty;
InBlock.gif            
byte[] decryptedByteArray = Convert.FromBase64String(decryptedText);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
/**/////---------- 方法一 ----------------------------
ExpandedSubBlockEnd.gif            
////为解密字符串创建一个 MemoryStream 对象

InBlock.gif            //MemoryStream ms = new MemoryStream(decryptedByteArray);
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**/////创建一个 CryptoStream 对象
InBlock.gif            //CryptoStream encStream = new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Read);
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**///// 创建一个 StreamReader 对象
InBlock.gif            //StreamReader sr = new StreamReader(encStream);
InBlock.gif            
//decryptData = sr.ReadLine();
InBlock.gif            
//sr.Close();
InBlock.gif            
//encStream.Close();
InBlock.gif            
//ms.Close();
ExpandedSubBlockStart.gifContractedSubBlock.gif
            /**/////---------- 方法一 结束 ----------------------------
InBlock.gif
InBlock.gif            
//---------- 方法二 ---------------------------------
InBlock.gif
            MemoryStream ms = new MemoryStream();
InBlock.gif            CryptoStream cs 
= new CryptoStream(ms, key.CreateDecryptor(), CryptoStreamMode.Write);
InBlock.gif            cs.Write(decryptedByteArray, 
0, decryptedByteArray.Length);
InBlock.gif            cs.FlushFinalBlock();
InBlock.gif            decryptData 
= Encoding.UTF8.GetString(ms.ToArray());
InBlock.gif            
//---------- 方法二 结束 ----------------------------
InBlock.gif
InBlock.gif            
//清空数组中的内容
InBlock.gif
            Array.Clear(decryptedByteArray, 0, decryptedByteArray.Length);
InBlock.gif            
return decryptData;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 产生对称算法的初始化向量(IV和数据加密标准 (DES) 算法的机密密钥(key)
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        private void GenerateIVAndKey()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//创建一个新的 DES key.
InBlock.gif
            DESCryptoServiceProvider key = new DESCryptoServiceProvider();
InBlock.gif            
byte[] Key = key.Key;
InBlock.gif            
byte[] IV = key.IV;
InBlock.gif            UnicodeEncoding converter 
= new UnicodeEncoding();
InBlock.gif            
string KeyValue = Convert.ToBase64String(Key);
InBlock.gif            
string IVValue = Convert.ToBase64String(IV);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获得数据加密标准 (DES) 算法的机密密钥和对称算法的初始化向量
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="Key">数据加密标准 (DES) 算法的机密密钥</param>
ExpandedSubBlockEnd.gif        
/// <param name="IV">对称算法的初始化向量</param>

InBlock.gif        private void GetKEYAndIV(out  byte[] Key, out  byte[] IV)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Key 
= null;
InBlock.gif            IV 
= null;
InBlock.gif            
using (Stream xmlInputStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(KEY_FILE))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                XmlDocument xmlDoc 
= new XmlDocument();
InBlock.gif                xmlDoc.Load(xmlInputStream);
InBlock.gif                XmlNodeList nodeList 
= xmlDoc.SelectSingleNode("Root").ChildNodes;
InBlock.gif                
foreach (XmlNode xn in nodeList)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
if (xn.NodeType != XmlNodeType.Element)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        
continue;
ExpandedSubBlockEnd.gif                    }

InBlock.gif                    
switch (xn.Name)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        
case "IV":
InBlock.gif                            IV 
= Convert.FromBase64String(xn.InnerXml);
InBlock.gif                            
break;
InBlock.gif                        
case "KEY":
InBlock.gif                            Key 
= Convert.FromBase64String(xn.InnerXml);
InBlock.gif                            
break;
InBlock.gif                        
default:
InBlock.gif                            
break;
ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

        XML文件就很简单了:

None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< Root >
None.gif  
< IV > L7h6oi25zn4= </ IV >
None.gif  
< KEY > vsbq4KMhR9I= </ KEY >
None.gif
</ Root >


       为什么 Enterprise Library 3.0 不把 key 文件弄成一个可以到处 copy 到任何计算机都能用的呢?David Hayden 说了这么一番话:企业库开发团队要求帮助使 key 文件安全可靠,因此使用了 DPAPI 加密了 key 文件,DPAPI 在不需要提供 key 文件就可以提供一种加密的方式,这是非常妙的。它的“坏处”就是它被限制在(机器的)当前用户或者(当前)机器的范围内。(The EntLib Team was required to help secure the key and hence used DPAPI to encrypt the key. DPAPI is great in that it is a way to provide encryption without requiring a key file. It is "bad" in that it is scoped to either the current user or machine. )

       说来说去,使用 DPAPI 加密的文件限制了我们在任何地方 copy 被加密的文件,但是却是从安全性上考虑必须这样。

       整个解决方案下载

       全文结束!

       参考资料:
       (1)加密 web.config 
       (2)asp.net2.0中的数据保护

转载于:https://www.cnblogs.com/scucj/archive/2007/05/30/765749.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值