Hash Password in C#? Bcrypt/PBKDF2

2019-01-30 06:36发布

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/generating-a-key-from-a-password.aspx?Redirected=true

I would like to hash passwords in C# using either bcrypt or PBKDF2 (which appears to be bcrypt related). I like to experiment with how many rounds it takes for my computer to hash a password. However everything seems to be about encrypting while everyone talks about hashing. I can't figure it out. How do i hash a password? It looks more like PBKDF2 (Rfc2898?) is a random number generator and i use GetBytes(amount) to choose how big my hash size is.

I'm confused. How exactly do i hash a password with bcrypt/PBKDF?

7条回答
贼婆χ
2楼-- · 2019-01-30 07:31

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;
    }
} 
查看更多
劳资没心,怎么记你
3楼-- · 2019-01-30 07:31

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);
    }
}
查看更多
冷血范
4楼-- · 2019-01-30 07:35

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 :)

查看更多
贼婆χ
5楼-- · 2019-01-30 07:38

It took me forever (days it took days) to find what to actually code to get hashed passwords to work!! so I put it here for convenience.

You do need to read the documentation and theory1 theory2 and then some or you could be open to security loopholes. Security is a very big topic! Buyer Beware!

Add the NuGet Package BCrypt.Net to the solution

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 

You should adjust the WorkFactor to what is appropriate see discussions. Its a log2 function

"The number is log2, so every time computers double in speed, add 1 to the default number."

Then you store the hashed password in your db as passwordFromLocalDB and to test an incoming password like this:

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)

Good Luck!

查看更多
混吃等死
6楼-- · 2019-01-30 07:38

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

查看更多
Ridiculous、
7楼-- · 2019-01-30 07:39

Earlier this year I was looking into the same thing for creating hashes for our ASP.NET Web Forms project, I wanted to do it the same way MVC projects do it out of the box.

I stumbled upon this question => ASP.NET Identity default Password Hasher, how does it work and is it secure? Then I found the source with the ByteArraysEqual method here => http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140327/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Crypto.cs?ImageName=Microsoft.AspNet.Identity.Core

查看更多
登录 后发表回答