.NET 提供了丰富的 CryptoAPI 以满足很大范围内的加密任务。比如,创建不同类型的散列字符串(MD5、SHA1 等)以及实现最重要的对称和非对称加密算法。
.NET Framework 还提供了单独的功能来保护本地计算机上或以每个用户为基础的秘密数据,这些工作都是通过 WindowsDPAPI(Data Protection API,数据保护 API)的完全被托管的封装类进行的。
1. 加密数据:机密性问题
你知道,可以使用散列码来保护密码。使用散列时,存储的是原数据的数字指纹,而不是数据本身。结果,你没有办法倒转散列过程来获得原来的数据。你所能做的就是对一个新的数据进行散列并对其进行比较。
散列是一个不可逆的过程,用来保护密码是最安全的方案。但当你想保护敏感数据并在随后对其解密时,这个方案就没用了。比如,存储用户信用卡信息时,你的程序需要读取到信用卡的相关信息。
使用纯文本的方式存储敏感数据并不安全。有时你会认为,既然数据存储在一个安全的服务器端的存储位置,就没有必要做额外的工作来加密它们。但是专家知道事实并非如此。不使用加密,黑客可能仅需花费几分钟甚至几秒钟就可以获得每个用户的密码或者信用卡帐号。不好的管理策略、脆弱的管理员口令或者服务器上其他可利用的软件都会导致安全方面的隐患和漏洞,甚至硬件维护也会导致问题。
2. .NET 加密命名空间
在 System.Security.Cryptography 命名空间中,你可以找到程序中用来加密和解密的类。此外,你还能找到所有创建不同类型的散列的基类。如果引用额外的 System.Security.dll 程序集,甚至可以访问到更多高级的安全功能,比如一个用来修改 Windiws ACL 的 API(System.Security.AccessControl 命名空间)、DPAPI 和用来创建密钥散列信息验证代码的类(HMAC)。
System.Security.Cryptography 命名空间中与安全相关的类的分类
| 加密算法 | 包含最重要的散列和加密算法以及用来创建数字签名的类 |
| 辅助类 | 这些辅助类可以创建真实加密的随机数,它们和底层的 Windows 加密系统(CryptoAPI)交互 |
| X509 证书 | 在 System.Security.Cryptography.X509Certificates 命名空间中,包含所有使用 X509 证书必需的类和用于访问 Windows 证书存储的类 |
| XML 签名和加密 | 在 System.Security.Cryptography.Xml 命名空间中包含对 XML 签名和加密标准的类。它们按 W3C 发布的标准对 XML 文档进行加密和签名 |
| CMS/PKCS#7 | 这个框架具备直接创建 CMS/PKCS 包装的信息的托管支持,而无需使用非托管调用(CMS,Crtptographic Message Syntax)(PKCS,Public-Key Crtptography Standard) |
在 Web 世界中,X509 证书扮演着非常重要的角色。它们建立 SSL 通信并执行证书验证以保证 Web 服务器和客户端之间的通信安全。X509 证书是一个二进制标准,用来将非对称加密算法的密钥和一个已发布了证书的特殊组织(证书授权)的签名封装在一起。
如果是简单的 SSL 连接,你不需要访问证书存储。但如果你想在另一台机器上的代码中调用 Web 服务或者 Web 程序,你需要使用一个 X509 证书进行验证。你的程序需要从 Windows 证书存储中读取证书,然后在实际发送请求之前将这个证书添加到 Web 请求(或 Web 服务代理)中。
System.Security.Cryptography.X509Certificates 命名空间包括如下几个可用的类:
- X509Certificate 和 X509Certificate2:这些类封装 X509 证书。让你能够从各种存储(如文件系统)中加载证书并访问证书的属性。前者是一个版本的 .NET Framework 就开始提供的原始类;后者是对前者的扩展
- X509Store:让你能访问 Windows 证书存储。对于每个用户来说,Windows 都创建一个这样的存储(通过 StoreLocation.CurrentUser 访问);而对于机器,只创建一个存储(通过 StoreLocation.LocalMachine 访问)。用户存储只对创建的用户可访问,而机器存储保存的证书则对机器上所有客户可用
- X509CertificateCollection:这是一个表示 X509Certificate 和 X509Certificate2 实例(它们表示单个证书)的集合的简单类。让你能够取到一组证书或者根据一个唯一(比如证书的主题键、主题名或散列)的标识取得一个证书
例如,象下面这样从存储中读取证书信息并将其赋给一个 Web 请求:
// Read the certificate from the store
// X509Store: 表示 X.509 存储区,该存储区是保留和管理证书的物理存储区
// StoreName: 指定要打开的 X.509 证书存储区的名称
// StoreLocation: 指定 X.509 证书存储区的位置
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
try
{
// Try to find the certificate based on this common name
X509Certificate2Collection results = store.Certificates.Find(
X509FindType.FindBySubjectDistinguishedName, "CN=Mario, CN=Szpuszta", false);
if (results.Count == 0)
{
throw new Exception("Unable to find certicate!");
}
else
{
certificate = results[0];
}
}
finally
{
store.Close();
}