可行的做法为:
1、 使用Aspnet_setreg.exe 工具。此工具使用DPAPI来加密和解密数据,它可以把你需要保护的数据保存在注册表,它受DACL(discretionary access control list)保护,在配置文件中只需要指明注册表键的位置。有一篇How to讲解了如何使用此Aspnet_setreg.exe 工具。在我的随笔系统安全简述中对DPAPI有简单的讲述——DPAPI(Data Protection Application Programming Interface),一个保护密钥的对策。DPAPI使用用户的登录密码加密和解密数据。数据保护过程:(1)生成一个强健的Key,称为主钥,它受用户的密码保护;(2)使用基于口令的密钥生成过程由用户密码生成一个密钥;(3)这个由口令生成的密钥用来加密主钥,它被存储在由计算机上的活动目录生成的用户概述中。安全地存储登录证明,比如用户名和密码,在磁盘上,是安全应用地一个重要方面。DPAPI是一个系统提供的数据保护服务,是一个安全地存储用户证明的解决方案。
2、 直接使用DPAPI和.Net framework提供的加密算法。提供一个key(key越强就越安全),使用DPAPI加密,把它存储在注册表中,然后我们可以使用此key来加密和解密数据了——加密和解密算法我们可以选择.Net framework提供的3DES(DES比较脆弱)。最后,我们把加密过的配置项(如连接串)写入config文件即可。
使用DPAPI时,需要我们提供足够强健的key,否则安全性会降低。另外,如果侵入者获得了系统的管理员权限的话,那这些安全措施都将失效,因为管理员有权限读取我们存入注册表的key。
下面是使用DPAPI加密和解密数据的例子:
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool CryptProtectData(
ref DATA_BLOB pDataIn,
String szDataDescr,
ref DATA_BLOB pOptionalEntropy,
IntPtr pvReserved,
ref CRYPTPROTECT_PROMPTSTRUCT
pPromptStruct,
int dwFlags,
ref DATA_BLOB pDataOut);
[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int
dwFlags,
ref IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
ref String lpBuffer,
int nSize,
IntPtr *Arguments);
[StructLayout(LayoutKind.Sequential,
CharSet=CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential,
CharSet=CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public String szPrompt;
}
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
public enum Store {USE_MACHINE_STORE = 1,
USE_USER_STORE};
private Store store;
public void DataProtector(Store tempStore)
{
store = tempStore;
}
public byte[] Encrypt(byte[] plainText, byte[]
optionalEntropy)
{
bool retVal = false;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new
CRYPTPROTECT_PROMPTSTRUCT();
InitPromptstruct(ref prompt);
int dwFlags;
try
{
try
{
int bytesSize = plainText.Length;
plainTextBlob.pbData =
Marshal.AllocHGlobal(bytesSize);
if(IntPtr.Zero == plainTextBlob.pbData)
{
throw new Exception("Unable to allocate
plaintext buffer.");
}
plainTextBlob.cbData = bytesSize;
Marshal.Copy(plainText, 0,
plainTextBlob.pbData, bytesSize);
}
catch(Exception ex)
{
throw new Exception("Exception marshalling
data. " + ex.Message);
}
if(Store.USE_MACHINE_STORE == store)
{
dwFlags =
CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
if(null == optionalEntropy)
{
optionalEntropy = new byte[0];
}
try
{
int bytesSize = optionalEntropy.Length;
entropyBlob.pbData =
Marshal.AllocHGlobal(optionalEntropy.Length);;
if(IntPtr.Zero == entropyBlob.pbData)
{
throw new Exception("Unable to
allocate entropy data buffer.");
}
Marshal.Copy(optionalEntropy, 0,
entropyBlob.pbData, bytesSize);
entropyBlob.cbData = bytesSize;
}
catch(Exception ex)
{
throw new Exception("Exception entropy
marshalling data. " +
ex.Message);
}
}
else
{
dwFlags = CRYPTPROTECT_UI_FORBIDDEN;
}
retVal = CryptProtectData(ref plainTextBlob, "",
ref entropyBlob,
IntPtr.Zero, ref prompt, dwFlags,
ref cipherTextBlob);
if(false == retVal)
{
throw new Exception("Encryption failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
if(IntPtr.Zero != plainTextBlob.pbData)
{
Marshal.FreeHGlobal(plainTextBlob.pbData);
}
if(IntPtr.Zero != entropyBlob.pbData)
{
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
catch(Exception ex)
{
throw new Exception("Exception encrypting. " +
ex.Message);
}
byte[] cipherText = new byte[cipherTextBlob.cbData];
Marshal.Copy(cipherTextBlob.pbData, cipherText, 0,
cipherTextBlob.cbData);
Marshal.FreeHGlobal(cipherTextBlob.pbData);
return cipherText;
}
private void InitPromptstruct(ref
CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize =
Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}
private unsafe static String GetErrorMessage(int
errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = new IntPtr();
IntPtr prtArguments = new IntPtr();
int retVal = FormatMessage(dwFlags, ref ptrlpSource,
errorCode, 0,
ref lpMsgBuf, messageSize,
&prtArguments);
if(0 == retVal)
{
throw new Exception("Failed to format message for
error code " +
errorCode + ". ");
}
return lpMsgBuf;
}