微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇
在上一篇文章中,我介绍了企业库Cryptographer模块的一些重要类,同时介绍了企业库Cryptographer模块为我们提供的扩展接口,今天我就要根据这些接口来进行扩展开发,实现2个加密解密方法(离散加密和对称性加密),分别实现自接口IHashProvider和接口ISymmetricCryptoProvider。
using System; using System.Collections.Generic; //构造函数中接受参数的类型NameValueCollection所在命名空间 using System.Collections.Specialized; using System.Linq; using System.Text; using System.Security.Cryptography; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;//用于企业库配置工具绑定 using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography; using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.Configuration; namespace EntLibStudy.Helper { [ConfigurationElementType(typeof(CustomHashProviderData))] public class CustomHashCryptography : IHashProvider { /// <summary> /// 构造函数,此处不可省略,否则会导致异常 /// </summary> /// <param name="attributes">配置文件中所配置的参数</param> public CustomHashCryptography(NameValueCollection attributes) { } /// <summary> /// 比较数据和已加密数据是否相等 /// </summary> /// <param name="plaintext">未加密数据</param> /// <param name="hashedtext">已加密数据</param> /// <returns>是否相等</returns> public bool CompareHash(byte[] plaintext, byte[] hashedtext) { var tmpHashText = CreateHash(plaintext); if (tmpHashText == null || hashedtext == null) return false; if (tmpHashText.Length != hashedtext.Length) return false; for (int i = 0; i < tmpHashText.Length; i++) { if (tmpHashText[i] != hashedtext[i]) return false; } return true; } /// <summary> /// 创建加密 /// </summary> /// <param name="plaintext">待加密数据</param> /// <returns>加密后数据</returns> public byte[] CreateHash(byte[] plaintext) { MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); return md5.ComputeHash(plaintext); } } }
这段代码主要就是实现一个离散加密,不过还是有几点需要注意:
1、在实现接口IHashProvider的基础上,为了能让这个自定义加密可以在企业库的配置工具里调用到需要为类加上一个特性:[ConfigurationElementType(typeof(CustomHashProviderData))],这个特性所在的命名空间为:using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;。
2、这个自定义加密必须包含一个构造函数,其参数的类型是NameValueCollection,这个参数是从配置文件中获取指定的配置属性,见下图:
注意:这个NameValueCollection类型,需要引用命名空间:using System.Collections.Specialized;
如果没有这个构造函数,将会引发异常:
Type does not provide a constructor taking a single parameter type of NameValueCollection
3、方法CompareHash、CreateHash,接收和返回的类型都是字节数组。
接下来看下对称加密CustomSymmetricCryptography ,具体代码如下:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;
using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.Configuration;
namespace EntLibStudy.Helper
{
[ConfigurationElementType(typeof(CustomSymmetricCryptoProviderData))]
public class CustomSymmetricCryptography : ISymmetricCryptoProvider
{
private string encryptKey="";
public CustomSymmetricCryptography(NameValueCollection attributes)
{
//从配置文件中获取key,如不存在则指定默认key
encryptKey = String.IsNullOrEmpty(attributes["key"]) ? "kyo-yo" : attributes["key"];
}
//默认密钥向量
private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
/// <summary>
/// 加密
/// </summary>
/// <param name="ciphertext">待加密数据</param>
/// <returns>加密后数据</returns>
public byte[] Decrypt(byte[] ciphertext)
{
if (encryptKey.Length > 8)
{
encryptKey = encryptKey.Substring(0, 7);
}
encryptKey = encryptKey.PadRight(8, ' ');
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey);
byte[] rgbIV = Keys;
byte[] inputByteArray = ciphertext;
DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return mStream.ToArray();
}
/// <summary>
/// 解密
/// </summary>
/// <param name="plaintext">加密数据</param>
/// <returns>解密后数据</returns>
public byte[] Encrypt(byte[] plaintext)
{
if (encryptKey.Length > 8)
{
encryptKey = encryptKey.Substring(0, 7);
}
encryptKey = encryptKey.PadRight(8, ' ');
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
byte[] rgbIV = Keys;
byte[] inputByteArray = plaintext;
DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return mStream.ToArray();
}
}
}
这个对称性加密的注意点基本和离散加密一样,但是这边的对称加密我引入了一个加密key,这个key是从配置文件中获取的。
第三点:在项目中应用自定义接口
在上面已经扩展好了2个加密方式,现在就要在实际的项目中运用这2个加密方式,首先打开企业库的配置工具,添加Cryptographer模块,然后在Hash Providers和ISymmetric Cryptograhpy Providers下分别添加刚才定义好的2个加密方式。
注意:添加的自定义加密方式必须放在项目的根目录下,如果放在项目下的文件夹下,如:Helper\Extension下,从企业库的配置文件中将无法找到自定义的加密方式,见下图:
在添加完配置后就可以在web.config看到以下配置信息:
<securityCryptographyConfiguration> <hashProviders> <add type="EntLibStudy.Helper.CustomHashCryptography, EntLibStudy.Helper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="CustomHashCryptography" /> </hashProviders> <symmetricCryptoProviders> <add key="kyo-yo" type="EntLibStudy.Helper.CustomSymmetricCryptography, EntLibStudy.Helper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="CustomSymmetricCryptography" /> </symmetricCryptoProviders> </securityCryptographyConfiguration>
/// <summary> /// 根据配置进行加密 /// </summary> /// <param name="instance">配置实例名</param> /// <param name="encryptString">待加密字符串</param> /// <returns>加密后字符串</returns> public static string Encode(string instance, string encryptString) { return Cryptographer.EncryptSymmetric(instance, encryptString); } /// <summary> /// 根据配置进行解密 /// </summary> /// <param name="instance">配置实例名</param> /// <param name="decryptString">待解密字符串</param> /// <returns>解密后字符串</returns> public static string Decode(string instance, string decryptString) { return Cryptographer.DecryptSymmetric(instance, decryptString); } /// <summary> /// 根据配置进行离散加密 /// </summary> /// <param name="instance">配置实例名</param> /// <param name="plaintString">待加密字符串</param> /// <returns>解密后字符串</returns> public static string CreateHash(string instance, string plaintString) { return Cryptographer.CreateHash(instance, plaintString); } /// <summary> /// 比较离散值是否相等 /// </summary> /// <param name="instance">配置实例名</param> /// <param name="plaintString">未加密字符串</param> /// <param name="hashedString">已加密字符串</param> /// <returns>是否相等</returns> public static bool CompareHash(string instance,string plaintString, string hashedString) { return Cryptographer.CompareHash(instance, plaintString, hashedString); }
接下来就是主要的项目应用了,在以前的代码中,例如学员的密码我是以明文的形式保存进数据库的,这显示是很不安全的,现在我就要替换这块代码,通过调用Utils.CreateHash方法加密录入的密码:
/// <summary> /// 获取已验证的学员对象 /// </summary> /// <param name="student">学员对象</param> /// <returns>是否验证成功</returns> private bool GetValidatedStudent(ref Model.Student student) { if (student == null) { student = new Model.Student(); } student.ClassId = Convert.ToInt32(ddlClass.SelectedValue); student.Sid = txtSid.Text.Trim(); student.Password = Helper.Utils.CreateHash("CustomHashCryptography", txtPwd.Text.Trim()); student.Name = txtName.Text.Trim(); student.Sex = Convert.ToInt32(rblSex.SelectedValue); student.Birthday = DateTime.Parse(txtBirthday.Text.Trim()); return student.IsValid(); }
源代码下载:点我下载
注意:
1、MSSQL数据库在DataBase目录下(需要自行附加数据库),SQLite数据库在Web目录的App_Data下,由于考虑到项目的大小,所以每个项目的BIN目录都已经删除,如出现无法生成项目请自行添加相关企业库的DLL。
2、由于微软企业库5.0 学习之路这个系列我是准备以一个小型项目的形式介绍企业库的各模块,所以源代码会根据系列文章的更新而更新,所以源代码不能保证与文章中所贴代码相同。
3、项目开发环境为:VS2010+SQL2005。
4、管理员帐户:admin
密码:admin