繁体   English   中英

C#中的哈希密码? Bcrypt / PBKDF2

[英]Hash Password in C#? Bcrypt/PBKDF2

我查询了msdn和其他资源如何做到这一点,但我想出了没有明确的解决方案。 这是我找到的最好的http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true

我想使用bcrypt或PBKDF2(看起来与bcrypt相关)在C#中散列密码。 我想试验一下我的计算机散列密码需要多少轮。 然而,一切似乎都是关于加密,而每个人都谈论哈希。 我无法弄清楚。 我如何哈希密码? 它看起来更像PBKDF2(Rfc2898?)是一个随机数生成器,我使用GetBytes(金额)来选择我的散列大小有多大。

我糊涂了。 我究竟如何用bcrypt / PBKDF哈希密码?

PBKDF2

你真的很亲密。 您给出的链接向您展示了如何调用Rfc2898DeriveBytes函数来获取PBKDF2哈希结果。 但是,由于示例使用派生密钥进行加密(PBKDF1和2的原始动机是创建适合用作加密密钥的“密钥”派生函数),因此您被抛弃了。 当然,我们不希望将输出用于加密,而是将其作为哈希本身。

如果你想要PBKDF2,你可以尝试为此目的编写的SimpleCrypto.Net库。 如果你看看实现 ,你可以看到它实际上只是一个薄的包装(你猜对了) Rfc2898DeriveBytes

BCrypt

如果你想试验这个变种,可以试试名为(还有什么) BCrypt.NET的C#实现。

免责声明:我没有使用或测试过我链接过的任何库... YMMV

我花了很长时间 (需要几天的时间)才能找到实际编码的代码来获取散列密码! 所以我把它放在这里是为了方便。

你需要阅读文档理论1 理论2 ,然后一些或你可能对安全漏洞开放。 安全是一个非常大的话题! 买家要小心!

将NuGet包BCrypt.Net添加到解决方案中

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

您应该将WorkFactor调整为适当的参见讨论 它是一个log2函数

“这个数字是log2,因此每次计算机速度加倍时,请将默认数字加1。”

然后将散列密码作为passwordFromLocalDB存储在数据库中,并测试传入password如下所示:

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

祝好运!

今年早些时候,我正在研究为ASP.NET Web Forms项目创建哈希的相同事情,我想以与MVC项目开箱即用的方式相同的方式进行。

我偶然发现了这个问题=> ASP.NET Identity默认密码Hasher,它是如何工作的并且它是否安全? 然后我在这里找到了带有ByteArraysEqual方法的源=> 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

首先,我敦促大家使用平台本身附带的加密验证参考算法

请勿使用第三方软件包和未经验证的OSS组件或您刚刚从Internet复制粘贴的任何其他代码。

对于.NET, 使用PBKDF2不是bCrypt,因为没有经过认证的bCrypt for .NET实现

我并不是说对任何高尚的开源开发者(我自己)都不尊重,但你永远不能确定他们的网站在10年内不会被黑客入侵你最终会从Nuget / npm或其他人那里获得恶意软件包包管理员。

有关验证的更多信息,请参阅此SO答案

现在,回到PBKDF2,这是简单的代码

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
}

如果你需要哈希的字符串表示(不是字节数组) - 你可以从这个答案中使用这个超高速转换类http://stackoverflow.com/a/624379/714733

对于PBKDF2,您可以使用System.Security.Cryptography.Rfc2898DeriveBytes。

请参阅MSDN: http//msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

PBKDF2使用HMACSHA1,如果你想要一个更现代和可定制的解决方案,你应该使用HMACSHA256或512关键拉伸来看看这个API,就像PBKDF2一样

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

源代码中包含的示例GUI演示了如何从密码中获取哈希,包括创建加密随机盐.....享受:)

对于使用.Net Core的任何人,Microsoft都有一个使用PB​​KDF2的示例代码页面:

在ASP.NET Core中散列密码

来自文章:

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=
 */

PBKDF2

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx中的示例中,当您到达“Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1,salt1,myIterations)”行时; “,k1是哈希。 该示例用于加密的原因是Rfc2898DeriveBytes最初设计用于创建加密密钥。

如果你不提供盐,Rfc2898DeriveBytes将创建它自己的,但我不知道RNGCryptoServiceProvider是否能更好地加密随机。

根据OWASP( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 ),Rfc2898DeriveBytes对SHA1的基础使用意味着它仅适用于长度最多为160位的散列。 如果你创建一个更长的哈希,攻击者仍然只需要担心前160位,但你已经使密码哈希/身份验证对你自己更加昂贵而没有任何收益。

以下是Rfc2898DeriveBytes密码散列的一些示例代码(在数据库中存储散列,salt和迭代):

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;
    }
} 

我对不涉及任何图书馆的答案感兴趣。

我读了这篇文章https://crackstation.net/hashing-security.htm ,它链接了不同语言C#的实现,我将在这里链接

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

有趣的是,它使用的Rfc2898DeriveBytes在这里提到过几次。

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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM