We are currently using HMACSHA512 in .net, with a 128Char (64byte) validation key The salt is 64 char randomly generated string. We allocated 2048 length on the database for the hashed base64 string result. It will be a public facing website. Is this approach reasonable or should it be changed to another approach such as Rfc2898DeriveBytes?
public string HashEncode(string password, string salt, string validationKey) {
byte[] hashKey = BosUtilites.HexStringToByteArray(validationKey);
var sha512 = new HMACSHA512(hashKey);
var hashInput = BosUtilites.StringToByteArray(password + salt);
byte[] hash = sha512.ComputeHash(hashInput);
return Convert.ToBase64String(hash);
}
public string GenerateSimpleSalt(int Size = 64) {
var alphaSet = new char[64]; // use 62 for strict alpha... that random generator for alphas only
//nicer results with set length * int i = 256. But still produces excellent random results.
//alphaset plus 2. Reduce to 62 if alpha requried
alphaSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890#=".ToCharArray();
var tempSB = GenerateRandomString(Size, alphaSet);
return tempSB.ToString();
}
public StringBuilder GenerateRandomString(int Size, char[] alphaSet) {
using (var crypto = new RNGCryptoServiceProvider()) {
var bytes = new byte[Size];
crypto.GetBytes(bytes); //get a bucket of very random bytes
var tempSB = new StringBuilder(Size);
foreach (var b in bytes) { // use b , a random from 0-255 as the index to our source array. Just mod on length set
tempSB.Append(alphaSet[b%(alphaSet.Length)]);
}
return tempSB;
}
EDIT2: In case Someone finds this via google, I have included the lessons learnt Average sample in tests on workstations was around 300 msecs. This should not be too noticeable during logon. And no more need for a Validation key. Which is a relief :-)
SCrypt package installed via nuget. and rfc2898 PBKDF2 changed to be large number or iterations but only 20bytes output. SAme CPU time.
New passwords are encoded in SCRYPT by default,
<package id="CryptSharpOfficial" version="2.0.0.0" targetFramework="net451" />
// save salt, hash algorithm used and resulting encoding on user record
public string PasswordEncode(string password, byte[] salt, HashAlgorithm hashAlgorithm ) {
switch (hashAlgorithm) {
case HashAlgorithm.PBKDF2:
var deriver2898 = new Rfc2898DeriveBytes(password, salt,<Use a number around 50K>); // approx 300msecs on workstation
byte[] hash = deriver2898.GetBytes(20); //
return Convert.ToBase64String(hash);
case HashAlgorithm.Scrypt:
var key = Encoding.UTF8.GetBytes(password);
byte[] hashScrypt = SCrypt.ComputeDerivedKey(key: key, salt: salt,
cost: 65536, // must be a power of 2 !, on PC, singlethread this is approx 1 sec
blockSize: 8,
parallel: 1,
maxThreads: 1,
derivedKeyLength: 128);
return Convert.ToBase64String(hashScrypt);
default:
throw new ArgumentOutOfRangeException("hashAlgorithm");
}
}
**EDIT 3: Latest Library Bcrypt.Net-Next 4.x
This Bcrypt library offers an up to date solution to the hashing process. For more details see why we selected bcrypt.
Do any security experts recommend bcrypt for password storage?