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

36 .net c# passwords hash bcrypt

我查询了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哈希密码?

par*_*cle 33

PBKDF2

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

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

BCrypt

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

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

  • FWIW,SimpleCrypto.NET 由于其实现似乎存在一些安全问题。在将这些类型的项目集成到您自己的项目中之前,请务必查看这些类型的项目的 GitHub 问题。 (2认同)

Ale*_*lex 11

首先,我敦促大家使用平台本身包含的经过加密验证的参考算法

不要使用 3rd 方包和未经验证的 OSS 组件或您刚刚从 Internet 复制粘贴的任何其他代码。

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

我并不是对任何高尚的开源开发人员(我自己也是)有任何不尊重的意思,但是您永远无法确定他们的网站在 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
}
Run Code Online (Sandbox Code Playgroud)

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


JPK*_*JPK 9

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

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

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

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 
Run Code Online (Sandbox Code Playgroud)

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

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

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

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)
Run Code Online (Sandbox Code Playgroud)

祝好运!


pcd*_*dev 8

编辑:正如 @MikeT 所指出的,我发布的原始链接和代码不再被认为是存储在数据存储中的哈希密码的最佳实践。

Scott Brady 的这篇文章说明了如何使用 PasswordHasher,以及如何使用该接口来开发更强大的哈希实现。

因此,不再需要自己应用字节级哈希函数,但如果您想了解它是如何完成的,本文将探讨其PasswordHasher<T>实现:

探索 ASP.NET Core 身份PasswordHasher

文章中的一段相关代码如下所示:

private static byte[] HashPasswordV2(string password, RandomNumberGenerator rng)
{
    const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes
    const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
    const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits
    const int SaltSize = 128 / 8; // 128 bits

    // Produce a version 2 text hash.
    byte[] salt = new byte[SaltSize];
    rng.GetBytes(salt);
    byte[] subkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);

    var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
    outputBytes[0] = 0x00; // format marker
    Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
    Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
    return outputBytes;
}
Run Code Online (Sandbox Code Playgroud)

原答案:

Microsoft 为使用 .Net Core 的任何人提供了一个使用 PBKDF2 的示例代码页面:

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=
 */
Run Code Online (Sandbox Code Playgroud)