using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using Microsoft.AspNetCore.Cryptography.KeyDerivation; namespace Sockeye.Util { public static class Hasher { public static string hash(string Salt, string Password) { //adapted from here: //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2( password: Password, salt: Convert.FromBase64String(Salt), prf: KeyDerivationPrf.HMACSHA512, iterationCount: 10000, numBytesRequested: 512 / 8)); return hashed; } //Generate salt /* Used for many things: DBID, JWT secret key when none provided, User Salt for login / password, temporary 2fa codes, download tokens, temporary user pw / login when newly created and haven't been set yet */ public static string GenerateSalt() { var salt = new byte[32]; var random = RandomNumberGenerator.Create(); random.GetNonZeroBytes(salt); return Convert.ToBase64String(salt); } public static string GetRandomAlphanumericString(int length) { const string alphanumericCharacters = "0123456789abcdefghijkmnopqrstuvwxyz"; return GetRandomString(length, alphanumericCharacters); } public static string GetRandomString(int length, IEnumerable characterSet) { if (length < 0) throw new ArgumentException("length must not be negative", "length"); if (length > int.MaxValue / 8) throw new ArgumentException("length is too big", "length"); if (characterSet == null) throw new ArgumentNullException("characterSet"); var characterArray = characterSet.Distinct().ToArray(); if (characterArray.Length == 0) throw new ArgumentException("characterSet must not be empty", "characterSet"); var bytes = new byte[length * 8]; RandomNumberGenerator.Create().GetBytes(bytes); var result = new char[length]; for (int i = 0; i < length; i++) { ulong value = BitConverter.ToUInt64(bytes, i * 8); result[i] = characterArray[value % (uint)characterArray.Length]; } return new string(result); } }//eoc }//eons