How to hash a password

后端 未结 9 800
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 14:49

I\'d like to store the hash of a password on the phone, but I\'m not sure how to do it. I can only seem to find encryption methods. How should the password be hashed properl

9条回答
  •  借酒劲吻你
    2020-11-22 15:27

    @csharptest.net's and Christian Gollhardt's answers are great, thank you very much. But after running this code on production with millions of record, I discovered there is a memory leak. RNGCryptoServiceProvider and Rfc2898DeriveBytes classes are derived from IDisposable but we don't dispose of them. I will write my solution as an answer if someone needs with disposed version.

    public static class SecurePasswordHasher
    {
        /// 
        /// Size of salt.
        /// 
        private const int SaltSize = 16;
    
        /// 
        /// Size of hash.
        /// 
        private const int HashSize = 20;
    
        /// 
        /// Creates a hash from a password.
        /// 
        /// The password.
        /// Number of iterations.
        /// The hash.
        public static string Hash(string password, int iterations)
        {
            // Create salt
            using (var rng = new RNGCryptoServiceProvider())
            {
                byte[] salt;
                rng.GetBytes(salt = new byte[SaltSize]);
                using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations))
                {
                    var hash = pbkdf2.GetBytes(HashSize);
                    // Combine salt and hash
                    var hashBytes = new byte[SaltSize + HashSize];
                    Array.Copy(salt, 0, hashBytes, 0, SaltSize);
                    Array.Copy(hash, 0, hashBytes, SaltSize, HashSize);
                    // Convert to base64
                    var base64Hash = Convert.ToBase64String(hashBytes);
    
                    // Format hash with extra information
                    return $"$HASH|V1${iterations}${base64Hash}";
                }
            }
    
        }
    
        /// 
        /// Creates a hash from a password with 10000 iterations
        /// 
        /// The password.
        /// The hash.
        public static string Hash(string password)
        {
            return Hash(password, 10000);
        }
    
        /// 
        /// Checks if hash is supported.
        /// 
        /// The hash.
        /// Is supported?
        public static bool IsHashSupported(string hashString)
        {
            return hashString.Contains("HASH|V1$");
        }
    
        /// 
        /// Verifies a password against a hash.
        /// 
        /// The password.
        /// The hash.
        /// Could be verified?
        public static bool Verify(string password, string hashedPassword)
        {
            // Check hash
            if (!IsHashSupported(hashedPassword))
            {
                throw new NotSupportedException("The hashtype is not supported");
            }
    
            // Extract iteration and Base64 string
            var splittedHashString = hashedPassword.Replace("$HASH|V1$", "").Split('$');
            var iterations = int.Parse(splittedHashString[0]);
            var base64Hash = splittedHashString[1];
    
            // Get hash bytes
            var hashBytes = Convert.FromBase64String(base64Hash);
    
            // Get salt
            var salt = new byte[SaltSize];
            Array.Copy(hashBytes, 0, salt, 0, SaltSize);
    
            // Create hash with given salt
            using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations))
            {
                byte[] hash = pbkdf2.GetBytes(HashSize);
    
                // Get result
                for (var i = 0; i < HashSize; i++)
                {
                    if (hashBytes[i + SaltSize] != hash[i])
                    {
                        return false;
                    }
                }
    
                return true;
            }
    
        }
    }
    

    Usage:

    // Hash
    var hash = SecurePasswordHasher.Hash("mypassword");
    
    // Verify
    var result = SecurePasswordHasher.Verify("mypassword", hash);
    

提交回复
热议问题