這個題目,我姑且這樣叫吧,照例,我們先來分析一下需求。比如有一個設定密碼的功能,但使用者希望能夠自己選擇密碼的密碼編譯演算法,如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); } }
好了,現在可以運行一個試試。