using System;
using System.Security.Cryptography;
namespace SharpUI.Source.Common.Util.Encryption
{
///
/// Password encryption utilities.
///
public class PasswordUtil : IPasswordUtil {
private const short ByteSize = 128;
private const int AlgIterations = 1000;
private readonly IConvertProxy _convertProxy;
public PasswordUtil()
{
_convertProxy = new ConvertProxy();
}
public PasswordUtil(IConvertProxy convertProxy)
{
_convertProxy = convertProxy;
}
///
/// Given the raw password in form of a character sequence, return a hashed password.
///
/// Raw password
/// Hashed password
/// Exception thrown if password is an empty string.
public string PasswordHash(string password) {
string pwdHash;
var salt = new byte[ByteSize];
using (var provider = new RNGCryptoServiceProvider()) {
provider.GetBytes(salt);
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, AlgIterations);
var hash = pbkdf2.GetBytes(ByteSize);
var hashBytes = new byte[ByteSize*2];
Array.Copy(salt, 0, hashBytes, 0, ByteSize);
Array.Copy(hash, 0, hashBytes, ByteSize, ByteSize);
pwdHash = _convertProxy.ToBase64String(hashBytes);
}
if (pwdHash.Trim().Length == 0) {
throw new PasswordEncryptException("ERROR: The PasswordHash() extension is trying to return empty hash value!");
}
return pwdHash;
}
///
/// Verify if the password matches the hashed password.
///
/// Raw password
/// Hashed password
/// True if password matches the hashed password, otherwise false.
public bool IsPasswordValid(string password, string hashedPassword) {
var valid = true;
var bytes = Convert.FromBase64String(hashedPassword);
var salt = new byte[ByteSize];
Array.Copy(bytes, 0, salt, 0, ByteSize);
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, AlgIterations);
var hash = pbkdf2.GetBytes(ByteSize);
for (var i = 0; i < ByteSize; i++) {
valid &= bytes[i + ByteSize] == hash[i];
}
return valid;
}
}
}