43 lines
1.6 KiB
C#
43 lines
1.6 KiB
C#
using System;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
//http://codereview.stackexchange.com/questions/96494/user-password-encryption-in-c + SCrypt
|
|
namespace MessageBoard.Encryption
|
|
{
|
|
|
|
public static class PasswordHasher
|
|
{
|
|
public static byte[] ComputeHash(string password, byte[] salt)
|
|
{
|
|
byte[] pwBytes = Encoding.UTF8.GetBytes(password);
|
|
byte[] hashBytes = new byte[64];
|
|
CryptSharp.Utility.SCrypt.ComputeKey(pwBytes, salt, 16384, 8, 1, null, hashBytes);
|
|
return hashBytes;
|
|
}
|
|
|
|
public static byte[] GenerateSalt(int saltByteSize = 24)
|
|
{
|
|
RNGCryptoServiceProvider saltGenerator = new RNGCryptoServiceProvider();
|
|
byte[] salt = new byte[saltByteSize];
|
|
saltGenerator.GetBytes(salt);
|
|
return salt;
|
|
}
|
|
|
|
public static bool VerifyPassword(String password, byte[] passwordSalt, byte[] passwordHash)
|
|
{
|
|
byte[] computedHash = ComputeHash(password, passwordSalt);
|
|
return AreHashesEqual(computedHash, passwordHash);
|
|
}
|
|
|
|
//Length constant verification - prevents timing attack
|
|
private static bool AreHashesEqual(byte[] firstHash, byte[] secondHash)
|
|
{
|
|
int minHashLength = firstHash.Length <= secondHash.Length ? firstHash.Length : secondHash.Length;
|
|
var xor = firstHash.Length ^ secondHash.Length;
|
|
for (int i = 0; i < minHashLength; i++)
|
|
xor |= firstHash[i] ^ secondHash[i];
|
|
return 0 == xor;
|
|
}
|
|
}
|
|
} |