有很多將使用者密碼儲存成密鑰的方法,比如最簡單的,直接把字串轉換成位元組。
string password = "Mgen!";
var encoding = new UnicodeEncoding(false, false);
byte[] bytes = encoding.GetBytes(password);
Console.WriteLine(encoding.GetString(bytes));
但是,顯然攻擊者可以直接通過位元組得到源文字。
第二種方法就是用散列演算法:
//+ using System.Security.Cryptography;
string password = "Mgen!";
var encoding = new UnicodeEncoding(false, false);
byte[] bytes = encoding.GetBytes(password);
using (var hashAlg = SHA1.Create())
{
var hash = hashAlg.ComputeHash(bytes);
Console.WriteLine(BitConverter.ToString(hash));
}
但是相同的密碼文字的散列結果肯定是一樣的,這樣攻擊者可能建立一個散列映射字典來推出密碼。
最後看看PBKDF。
注意:
.NET中PBKDF1的執行是PasswordDerivedBytes類,但是在.NET 2.0後,PBKDF2的執行:Rfc2898DerivedBytes類的GetBytes方法替代了PasswordDerivedBytes的GetBytes方法。但是PasswordDerivedBytes類本身並沒有被廢棄,因為它不僅提供PBKDF1的執行,其CryptDerivedKey方法調用了Windows加密函數庫CryptoAPI的相應函數。
//+ using System.Security.Cryptography;
//密碼文字
string password = "Mgen!";
//隨機填充密碼salt
byte[] salt = new byte[20];
var rng = RandomNumberGenerator.Create();
rng.GetBytes(salt);
//預設以UTF8(無BOM)得到位元組。嘻哈
var kd = new Rfc2898DeriveBytes(password, salt);
//輸出密鑰1
Console.WriteLine(BitConverter.ToString(kd.GetBytes(10)));
//更換salt
rng.GetBytes(kd.Salt);
//輸出密鑰2
Console.WriteLine(BitConverter.ToString(kd.GetBytes(10)));
輸出:
B2-46-B4-A4-EB-E2-A0-B8-B4-44
07-93-8D-06-9A-BB-AE-21-B8-91
OK,同樣一個密碼,由於salt不同,輸出密鑰也不同!