MD5加密在因为具有加密的不可逆性,所以在密码加密,以及文件验证有很大的应用.在密码加密方面,如果在数据库中保存明文密码,将是非常危险的.如果密码是MD5加密过得,就会安全的多
但是用MD5加密过的明文密码,因为是不能逆向还原出明文的.好处是:DBA,开发人员最多只知道你的MD5加密过的密码,而不知道正真的密码,坏处是一旦你自己把密码忘了,那就只能通过邮件等方式更换密码了.
好了先上一段MD5的核心类:
using System; using System.Text; using System.Security.Cryptography; using System.IO; using System.Xml; namespace MD5Lib { /// <summary> /// MD5加密及验证 /// </summary> public sealed class MD5Helper { /// <summary> /// 获得64位的MD5加密 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string GetMD5_64(string input) { MD5 md5 = MD5.Create(); // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(input)); return Convert.ToBase64String(s); } /// <summary> /// 获得32位的MD5加密 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string GetMD5_32(string input) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] data = md5.ComputeHash(System.Text.Encoding.Default.GetBytes(input)); StringBuilder sb = new StringBuilder(); for (int i = 0; i < data.Length; i++) { sb.Append(data[i].ToString("x2")); } return sb.ToString(); } /// <summary> /// 获得16位的MD5加密 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string GetMD5_16(string input) { return GetMD5_32(input).Substring(8, 16); } /// <summary> /// 获得8位的MD5加密 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string GetMD5_8(string input) { return GetMD5_32(input).Substring(8, 8); } /// <summary> /// 获得4位的MD5加密 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string GetMD5_4(string input) { return GetMD5_32(input).Substring(8, 4); } public static string MD5EncryptHash(String input) { MD5 md5 = new MD5CryptoServiceProvider(); //the GetBytes method returns byte array equavalent of a string byte[] res = md5.ComputeHash(Encoding.Default.GetBytes(input), 0, input.Length); char[] temp = new char[res.Length]; //copy to a char array which can be passed to a String constructor Array.Copy(res, temp, res.Length); //return the result as a string return new String(temp); } //对文件添加MD5标签及验证 #region MD5签名验证 /// <summary> /// 对给定文件路径的文件加上标签(如果文件已经更改,则更新配置的MD5值) /// </summary> /// <param name="path">要加密的文件的路径</param> /// <param name="md5_conf_path">加密的密文保存文件地址(自动生成配置)</param> /// <returns>标签的值</returns> public static bool AddMD5(string path , string md5_conf_path) { bool IsNeed = true; if (CheckMD5(path,md5_conf_path)) //已进行MD5处理 IsNeed = false; try { if (IsNeed) { FileStream fsread = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] md5File = new byte[fsread.Length]; fsread.Read(md5File, 0, (int)fsread.Length); // 将文件流读取到Buffer中 fsread.Close(); string result = MD5Buffer(md5File, 0, md5File.Length); // 对Buffer中的字节内容算MD5 Boolean is_exist = false; XmlDocument doc = new XmlDocument(); doc.Load(md5_conf_path); XmlNodeList node_path = doc.SelectNodes("data/path"); foreach (XmlNode item in node_path) { if (item.Attributes["file"].InnerText == path) { is_exist = true; item.Attributes["md5"].InnerText = result;//修改file的验证码 doc.Save(md5_conf_path);//保存到配置 break; } } if (!is_exist) { //加入MD5验证配置 XmlElement root = doc.DocumentElement;//获取根节点 XmlElement tagOuter = doc.CreateElement("path"); tagOuter.SetAttribute("file", path); tagOuter.SetAttribute("md5", result); root.AppendChild(tagOuter); doc.Save(md5_conf_path);//保存到配置 } } } catch { return false; } return true; } /// <summary> /// 对给定路径的文件进行验证 /// </summary> /// <param name="path">md5加密的文件</param> /// <param name="md5_conf_path">加密的密文保存文件地址</param> /// <returns>是否加了标签或是否标签值与内容值一致</returns> public static bool CheckMD5(string path, string md5_conf_path) { try { FileStream get_file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); byte[] md5File = new byte[get_file.Length]; // 读入文件 get_file.Read(md5File, 0, (int)get_file.Length); get_file.Close(); Boolean is_exist = false; XmlDocument doc = new XmlDocument(); doc.Load(md5_conf_path); XmlNodeList node_path = doc.SelectNodes("data/path"); string md5 = string.Empty; foreach (XmlNode item in node_path) { if (item.Attributes["file"].InnerText == path) { is_exist = true; md5 = item.Attributes["md5"].InnerText; break; } } if (!is_exist) return false;//没有配置返回false string result = MD5Buffer(md5File, 0, md5File.Length);//计算path的MD5值,用于与配置文件里面的MD5进行对比 return result == md5; } catch { return false; } } /// <summary> /// 是否存在文件的MD5密码的配置 /// </summary> /// <param name="path">文件路径</param> /// <param name="md5_conf_path">配置路径</param> /// <returns></returns> public static Boolean Is_Exist(string path, string md5_conf_path) { XmlDocument doc = new XmlDocument(); doc.Load(md5_conf_path); XmlNodeList node_path = doc.SelectNodes("data/path"); foreach (XmlNode item in node_path) { if (item.Attributes["file"].InnerText == path) { return true; } } return false; } /// <summary> /// 计算文件的MD5值 /// </summary> /// <param name="MD5File">MD5签名文件字符数组</param> /// <param name="index">计算起始位置</param> /// <param name="count">计算终止位置</param> /// <returns>计算结果</returns> private static string MD5Buffer(byte[] MD5File, int index, int count) { System.Security.Cryptography.MD5CryptoServiceProvider get_md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] hash_byte = get_md5.ComputeHash(MD5File, index, count); string result = System.BitConverter.ToString(hash_byte); result = result.Replace("-", ""); return result; } #endregion } }
一,先测试Password(密码)加密:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MD5Lib; namespace MD5Demo { class Program { static void Main(string[] args) { string my_password = "Aonaufly-%~ss"; Console.WriteLine("我的密码 : {0} ", my_password); //使用32MD5加密 string md5_32_miwen = MD5Helper.GetMD5_32(my_password); Console.WriteLine("对密码 : {0} 加密后 MD5密文 : {1}", my_password , md5_32_miwen); if (md5_32_miwen == MD5Helper.GetMD5_64(my_password)) { Console.WriteLine("密码验证通过"); } else { Console.WriteLine("密码验证未通过 -- 32为加密和64位加密的密文是不一样的"); Console.WriteLine("==========================================="); if (md5_32_miwen == MD5Helper.GetMD5_32(my_password)) { Console.WriteLine("密码验证通过"); } } Console.Read(); } } }
结果:
从测试代码看出 , 我们用32位MD5加密过的密文和用64位MD5加密过的密文是完全不一样的,这点要注意.
比如 : 你存的用户的密码是用32位MD5加密过的,而对比密码却用64位的,那就很尴尬了.
二,关于文件验证
①,测试准备
我们先在Debug目录放2个文件:
关于Aonaufly.xml(程序游戏当中进行使用) , 如下:
<?xml version="1.0" encoding="utf-8" ?> <data> <img name="offline_Settlement1" res="uiimg/res/img/offline_other/js_taitou_1.png"/> <img name="offline_Settlement2" res="uiimg/res/img/offline_other/js_taitou_2.png"/> <img name="offline_Settlement3" res="uiimg/res/img/offline_other/jjcg_ditu.png"/> <img name="offline_Settlement4" res="uiimg/res/img/offline_other/tanchuang.png"/> <img name="offline_Settlement5" res="uiimg/res/img/offline_other/lose.png"/> <img name="offline_Settlement6" res="uiimg/res/img/offline_other/win.png"/> </data>
关于checkmd5.xml(用于验证程序游戏中的配置是否安全)
<?xml version="1.0" encoding="utf-8"?> <data> </data>
我们来看测试代码 no.1 , 如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MD5Lib; namespace MD5Demo { class Program { static void Main(string[] args) { Console.WriteLine("MD5签名验证======================================"); string txt_path = @"Aonaufly.xml";//测试文件(为此文件生成MD5码) string txt_md5_conf = @"checkmd5.xml";//所有需要生成MD5码的文件的MD5码保存在此文件中 //MD5Helper.AddMD5(txt_path, txt_md5_conf); //对给定文件路径的文件加上标签 - 成功 if (MD5Helper.CheckMD5(txt_path, txt_md5_conf)) { Console.WriteLine("{0} 没有被篡改,可以放心使用" , txt_path); } else { if (MD5Helper.Is_Exist(txt_path, txt_md5_conf)) { Console.WriteLine("{0} 已经被篡改,请小心使用", txt_path); } else { Console.WriteLine("{0}中不存在文件{1}的MD5的配置信息,请重新生成!!!", txt_md5_conf, txt_path); } } Console.Read(); } } }
结果:
确实是 , checkmd5.xml没有关于Aonaufly.xml的记录,如下图
好,我们记录一条Aoanufly.xml的MD5信息,代码如下: no.2
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MD5Lib; namespace MD5Demo { class Program { static void Main(string[] args) { Console.WriteLine("MD5签名验证======================================"); string txt_path = @"Aonaufly.xml";//测试文件(为此文件生成MD5码) string txt_md5_conf = @"checkmd5.xml";//所有需要生成MD5码的文件的MD5码保存在此文件中 MD5Helper.AddMD5(txt_path, txt_md5_conf); Console.Read(); } } }
MD5Helper.AddMD5(txt_path, txt_md5_conf);
将txt_path文件的md5码记录到txt_md5_conf文件中,注意,如txt_md5_conf中无关于txt_path文件的md5的记录则做添加操作,如果有(①,MD5没有改变则不作任何错误,②,MD5已变更改其记录的MD5值)
注意MD5会因为txt_path文件的改变而改变
结果如下:
注意file为Aonaufly.xml的路径,是path
我们不改变Aonaufly.xml的内容,做测试 no.3,如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MD5Lib; namespace MD5Demo { class Program { static void Main(string[] args) { Console.WriteLine("MD5签名验证======================================"); string txt_path = @"Aonaufly.xml";//测试文件(为此文件生成MD5码) string txt_md5_conf = @"checkmd5.xml";//所有需要生成MD5码的文件的MD5码保存在此文件中 //MD5Helper.AddMD5(txt_path, txt_md5_conf); //对给定文件路径的文件加上标签 - 成功 if (MD5Helper.CheckMD5(txt_path, txt_md5_conf)) { Console.WriteLine("{0} 没有被篡改,可以放心使用" , txt_path); } else { if (MD5Helper.Is_Exist(txt_path, txt_md5_conf)) { Console.WriteLine("{0} 已经被篡改,请小心使用", txt_path); } else { Console.WriteLine("{0}中不存在文件{1}的MD5的配置信息,请重新生成!!!", txt_md5_conf, txt_path); } } Console.Read(); } } }
得到结果如下:
而当我们修改了一个Aonaufly.xml , 如下:
我们还是以no.3(如上)代码测试 . 结果如下:
在文件签名的应用中,在程序每个正式的版本中打一个MD5码,监听配置文件的篡改,保证安全.
转载于:https://blog.51cto.com/aonaufly/1952775