.NET安全系列之五:数据保护API

本文介绍了如何使用Windows的DPAPI(数据保护API)通过System.Security.Cryptography.ProtectedData和ProtectedMemory类来加密和解密数据。此外,还展示了如何利用SecureString类保护敏感字符串,并在应用程序配置文件中加密设置。

http://www.cnblogs.com/lsxqw2004/archive/2009/01/24/1380721.html

 

从Windows 2000开始,Windows操作系统提供了一套密码学方面的API,称为DPAPI(Data Protection API,数据保护API)。系统中的这套API由crypt32.dll实现,它使用当前用户的登录用户名/密码对来管理密钥。它可以用于标识一个进程、 Windows会话或目前使用的机器,从而在用户、进程、会话或机器级别上加密数据从而确保其机密性。同时使用DPAPI可以使我们不用再负责密钥的管 理。

深入一些,这套API还可以管理对用户密码的修改。例如,如果为某个特定用户将数据加密保存后,即使该用户的密钥发生了变化,仍然可以使用那些数据。这项功能依靠保存过期密钥这一机制实现的。

 

使用System.Security.Cryptography.ProtectedData类

下面的例子演示了使用System.Security.Cryptography.ProtectedData类在用户级别保护数据。

 

using System.Security.Cryptography;

class Program{

static void Main() {

string sMsg = "The message to encrypt!" ;

string sEnc, sDec;

System.Text.Encoding utf = new System.Text.UTF8Encoding ();

byte [] entropy = new byte [] { 1, 2, 3, 4, 5, 6, 7, 8 };

{

byte [] bMsg = utf.GetBytes(sMsg);

byte [] bEnc = ProtectedData.Protect(

bMsg , entropy , DataProtectionScope.CurrentUser);

sEnc = System.Convert .ToBase64String(bEnc);

}

{

byte [] bEnc = System.Convert .FromBase64String(sEnc);

byte [] bDec = ProtectedData.Unprotect(

bEnc, entropy, DataProtectionScope.CurrentUser);

sDec = utf.GetString(bDec);

}

System.Console .WriteLine("Message : " + sMsg);

System.Console .WriteLine("Encrypted: " + sEnc);

System.Console .WriteLine("Decrypted: " + sDec);

}

}

 

可以通过设置DataProtectionScope.LocalMachine值来实现在机器级别保护该数据。本例中为加密添加 ,这意味着,即使进程执行的上下文环境符合要求(即处在正确的用户或机器下),如果不知道加密使用的熵也是无法解密数据。即可以把熵值看成某种形式的辅助密钥。

 

使用System.Security.Cryptography.ProtectedMemory类

    使用System.Security.Cryptography.ProtectedMemory类可以获得比ProtectedData类更加精确的保护数据的程度。枚举量MemoryProtectionScope提供了以下选项:

SameProcess: 表示只有处在同一进程中的代码才能将进过加密的数据解密。

SameLogon: 表示只有处在同一用户上下文的代码才能将经过加密的数据解密。

CrossProcess: 表示只要在加密完成后操作系统没有重启,那么在任何进程中执行的任何代码都能将经过加密的数据解密。

下面的示例演示了此类的使用。注意:被加密的数据的字节数必须是16的倍数。

using System.Security.Cryptography;

class Program {

static void Main() {

string sMsg = "01234567890123456789012345678901" ;

System.Text.Encoding utf = new System.Text.UTF8Encoding ();

System.Console .WriteLine("Message : " + sMsg);

byte [] bMsg = utf.GetBytes(sMsg);

ProtectedMemory.Protect( bMsg, MemoryProtectionScope.SameProcess );

System.Console .WriteLine("Encrypted: " + utf.GetString(bMsg));

ProtectedMemory.Unprotect( bMsg, MemoryProtectionScope.SameProcess );

System.Console .WriteLine("Decrypted: " + utf.GetString(bMsg));

}

}

 

使用System.Security.SecureString类

    字符串在内存中的存储是不加密的,而且由于垃圾回收机制,字符串这种引用类型在销毁之前有一段不受控制的时间。如果某些恶意的人能够访问到Windows进程的页面,将这些字符串暴露在外面是很危险的。

    为了解决如上问题,.NET Framework提供了SecureString类,其采用DPAPI服务并且允许字符串以加密的形式保存在内存中。

    可以通过一个字符数组(使用过后将其设为零)初始化一个SecureString类的实例,或者通过一个字符一个字符的将其构造出来。Marshal类提供了多个方法以供解密一个保存在SecureString类实例中的加密字符串。

下面示例展示了SecureString类的使用:

 

using System;

using System.Security;

using System.Runtime.InteropServices;

class Program {

static void Main() {

SecureString pwd = new SecureString ();

ConsoleKeyInfo nextKey = Console .ReadKey( true );

while (nextKey.Key != ConsoleKey .Enter) {

pwd.AppendChar( nextKey.KeyChar );

Console .Write( "*" );

nextKey = Console .ReadKey( true );

}

Console .WriteLine();

pwd.MakeReadOnly();

IntPtr bstr = Marshal .SecureStringToBSTR(pwd);

// Get an instance of the Sring class

// only for the example needs.

try { Console .WriteLine( Marshal .PtrToStringAuto(bstr) ); }

finally { Marshal .ZeroFreeBSTR(bstr); }

}

}

 

使用中往往很难避免将一个SecureString在内存中解密,甚至存放在一个字符串。一定要注意需要在特定的内容区域执行此操作,而写使用完后要尽快销毁,以免出现前文提到的安全问题。

 

保护特殊文件中的数据

在应用程序的配置文件中常常包含需要加密的设置。.NET中这通过System.Configuration.Configuration类来实现。下面示例演示了在一个名为TagPassword的配置参数中保存经过加密的MyPassword字符串。

 

using System.Configuration;

class Program {

static void Main() {

SavePwd("MyPassword" );

System.Console .WriteLine(LoadPwd());

}

static void SavePwd(string pwd) {

Configuration cfg = ConfigurationManager.OpenExeConfiguration(

ConfigurationUserLevel.None );

cfg.AppSettings.Settings.Add( "TagPassword" , pwd );

cfg.AppSettings.SectionInformation.ProtectSection(

"RsaProtectedConfigurationProvider" );

cfg.Save();

}

static string LoadPwd() {

Configuration cfg = ConfigurationManager.OpenExeConfiguration(

ConfigurationUserLevel.None );

return cfg.AppSettings.Settings["TagPassword" ].Value;

}

}

如上,在保存操作的时候需要进行处理,以指定我们希望保存一个加密的版本,而在配置文件被读取的时候加密信息会自动被解密。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值