/// <summary> /// Compares a hash, salt and plain password and sets IsValid /// </summary> public SecuredPassword(string plainPassword, byte[] hash, byte[] salt, HashStrategyKind hashStrategy) { _hash = hash; _salt = salt; SetHashStrategy(hashStrategy); byte[] newKey; switch (hashStrategy) { case HashStrategyKind.Pbkdf210001Iterations: var numberOfIterations = (int)_hashingParameter; if (numberOfIterations <= 10000) { throw new ArgumentException("Iterations must be greater than 10000"); } using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, salt, numberOfIterations, HashAlgorithmName.SHA256)) { newKey = deriveBytes.GetBytes(_saltSize); IsValid = newKey.SequenceEqual(hash); } break; case HashStrategyKind.Argon2WorkCost: SecureArray <byte> hashB = null; try { var passwordBytes = Encoding.ASCII.GetBytes(plainPassword); var configOfPasswordToVerify = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, TimeCost = 10, MemoryCost = (int)_hashingParameter, Lanes = 5, Threads = Environment.ProcessorCount, Salt = _salt, Password = passwordBytes, HashLength = 20 }; var hashString = Encoding.ASCII.GetString(_hash); if (configOfPasswordToVerify.DecodeString(hashString, out hashB) && hashB != null) { var argon2ToVerify = new Argon2(configOfPasswordToVerify); using (var hashToVerify = argon2ToVerify.Hash()) { if (!hashB.Buffer.Where((b, i) => b != hashToVerify[i]).Any()) { IsValid = true; } } } } finally { hashB?.Dispose(); } break; } }
internal static ObjectResult VerifyUser(string username, string password) { if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) { return(new InvalidResult("Error: Username/Password are required.")); } try { var result = from user in context.users where user.username == username select user; if (result.Count() == 0) { return(new NotFoundResult("Error: User does not exist.")); } string passwordHash = result.First().passwordHash; bool? isAdmin = result.First().isAdmin; //START CODE BLOCK //-- Code within used from //https://github.com/mheyman/Isopoh.Cryptography.Argon2/blob/master/README.md Argon2Config config = new Argon2Config { Type = Argon2Type.DataIndependentAddressing, Version = Argon2Version.Nineteen, TimeCost = 3, MemoryCost = 32768, Lanes = 4, Threads = Environment.ProcessorCount, Password = Encoding.ASCII.GetBytes(password), Salt = Convert.FromBase64String(Properties.Settings.Default.Salt), HashLength = 20 }; SecureArray <byte> hashB = null; try { if (config.DecodeString(passwordHash, out hashB) && hashB != null) { var argon2ToVerify = new Argon2(config); using (var hashToVerify = argon2ToVerify.Hash()) { if (!hashB.Buffer.Where((b, i) => b != hashToVerify[i]).Any()) { return(new OkResult(isAdmin.ToString())); } else { return(new WrongResult("Error: Username/Password is incorrect.")); } } } } catch (Exception ex) { return(new InvalidResult("Error: Failed to verify password.")); } finally { hashB?.Dispose(); } //END CODE BLOCK } catch (Exception ex) { return(new InvalidResult("Error: Failed retrieving data from the database.")); } return(new InvalidResult("Error: Failed to process verification.")); }