Hash Password in C#? Bcrypt/PBKDF2

前端 未结 9 1019
傲寒
傲寒 2020-12-22 20:06

I looked up msdn and other resources on how to do this but i came up with no clear solutions. This is the best i found http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/gen

相关标签:
9条回答
  • 2020-12-22 20:33

    PBKDF2 uses HMACSHA1, if you would like a more modern and customisable solution you should look at this API using HMACSHA256 or 512 with key stretching just like PBKDF2

    https://sourceforge.net/projects/pwdtknet/

    Sample GUI included in source code demonstrated how to get a hash from a password including the creation of crypto random salt.....enjoy :)

    0 讨论(0)
  • 2020-12-22 20:34

    Microsoft has a page up with sample code using PBKDF2 for anyone using .Net Core:

    Hash passwords in ASP.NET Core

    From the article:

    using System;
    using System.Security.Cryptography;
    using Microsoft.AspNetCore.Cryptography.KeyDerivation;
    
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.Write("Enter a password: ");
            string password = Console.ReadLine();
    
            // generate a 128-bit salt using a secure PRNG
            byte[] salt = new byte[128 / 8];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }
            Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
    
            // derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
            string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
                password: password,
                salt: salt,
                prf: KeyDerivationPrf.HMACSHA1,
                iterationCount: 10000,
                numBytesRequested: 256 / 8));
            Console.WriteLine($"Hashed: {hashed}");
        }
    }
    
    /*
     * SAMPLE OUTPUT
     *
     * Enter a password: Xtw9NMgx
     * Salt: NZsP6NnmfBuYeJrrAKNuVQ==
     * Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
     */
    
    0 讨论(0)
  • 2020-12-22 20:36

    First of all, I urge everyone to use a cryptographically verified reference algorithm included with the platform itself.

    Do not use 3rd party packages and non-verified OSS components or any other code you just copy-pasted from the Internet.

    For .NET use PBKDF2 and not bCrypt because there's no certified implementation of bCrypt for .NET

    I don't mean any disrespect for any noble open-source devs (being one myself), but you can never be sure their website won't be hacked in 10 years and you end up getting a malware package from Nuget/npm or other package managers.

    More info about verification can be found in this SO answer

    Now, back to PBKDF2, here's the simple code

    public static byte[] PBKDF2Hash(string input, byte[] salt)
    {
        // Generate the hash
        Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
        return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
    }
    

    If you need a string representation of the hash (not byte-array) - you can use this superfast conversion class from this answer http://stackoverflow.com/a/624379/714733

    0 讨论(0)
  • 2020-12-22 20:36

    For PBKDF2, you might be able to use System.Security.Cryptography.Rfc2898DeriveBytes.

    See MSDN here: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

    0 讨论(0)
  • 2020-12-22 20:37

    PBKDF2

    In the example in http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx, when you get to the line "Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1, myIterations);", k1 is the hash. The reason the example is for encryption is that Rfc2898DeriveBytes was originally designed to create encryption keys.

    If you do not provide a salt, Rfc2898DeriveBytes will create it's own, but I do not know whether RNGCryptoServiceProvider does a better job of being cryptographically random.

    According to OWASP (https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2), the underlying use of SHA1 by Rfc2898DeriveBytes means it's only good for hashes up to 160 bits in length. If you create a longer hash, an attacker still only has to worry about the first 160 bits, but you have made password hashing/authentication more expensive for yourself with no gain.

    Here's some example code for Rfc2898DeriveBytes password hashing (store the hash, salt and iterations in the DB):

    public class Rfc2898PasswordEncoder
    {
        private int _byteLength = 160 / 8; // 160 bit hash length
    
        public class EncodedPassword
        {
            public byte[] Hash { get; set; }
            public byte[] Salt { get; set; }
            public int Iterations { get; set; }
        }
    
        public EncodedPassword EncodePassword(string password, int iterations)
        {
            var populatedPassword = new EncodedPassword
            {
                Salt = CreateSalt(),
                Iterations = iterations
            };
    
            // Add Hash
            populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);
    
            return populatedPassword;
        }
    
        public bool ValidatePassword(string password, EncodedPassword encodedPassword)
        {
            // Create Hash
            var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);
    
            return testHash == encodedPassword.Hash;
        }
    
        public byte[] CreateSalt()
        {
            var salt = new byte[_byteLength]; // Salt should be same length as hash
    
            using (var saltGenerator = new RNGCryptoServiceProvider())
            {
                saltGenerator.GetBytes(salt);
            }
    
            return salt;
        }
    
        private byte[] CreateHash(string password, byte[] salt, long iterations)
        {
            byte[] hash;
            using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
            {
                hash = hashGenerator.GetBytes(_byteLength);
            }
    
            return hash;
        }
    } 
    
    0 讨论(0)
  • 2020-12-22 20:39

    i was interested in an answers that didn't involve any libraries.

    I read this article https://crackstation.net/hashing-security.htm which links an implementation in different languages C# among them which i will link here too

    https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs

    interestingly it uses Rfc2898DeriveBytes as mentioned a few times here.

    private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes){
        using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt)) {
            pbkdf2.IterationCount = iterations;
            return pbkdf2.GetBytes(outputBytes);
        }
    }
    
    0 讨论(0)
提交回复
热议问题