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; } } }