背景
在程序或服务开发过程中,我们通常会把一些程序需要用到的常量数据配置在web.config或app.config文件中,通常配置到这些文件中的Key与Value都是明文的,但有时候我们并不希望这些配置让他人知道。
在这种情况下,我们可以使用ASP.NET Encrypt和Decrypt来对配置文件进行加密,不影响程序使用,但又不被他人知道配置的具体内容。
环境
- Windonw 7 / Windows Server 2008
- .Net Framework 4.0
- IIS
以上环境准备好后,在搭建好的IIS上创建三个站点 WebSite1, WebSite2, WebSite3
工具
- asp.net_regiis.exe
- vs 2010 tool
- sn.exe
- gacutil.exe
asp.net_regiis.exe位于路径C:\Windows\Microsoft.NET\Framework64\v4.0.30319
使用管理员身份运行cmd.exe
Start --> All Programs --> Microsoft Visual Studio 2010 --> Visual Studio Tools --> Visual Studio x64 Win64 Command Prompt (2010)(run as administrator)
sn, gacutil 在VS 2010 tool中可直接使用
Providers in .NET Framework
DpapiProtectedConfigurationProvider
uses the Windows Data Protected API(DPAPI) to encrypt and Decrypt data.RsaProtectedConfigurationProvider
useed the RSA encryption algorithm to encrypt and Decrypt data.
Providers means Protected configuration Providers
Machine-Level and User-Level
Machine-Level
available to all users
Machine-level 的Key对所有管理员用户有效果,但也受ACLs的约束
User-Level
available only to the user that created the key container.
stored with the Windonw user profile for a particular user
userd to encrypt and decrypt information for applications that run under that specific user identity.
user-level 的Key是与用户账号绑定的,用户被删除时,key也被删除
这里所讲的avalliable是指能够加密和解密
Tool and Parameters
Tool
asp.net_regiis.exe
encrypt parameters
-pe the name of the configuraiton element to be encrypt
-app identity the application for which the web.config file will be encrypted
-site identity which web site the application is a part of
-prov identity the name of the ProtectedConfigurationProvider that will preform the encryption and decryption.
pe, app 是必须要指定的值
site默认值为1, prov默认使用defaultProvider
decrypt parameters
-pd the name of the configuration element to be decrypted.
-app identify the application for which the web.config file will be encrypted
-site identify which Web site the application is a part of
-prov not need to specify
在解密时不需要使用prov来指定ProtectedConfigurationProvider,because that information is read from the configProtectionProvider attribute of the protected configuration section.
Encrypting Website’s Web.config
在VS Tool中输入以下命令
aspnet_regiis -pef "connectionStrings" E:\webSite1
或
aspnet_regiis -pe "connectionStrings" -app "/WebSite1" -site "WebSite1"
需要为WebSite1添加虚拟目录
或
aspnet_regiss -pe "connectionStrings" -app "/WebSite1" -site "WebSite1" -prov DataProtectionConfigurationProvider
需要为WebSite1添加虚拟目录,指定Provider
解密
aspnet_regiis -pd "connectionStrings" -app "/WebSite1" -site "WebSite1"
Create a RSA Key Container
Tool
aspnet_regiis
Parameters
-pc : the name of the key container used by the RsaProtectedConfigurationProvider specified in the configProtectedData section of web.config file
-exp : ensure that RSA key container can be exported
Web.config的配置
<configProtectedData>
<providers>
<add name="CustomerProvider" keyContainerName="SampleKeys" useMachineContainer="true" description="Users RsaCryptoSErviceProvider to encrypt and decrypt" type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=4.0.0.0, Cultuer=neutral, PublicKeyToken=b03f5f7f11d50a3a">
</providers>
</configProtectedData>
以上配置中的KeyContainerName="true",表示使用Machine-level, false表示使用user-level
加密时使用以下命令
aspnet_regiis -pe "connectionStrings" -app "/WebSite2" -site "WebSite2" -prov "CustomeProvider"
Exporting a RSA Key Container
使用命令
aspnet_regiis -px "SampleKeys" E:\MachineSmapleKey.xml -pri
Importing a RSA Key Container
aspnet_regiis -pi "MyKeys" keys.xml -pku
Deleting a RSA Key Container
aspnet_regiis -pz "MyKeys"
Custome Provider Type
Implementing a Protected Configuration Provider
- Algorithm
an algorithm other than those available with the RSA or DPAPI providers - Required Classes
ProtectedConfigurationProvider class from the System.Configuration namespace
ProviderBase class from the System.Configuration.Provider namespace - Required Members
Initialize method (from ProviderBase)
Encrypt method (from ProtectedConfigurationProvider)
Decrypt method (from ProtectedConfigurationProvider)
Build Protected Configuration Provider
- Generate a strong-name key pair
sn -k keys.snk
- Create a program file named TripleDESProtectedConfigurationProvider
using System.Xml;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.Configuration;
namespace AA.BB.ProtectedConfiguration
{
public class TripleDESProtectedConfigurationProvider : ProtectedConfigurationProvider
{
private TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
private string pKeyFilePath;
private string pName;
public string KeyFilePath
{
get { return pKeyFilePath; }
}
//
// ProviderBase.Name
//
public override string Name
{
get { return pName; }
}
//
// ProviderBase.Initialize
//
public override void Initialize(string name, NameValueCollection config)
{
pName = name;
pKeyFilePath = config["keyFilePath"];
ReadKey(KeyFilePath);
}
//
// ProtectedConfigurationProvider.Encrypt
//
public override XmlNode Encrypt(XmlNode node)
{
string encryptedData = EncryptString(node.OuterXml);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml("<EncryptedData>" + encryptedData + "</EncryptedData>");
return xmlDoc.DocumentElement;
}
//
// ProtectedConfigurationProvider.Decrypt
//
public override XmlNode Decrypt(XmlNode encryptedNode)
{
string decryptedData = DecryptString(encryptedNode.InnerText);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(decryptedData);
return xmlDoc.DocumentElement;
}
//
// EncryptString
// Encrypts a configuration section and returns the encrypted
// XML as a string.
//
private string EncryptString(string encryptValue)
{
byte[] valBytes = Encoding.Unicode.GetBytes(encryptValue);
ICryptoTransform transform = des.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write);
cs.Write(valBytes, 0, valBytes.Length);
cs.FlushFinalBlock();
byte[] returnBytes = ms.ToArray();
cs.Close();
return Convert.ToBase64String(returnBytes);
}
//
// DecryptString
// Decrypts an encrypted configuration section and returns the
// unencrypted XML as a string.
//
private string DecryptString(string encryptedValue)
{
byte[] valBytes = Convert.FromBase64String(encryptedValue);
ICryptoTransform transform = des.CreateDecryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write);
cs.Write(valBytes, 0, valBytes.Length);
cs.FlushFinalBlock();
byte[] returnBytes = ms.ToArray();
cs.Close();
return Encoding.Unicode.GetString(returnBytes);
}
//
// CreateKey
// Generates a new TripleDES key and vector and writes them
// to the supplied file path.
//
public void CreateKey(string filePath)
{
des.GenerateKey();
des.GenerateIV();
StreamWriter sw = new StreamWriter(filePath, false);
sw.WriteLine(ByteToHex(des.Key));
sw.WriteLine(ByteToHex(des.IV));
sw.Close();
}
//
// ReadKey
// Reads in the TripleDES key and vector from the supplied
// file path and sets the Key and IV properties of the
// TripleDESCryptoServiceProvider.
//
private void ReadKey(string filePath)
{
StreamReader sr = new StreamReader(filePath);
string keyValue = sr.ReadLine();
string ivValue = sr.ReadLine();
des.Key = HexToByte(keyValue);
des.IV = HexToByte(ivValue);
}
//
// ByteToHex
// Converts a byte array to a hexadecimal string.
//
private string ByteToHex(byte[] byteArray)
{
string outString = "";
foreach (Byte b in byteArray)
outString += b.ToString("X2");
return outString;
}
//
// HexToByte
// Converts a hexadecimal string to a byte array.
//
private byte[] HexToByte(string hexString)
{
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
returnBytes[i] = Convert.ToByte(hexString.Substring(i*2, 2), 16);
return returnBytes;
}
}
}
- Compile the code and assign the resulting assembly with the strong-name key
csc /out:TripleDESProtectedConfigurationProvider.dll /t:library TripleDESProtectedConfigurationProvider.cs /r:System.Configuration.dll /keyfile:keys.snk
- Install the assembly in the GAC(global assembly cach)
gacutil -i TripleDESProtectedConfigurationProvider.dll
Use a Custom Provider type
-
Generate Key File
CreateKey.exe E:\ASP\Keys.txt
Modify the configProtectedData Section of the Web.config
<configProtectedData>
<providers>
<add name="SampleProvider" useMachineContainer="true" type="AA.BB.TripleDESProtectedConfigurationProvider TripleDESProtectedConfigurationProvider Version=0.0.0.0, Cultuer=neutral PublicKeyToken=b06675f7f11d50a3a",description="Users RsaCryptoSErviceProvider to encrypt and decrypt" keyFilePath="E:\ASP\Key" >
</providers>
</configProtectedData>