1. 程式人生 > >使用MD5對使用者密碼加密與解密

使用MD5對使用者密碼加密與解密

MD5簡介: 

         MD5的全稱是Message-Digest Algorithm 5,在90年代初由MIT的電腦科學實驗室和RSA Data Security Inc發明,經MD2、MD3和MD4發展而來。MD5將任意長度的“位元組串”變換成一個128bit的大整數,並且它是一個不可逆的字串變換演算法。換句話說就是,即使你看到源程式和演算法描述,也無法將一個MD5的值變換回原始的字串,從數學原理上說,是因為原始的字串有無窮多個,這有點象不存在反函式的數學函式。 

   C#中常涉及到對使用者密碼的加密於解密的演算法,其中使用MD5加密是最常見的的實現方式。

一.使用16位、32位、64位MD5方法對使用者名稱加密

1)16位的MD5加密

/// <summary>
/// 16位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt16(string password)
{
    var md5 = new MD5CryptoServiceProvider();
    string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8);
    t2 = t2.Replace("-", "");
    return t2;
}
2)32位的MD5加密
/// <summary>
/// 32位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt32(string password)
{
    string cl = password;
    string pwd = "";
    MD5 md5 = MD5.Create(); //例項化一個md5對像
    // 加密後是一個位元組型別的陣列,這裡要注意編碼UTF8/Unicode等的選擇 
    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
    // 通過使用迴圈,將位元組型別的陣列轉換為字串,此字串是常規字元格式化所得
    for (int i = 0; i < s.Length; i++)
    {
        // 將得到的字串使用十六進位制型別格式。格式後的字元是小寫的字母,如果使用大寫(X)則格式後的字元是大寫字元 
        pwd = pwd + s[i].ToString("X");
    }
    return pwd;
}

3)64位的MD5加密
public static string MD5Encrypt64(string password)
{
    string cl = password;
    //string pwd = "";
    MD5 md5 = MD5.Create(); //例項化一個md5對像
    // 加密後是一個位元組型別的陣列,這裡要注意編碼UTF8/Unicode等的選擇 
    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
    return Convert.ToBase64String(s);
}

4)使用MD5為使用者密碼加密
/// <summary>
/// 加密使用者密碼
/// </summary>
/// <param name="password">密碼</param>
/// <param name="codeLength">加密位數</param>
/// <returns>加密密碼</returns>
public static string md5(string password, int codeLength)
{
    if (!string.IsNullOrEmpty(password))
    {
        // 16位MD5加密(取32位加密的9~25字元)  
        if (codeLength == 16)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, "MD5").ToLower().Substring(8, 16);
        }

        // 32位加密
        if (codeLength == 32)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, "MD5").ToLower();
        }
    }
    return string.Empty;
}

  由於MD5是不可逆的,所以加密之後就無法解密,取使用者名稱和密碼時候,需要再加密一邊使用者輸入的資料與資料庫中已加密的資料進行比對。如果比對結果一致,則可以判定登陸成功!程式碼如下所示:
/// <summary>
/// 登陸
/// </summary>
public Model.UserInfo UserLogOn(string USERID, string pwd, out string statusCode)
{
    //假設已經通過使用者ID獲取到UserInfo的Model物件
    Model.UserInfo model = GetModel(USERID);
    if (model != null)
    {
        if (model.PASSWORD == MD5Encrypt64(pwd))
        {
            statusCode = "登陸成功";
        }
        else {
            statusCode = “密碼錯誤”;
        }
    }
    else
    {
        statusCode = "使用者不存在!";
        model = null;
    }   
    return model;
}
5)通過DESCryptoServiceProvider物件對字串進行加密解密
/// <summary>
/// DES資料加密
/// </summary>
/// <param name="targetValue">目標值</param>
/// <param name="key">金鑰</param>
/// <returns>加密值</returns>
public static string Encrypt(string targetValue, string key)
{
    if (string.IsNullOrEmpty(targetValue))
    {
        return string.Empty;
    }

    var returnValue = new StringBuilder();
    var des = new DESCryptoServiceProvider();
    byte[] inputByteArray = Encoding.Default.GetBytes(targetValue);
    // 通過兩次雜湊密碼設定對稱演算法的初始化向量   
    des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
                                                Substring(0, 8), "sha1").Substring(0, 8));
    // 通過兩次雜湊密碼設定演算法的機密金鑰   
    des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
                                                .Substring(0, 8), "md5").Substring(0, 8));
    var ms = new MemoryStream();
    var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    foreach (byte b in ms.ToArray())
    {
        returnValue.AppendFormat("{0:X2}", b);
    }
    return returnValue.ToString();
}

此種演算法可以通過加密金鑰進行解密,解密方法如下:
/// <summary>
/// DES資料解密
/// </summary>
/// <param name="targetValue"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string targetValue, string key)
{
    if (string.IsNullOrEmpty(targetValue))
    {
        return string.Empty;
    }
    // 定義DES加密物件
    var des = new DESCryptoServiceProvider();
    int len = targetValue.Length / 2;
    var inputByteArray = new byte[len];
    int x, i;
    for (x = 0; x < len; x++)
    {
        i = Convert.ToInt32(targetValue.Substring(x * 2, 2), 16);
        inputByteArray[x] = (byte)i;
    }
    // 通過兩次雜湊密碼設定對稱演算法的初始化向量   
    des.Key = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5").
                                                Substring(0, 8), "sha1").Substring(0, 8));
    // 通過兩次雜湊密碼設定演算法的機密金鑰   
    des.IV = Encoding.ASCII.GetBytes(FormsAuthentication.HashPasswordForStoringInConfigFile
                                            (FormsAuthentication.HashPasswordForStoringInConfigFile(key, "md5")
                                                .Substring(0, 8), "md5").Substring(0, 8));
    // 定義記憶體流
    var ms = new MemoryStream();
    // 定義加密流
    var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    return Encoding.Default.GetString(ms.ToArray());
}


以下是通過Unity實現的一個簡單例項:
using UnityEngine;
using System;
using UnityEditor;
using System.Text;
using System.Collections;
using System.Security.Cryptography;

public class MD5Algorithm {

	static string password = "12345678";

	/// <summary>
	/// 16位MD5加密
	/// </summary>
	/// <param name="password"></param>
	/// <returns></returns>
	public static string MD5Encrypt16(string password)
	{
		var md5 = new MD5CryptoServiceProvider();
		string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)));
		t2 = t2.Replace("-", "");
		return t2;
	}

	/// <summary>
	/// 32位MD5加密
	/// </summary>
	/// <param name="password"></param>
	/// <returns></returns>
	public static string MD5Encrypt32(string password)
	{
		string cl = password;
		string pwd = "";
		MD5 md5 = MD5.Create(); //例項化一個md5對像
		// 加密後是一個位元組型別的陣列,這裡要注意編碼UTF8/Unicode等的選擇 
		byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
		// 通過使用迴圈,將位元組型別的陣列轉換為字串,此字串是常規字元格式化所得
		for (int i = 0; i < s.Length; i++)
		{
			// 將得到的字串使用十六進位制型別格式。格式後的字元是小寫的字母,如果使用大寫(X)則格式後的字元是大寫字元 
			pwd = pwd + s[i].ToString("X");
		}
		return pwd;
	}


	//64位的MD5加密
	public static string MD5Encrypt64(string password)
	{
		string cl = password;
		//string pwd = "";
		MD5 md5 = MD5.Create(); //例項化一個md5對像
		// 加密後是一個位元組型別的陣列,這裡要注意編碼UTF8/Unicode等的選擇 
		byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
		return Convert.ToBase64String(s);
	}
		

	[MenuItem("MD5/16位MD5加密")]
	static void MD5of16Bytes()
	{
		string pw = MD5Encrypt16(password);
		Debug.Log("MD5-16Bytes : " + pw);
	}

	[MenuItem("MD5/32位MD5加密")]
	static void MD5of32Bytes()
	{
		string pw = MD5Encrypt32(password);
		Debug.Log("MD5-32Bytes : " + pw);
	}

	[MenuItem("MD5/64位MD5加密")]
	static void MD5of64Bytes()
	{
		string pw = MD5Encrypt64(password);
		Debug.Log("MD5-64Bytes : " + pw);
	}
		
}




執行結果如下: