这个题目,我姑且这样叫吧,照例,我们先来分析一下需求。
比如有一个设置密码的功能,但用户希望能够自己选择密码的加密算法,如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);
- }
- }
好了,现在可以运行一个试试。