明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

詳細(xì)說(shuō)明對(duì)密碼執(zhí)行散列與 salt 運(yùn)算方法

[摘要]大家對(duì)密碼執(zhí)行散列和Salt運(yùn)算一定不陌生。兩個(gè)Visual Studio企業(yè)版示例都是用的這個(gè)方法來(lái)加密這個(gè)方法的。結(jié)合示例代碼,我總結(jié)了一個(gè)包含對(duì)密碼進(jìn)行加密,比較等靜態(tài)方法的類! ∈褂谜f(shuō)明:先用HashAndSalt方法對(duì)密碼進(jìn)行加密,然后存儲(chǔ)到數(shù)據(jù)庫(kù)中。 在用戶登錄時(shí)用ComparePa...

  大家對(duì)密碼執(zhí)行散列和Salt運(yùn)算一定不陌生。兩個(gè)Visual Studio企業(yè)版示例都是用的這個(gè)方法來(lái)加密這個(gè)方法的。結(jié)合示例代碼,我總結(jié)了一個(gè)包含對(duì)密碼進(jìn)行加密,比較等靜態(tài)方法的類。
  使用說(shuō)明:先用HashAndSalt方法對(duì)密碼進(jìn)行加密,然后存儲(chǔ)到數(shù)據(jù)庫(kù)中。 在用戶登錄時(shí)用ComparePasswords方法在對(duì)用戶輸入的密碼和用戶注冊(cè)時(shí)存儲(chǔ)在數(shù)據(jù)庫(kù)中的密碼進(jìn)行比較,判斷用戶輸入的密碼是否正確。

 

Credentials.cs

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
 
namespace BookStore.Common
{
       /// <summary>
       /// Credentials 的摘要說(shuō)明。
       /// 原理:
       /// 對(duì)密碼執(zhí)行散列運(yùn)算
       /// 若要避免以明文形式存儲(chǔ)密碼,一種常見(jiàn)的安全做法是對(duì)密碼執(zhí)行散列運(yùn)算。如以下代碼所示,使用 System.Security.Cryptography 命名空間(它實(shí)現(xiàn) 160 位 SHA-1 標(biāo)準(zhǔn))對(duì)密碼進(jìn)行散列運(yùn)算。有關(guān)更多信息,請(qǐng)參見(jiàn) SHA1 成員。
       /// 對(duì)散列執(zhí)行 Salt 運(yùn)算
       /// 雖然對(duì)密碼執(zhí)行散列運(yùn)算的一個(gè)好的開(kāi)端,但若要增加免受潛在攻擊的安全性,則可以對(duì)密碼散列執(zhí)行 Salt 運(yùn)算。Salt 就是在已執(zhí)行散列運(yùn)算的密碼中插入的一個(gè)隨機(jī)數(shù)字。這一策略有助于阻止?jié)撛诘墓粽呃妙A(yù)先計(jì)算的字典攻擊。字典攻擊是攻擊者使用密鑰的所有可能組合來(lái)破解密碼的攻擊。當(dāng)您使用 Salt 值使散列運(yùn)算進(jìn)一步隨機(jī)化后,攻擊者將需要為每個(gè) Salt 值創(chuàng)建一個(gè)字典,這將使攻擊變得非常復(fù)雜且成本極高。
       /// Salt 值隨散列存儲(chǔ)在一起,并且未經(jīng)過(guò)加密。所存儲(chǔ)的 Salt 值可以在隨后用于密碼驗(yàn)證。
       /// </summary>
       public class Credentials
       {
              private static string key = "!48%0d-F=cj>,s&2";  //密鑰(增加密碼復(fù)雜度,好像比較多余)
              private const int saltLength = 4;                         //定義salt值的長(zhǎng)度
 
              /// <summary>
              /// 對(duì)密碼進(jìn)行Hash 和 Salt
              /// </summary>
              /// <param name="Password">用戶輸入的密碼</param>
              /// <returns></returns>
              public static byte[] HashAndSalt(string Password)
              {
                     return CreateDbPassword(HashPassword(Password));
              }
 
              /// <summary>
              /// 對(duì)用戶輸入的密碼加上密鑰key后進(jìn)行SHA1散列
              /// </summary>
              /// <param name="Password">用戶輸入的密碼</param>
              /// <returns>返回 160 位 SHA-1 散列后的的byte[](160位對(duì)應(yīng)20個(gè)字節(jié))</returns>
              private static byte[] HashPassword( string Password )
              {
                     //創(chuàng)建SHA1的對(duì)象實(shí)例sha1
                     SHA1 sha1 = SHA1.Create();
                     //計(jì)算輸入數(shù)據(jù)的哈希值
                     return sha1.ComputeHash( Encoding.Unicode.GetBytes( Password + key ) );
              }
             
              /// <summary>
              /// 比較數(shù)據(jù)庫(kù)中的密碼和所輸入的密碼是否相同
              /// </summary>
              /// <param name="storedPassword">數(shù)據(jù)庫(kù)中的密碼</param>
              /// <param name="Password">用戶輸入的密碼</param>
              /// <returns>true:相等/false:不等</returns>
              public static bool ComparePasswords(byte[] storedPassword, string Password)
              {
                     //首先將用戶輸入的密碼進(jìn)行Hash散列
                     byte[] hashedPassword = HashPassword(Password);
 
                     if (storedPassword == null hashedPassword == null hashedPassword.Length != storedPassword.Length - saltLength)
                     {
                            return false;
                     }
 
                     //獲取數(shù)據(jù)庫(kù)中的密碼的salt 值,數(shù)據(jù)庫(kù)中的密碼的后4個(gè)字節(jié)為salt 值
                     byte[] saltValue = new byte[saltLength];
                     int saltOffset = storedPassword.Length - saltLength;
                     for (int i = 0; i < saltLength; i++){
                            saltValue[i] = storedPassword[saltOffset + i];
                     }
                    
                     //用戶輸入的密碼用戶輸入的密碼加上salt 值,進(jìn)行salt
                     byte[] saltedPassword = CreateSaltedPassword(saltValue, hashedPassword);
             
                     //比較數(shù)據(jù)庫(kù)中的密碼和經(jīng)過(guò)salt的用戶輸入密碼是否相等
                     return CompareByteArray(storedPassword, saltedPassword);
              }
 
              /// <summary>
              /// 比較兩個(gè)ByteArray,看是否相等
              /// </summary>
              /// <param name="array1"></param>
              /// <param name="array2"></param>
              /// <returns>true:相等/false:不等</returns>
              private static bool CompareByteArray(byte[] array1, byte[] array2)
              {
                     if (array1.Length != array2.Length)
                     {
                            return false;
                     }
                     for (int i = 0; i < array1.Length; i++)
                     {
                            if (array1[i] != array2[i])
                            {
                                   return false;
                            }
                     }
                     return true;
              }
 
              /// <summary>
              /// 對(duì)要存儲(chǔ)的密碼進(jìn)行salt運(yùn)算
              /// </summary>
              /// <param name="unsaltedPassword">沒(méi)有進(jìn)行過(guò)salt運(yùn)算的hash散列密碼</param>
              /// <returns>經(jīng)過(guò)salt的密碼(經(jīng)過(guò)salt的密碼長(zhǎng)度為:20+4=24,存儲(chǔ)密碼的字段為Binary(24))</returns>
              private static byte[] CreateDbPassword(byte[] unsaltedPassword)
              {
                     //獲得 salt 值
                     byte[] saltValue = new byte[saltLength];
                     RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
                     rng.GetBytes(saltValue);
                    
                     return CreateSaltedPassword(saltValue, unsaltedPassword);
              }
             
              /// <summary>
              /// 創(chuàng)建一個(gè)經(jīng)過(guò)salt的密碼
              /// </summary>
              /// <param name="saltValue">salt 值</param>
              /// <param name="unsaltedPassword">沒(méi)有進(jìn)行過(guò)salt運(yùn)算的hash散列密碼</param>
              /// <returns>經(jīng)過(guò)salt的密碼</returns>
              private static byte[] CreateSaltedPassword(byte[] saltValue, byte[] unsaltedPassword)
              {
                     //將salt值數(shù)組添加到hash散列數(shù)組后拼接成rawSalted數(shù)組中
                     byte[] rawSalted  = new byte[unsaltedPassword.Length + saltValue.Length];
                     unsaltedPassword.CopyTo(rawSalted,0);
                     saltValue.CopyTo(rawSalted,unsaltedPassword.Length);
                    
                     //將合并后的rawSalted數(shù)組再進(jìn)行SHA1散列的到saltedPassword數(shù)組(長(zhǎng)度為20字節(jié))
                     SHA1 sha1 = SHA1.Create();
                     byte[] saltedPassword = sha1.ComputeHash(rawSalted);
 
                     //將salt值數(shù)組在添加到saltedPassword數(shù)組后拼接成dbPassword數(shù)組(長(zhǎng)度為24字節(jié))
                     byte[] dbPassword  = new byte[saltedPassword.Length + saltValue.Length];
                     saltedPassword.CopyTo(dbPassword,0);
                     saltValue.CopyTo(dbPassword,saltedPassword.Length);
 
                     return dbPassword;
              }
 
       }
}