我最近注意到System.Security.Cryptography的性能非常慢。
要生成具有100000次迭代的密码哈希,大约需要3秒钟。
使用Microsoft.AspNet.Cryptography进行相同配置的类似代码进行哈希处理所需的时间减少了大约10倍。
我用来测试的代码是
using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNet.Cryptography.KeyDerivation;
namespace CryptoTest
{
internal class Program
{
public static void Main(string[] args)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
Crypto crypto = new Crypto();
Console.WriteLine($"Iterations: {test.HashIterations}, KeySize: {test.KeySize}, SaltSize: {test.DefaultSaltSize}");
var salt = test.GenerateSalt();
string password = "Very C0mplicated-AnD_L0ng.P@ssw0rd!";
var saltedHashOld = crypto.GenerateSaltedHash(password, salt);
watch.Stop();
Console.WriteLine($"Time elapsed: {watch.ElapsedMilliseconds}ms");
Console.WriteLine(saltedHashOld);
watch.Reset();
watch.Start();
var prf = KeyDerivationPrf.HMACSHA1;
var saltedHash = crypto.GenerateSaltedHash(password, salt, prf);
watch.Stop();
Console.WriteLine($"using {prf}");
Console.WriteLine($"Time elapsed: {watch.ElapsedMilliseconds}ms");
Console.WriteLine(saltedHash);
watch.Reset();
watch.Start();
prf = KeyDerivationPrf.HMACSHA256;
saltedHash = crypto.GenerateSaltedHash(password, salt, prf);
watch.Stop();
Console.WriteLine($"using {prf}");
Console.WriteLine($"Time elapsed: {watch.ElapsedMilliseconds}ms");
Console.WriteLine(saltedHash);
watch.Reset();
watch.Start();
prf = KeyDerivationPrf.HMACSHA512;
saltedHash = crypto.GenerateSaltedHash(password, salt, prf);
watch.Stop();
Console.WriteLine($"using {prf}");
Console.WriteLine($"Time elapsed: {watch.ElapsedMilliseconds}ms");
Console.WriteLine(saltedHash);
Console.WriteLine("finished");
}
}
public class Crypto
{
public int HashIterations => 100000;
public int DefaultSaltSize => 96;
public int KeySize => 96;
public KeyDerivationPrf Prf => KeyDerivationPrf.HMACSHA1;
public string GenerateSaltedHash(string password, string salt)
{
return ComputeHash(HashIterations, password, salt, KeySize);
}
public string GenerateSaltedHash(string password, string salt, KeyDerivationPrf prf)
{
return ComputeHash(HashIterations, password, salt, KeySize, prf);
}
public string GenerateSalt()
{
var rand = RandomNumberGenerator.Create();
var ret = new byte[DefaultSaltSize];
rand.GetBytes(ret);
return Convert.ToBase64String(ret);
}
private string ComputeHash(int iterationsNo, string plainText, string salt, int keySize)
{
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
var pbkdf2 = new Rfc2898DeriveBytes(plainText, saltBytes, iterationsNo);
var key = pbkdf2.GetBytes(keySize);
return Convert.ToBase64String(key);
}
private string ComputeHash(int iterationsNo, string plainText, string salt, int keySize, KeyDerivationPrf prf)
{
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
var key = KeyDerivation.Pbkdf2(plainText, saltBytes, prf, iterationsNo, keySize);
return Convert.ToBase64String(key);
}
}
}
如果与Python Django框架登录的默认设置进行比较,它进行了300000次迭代,并且仍用不到一秒钟的时间进行了密码哈希处理,而使用System.Security.Cryptography则需要花费很长时间才能对登录进行身份验证如果迭代次数提高到当前标准。
应该使用哪个?
还是我在这里想念什么?