这个题目,我姑且这样叫吧,照例,我们先来分析一下需求。
比如有一个设置密码的功能,但用户希望能够自己选择密码的加密算法,如MD5、HMAC、SHA1等,然后程序会根据用户所选择的算法对密码进行加密并存入数据库,同时在配置文件中记录下用户的选择。
按照一般的思路,我们可能会做一个分支判断,如
switch( 用户的选择 )
{
case "MD5":
MD5 md5 = MD5.Create();..............
break;
...........
}
呵呵,其实我们不必要这样做,来,先来看看MD5、HMAC、SHA1、SHA384等类有什么共同的特征?
1、都是通过调用Create静态方法来创建一个实例,当然,像MD5这些类都是抽象类,是不能被实例化的。其实,它们都返回一个名为“算法名CryptoServiceProvider”的类实例,如MD5CryptoServiceProvider、SHA1CryptoServiceProvider等,这些类都是对算法计算的具体实现。
2、都是通过调用ComputeHash方法计算哈希值的。
而且,这些类都是位于同一个命名空间下,因些,根据不同的算法进行加密,唯一不同的是类名,也就是说,我们的代码只写一次就可以了,把代码封装在一个方法中,通过在参数中传递类名。
能做到这种功夫的,也就用到反射了,通过反射动态动调用类成员来完成。
/// <summary>
/// 通过算法计算哈希值。
/// </summary>
/// <param name="className">算法类名</param>
/// <param name="tcode">待加密的字符串</param>
/// <returns>加密后的字节数组</returns>
private byte[] ComputeHash(string className, string tcode)
{
byte[] bufRes = null;
// 加载程序集
Assembly asmby = Assembly.Load(@"mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Type myType = asmby.GetType("System.Security.Cryptography." + className, false, true);
if (myType != null)
{
// 得到与Create方法有关的MethodInfo
// GetMethod通过传入的Type数组的维数和类型来
// 判断获取哪个重载。
MethodInfo mdf=myType.GetMethod("Create",new Type[0]);
if (mdf != null)
{
object ob = null;
// 调用方法
ob = mdf.Invoke(null, null);
if (ob != null)
{
// 得到ComputeHash方法的MethodInfo
MethodInfo mfo = myType.GetMethod("ComputeHash", new Type[] { typeof(byte[]) });
if (mfo!=null)
{
// 调用方法
bufRes = (byte[])mfo.Invoke(ob, new object[]{
Encoding.Default.GetBytes(tcode)
});
}
}
}
}
return bufRes;
}
接着需要一个方法来把字节数组转为字符串。
/// <summary>
/// 把字节数组转换为十六进制字符串。
/// </summary>
/// <param name="bf"></param>
/// <returns></returns>
private string ByteToStr(byte[] bf)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in bf)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
然后,我们就可以在其它代码中使用了。
public partial class b : Form
{
public b()
{
InitializeComponent();
comboBox1.Items.Add("HMAC");
comboBox1.Items.Add("MD5");
comboBox1.Items.Add("SHA1");
comboBox1.Items.Add("SHA256");
comboBox1.Items.Add("SHA384");
comboBox1.Items.Add("SHA512");
comboBox1.Items.Add("RIPEMD160");
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox1.SelectedIndex = 0;
}
private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1)
{
return;
}
try
{
byte[] bHash = ComputeHash(comboBox1.SelectedItem.ToString(), txtIn.Text);
if (bHash != null)
{
txtOut.Text = ByteToStr(bHash);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
好了,现在可以运行一个试试。