使用MD5或sha-256 C#哈希密码#

Sea*_*ean 43 c# hash sha256

我正在为一个应用程序编写一个注册表单,但仍然遇到了新的c#问题.

我希望加密/哈希密码到md5或sha-256,最好是sha-256.

有什么好例子吗?我希望它能够从"字符串密码"中获取信息; 然后散列它并存储在变量"string hPassword;"中.有任何想法吗?

Luk*_*keH 78

不要使用简单的哈希,甚至是盐渍哈希.使用某种密钥加强技术,如bcrypt(此处使用.NET实现)或PBKDF2(具有内置实现).

这是使用PBKDF2的示例.

从密码生成密钥...

string password = GetPasswordFromUserInput();

// specify that we want to randomly generate a 20-byte salt
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
{
    byte[] salt = deriveBytes.Salt;
    byte[] key = deriveBytes.GetBytes(20);  // derive a 20-byte key

    // save salt and key to database
}
Run Code Online (Sandbox Code Playgroud)

然后测试密码是否有效......

string password = GetPasswordFromUserInput();

byte[] salt, key;
// load salt and key from database

using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
    byte[] newKey = deriveBytes.GetBytes(20);  // derive a 20-byte key

    if (!newKey.SequenceEqual(key))
        throw new InvalidOperationException("Password is invalid!");
}
Run Code Online (Sandbox Code Playgroud)

  • 我假设在你的帖子中你说**PBKDF2**,你打算说**或**.我不建议在.NET中使用bcrypt,StackOverflow放弃了bcrypt来使用PBKDF2.请参阅StackOverflow博客上Kevin Montrose的评论http://blog.stackoverflow.com/2011/05/stack-exchange-is-an-openid-provider/ (3认同)
  • bcrypt的问题在于它没有经过验证的.NET实现,这就是为什么StackOverflow选择放弃使用bcrypt的原因.他们不希望花费资源来验证实现,而已经在.NET中验证了.NET中包含的PBKDF2本机实现. (2认同)

Don*_*nut 54

您将要使用System.Security.Cryptography命名空间; 特别是MD5班级SHA256班级.

这个页面上的代码中抽取一点,并且知道两个类具有相同的基类(HashAlgorithm),你可以使用这样的函数:

public string ComputeHash(string input, HashAlgorithm algorithm)
{
   Byte[] inputBytes = Encoding.UTF8.GetBytes(input);

   Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);

   return BitConverter.ToString(hashedBytes);
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样调用它(对于MD5):

string hPassword = ComputeHash(password, new MD5CryptoServiceProvider());
Run Code Online (Sandbox Code Playgroud)

或者对于SHA256:

string hPassword = ComputeHash(password, new SHA256CryptoServiceProvider());
Run Code Online (Sandbox Code Playgroud)

编辑:添加Salt支持
正如dtb在注释中指出的那样,如果它包含添加salt的能力,则此代码会更强.如果你不熟悉它,salt是一组随机位,它们被包含作为散列函数的输入,这对于阻止对散列密码的字典攻击(例如,使用彩虹表)有很长的路要走.这ComputeHash是支持salt 的函数的修改版本:

public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
   Byte[] inputBytes = Encoding.UTF8.GetBytes(input);

   // Combine salt and input bytes
   Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
   salt.CopyTo(saltedInput, 0);
   inputBytes.CopyTo(saltedInput, salt.Length);

   Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);

   return BitConverter.ToString(hashedBytes);
}
Run Code Online (Sandbox Code Playgroud)

希望这对你有所帮助!

  • 使用PBKDF2(通过`Rfc2898DeriveBytes`)更安全,实际上需要*更少*代码. (8认同)
  • `MD5CryptoServiceProvider`和`SHA256CryptoServiceProvider`(以及相关的`HashAlgorithm`s)实现了`IDisposable`接口,因此它们的创建和生命周期应该最佳地包装在`using'块中,而不是刚刚作为参数传递的新对象. (4认同)

Ada*_*cer 6

在将数据存储在数据库中时,应始终在密码之前对密码进行加密.

推荐的数据库列:

  • PasswordSalt:int
  • PasswordHash:二进制(20)

您在网上找到的大多数帖子都会讨论对salt和hash进行ASCII编码,但这不是必需的,只会添加不需要的计算.此外,如果使用SHA-1,则输出将只有20个字节,因此数据库中的哈希字段长度只需要20个字节.我理解你对SHA-256的询问,但除非你有令人信服的理由,否则在大多数商业实践中使用带盐值的SHA-1就足够了.如果坚持使用SHA-256,则数据库中的哈希字段长度必须为32个字节.

下面是一些将生成salt,计算哈希值并根据密码验证哈希值的函数.

下面的salt函数从4个加密创建的随机字节生成加密强盐作为整数.

private int GenerateSaltForPassword()
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] saltBytes = new byte[4];
    rng.GetNonZeroBytes(saltBytes);
    return (((int)saltBytes[0]) << 24) + (((int)saltBytes[1]) << 16) + (((int)saltBytes[2]) << 8) + ((int)saltBytes[3]);
}
Run Code Online (Sandbox Code Playgroud)

然后可以使用带有以下功能的salt对密码进行哈希处理.将salt连接到密码,然后计算哈希值.


private byte[] ComputePasswordHash(string password, int salt)
{
    byte[] saltBytes = new byte[4];
    saltBytes[0] = (byte)(salt >> 24);
    saltBytes[1] = (byte)(salt >> 16);
    saltBytes[2] = (byte)(salt >> 8);
    saltBytes[3] = (byte)(salt);

    byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);

    byte[] preHashed = new byte[saltBytes.Length + passwordBytes.Length];
    System.Buffer.BlockCopy(passwordBytes, 0, preHashed, 0, passwordBytes.Length);
    System.Buffer.BlockCopy(saltBytes, 0, preHashed, passwordBytes.Length, saltBytes.Length);

    SHA1 sha1 = SHA1.Create();
    return sha1.ComputeHash(preHashed);
}

Run Code Online (Sandbox Code Playgroud)

只需计算哈希值,然后将其与预期的哈希值进行比较,即可检查密码.


private bool IsPasswordValid(string passwordToValidate, int salt, byte[] correctPasswordHash)
{
    byte[] hashedPassword = ComputePasswordHash(passwordToValidate, salt);

    return hashedPassword.SequenceEqual(correctPasswordHash);
}

Run Code Online (Sandbox Code Playgroud)

  • -1表示普通SHA-1.使用慢速哈希,例如PBKDF2,bcrypt或scrypt.它也建议使用64位盐,但这是一个小问题. (4认同)

ovo*_*lko 5

TL;DR 使用Microsoft.AspNetCore.Cryptography.KeyDerivation,使用 SHA-512 实现 PBKDF2。

开始使用密码散列的好主意是查看OWASP 指南的规定。推荐的算法列表包括 Argon2、PBKDF2、scrypt 和 bcrypt。所有这些算法都可以调整,以调整散列密码所需的时间,以及相应地通过暴力破解密码的时间。所有这些算法都利用盐来防止彩虹表攻击。

这些算法都不是很弱,但是有一些区别:

  • bcrypt 已经存在了近 20 年,得到了广泛的应用,并且经受住了时间的考验。它可以很好地抵抗 GPU 攻击,但不能抵抗 FPGA
  • Argon2 是最新成员,是 2015 年密码哈希竞赛的获胜者。它可以更好地防御 GPU 和 FPGA 攻击,但对我来说有点太新了
  • 我对scrypt了解不多。它的设计目的是阻止 GPU 和 FPGA 加速攻击,但我听说它并不像最初声称的那么强大
  • PBKDF2 是一系列由不同哈希函数参数化的算法。它不提供针对 GPU 或 ASIC 攻击的特定保护,特别是在使用 SHA-1 等较弱的哈希函数时,但如果它对您很重要,则它经过 FIPS 认证,并且如果迭代次数为足够大。

仅基于算法,​​我可能会选择 bcrypt,PBKDF2 是最不受欢迎的。

然而,这并不是故事的全部,因为即使是最好的算法也可能因为糟糕的实现而变得不安全。让我们看看 .NET 平台有哪些功能:

  • Bcrypt 可通过bcrypt.net获得。他们说该实现是基于 Java jBCrypt。目前 github 上有 6 个贡献者和 8 个问题(全部已关闭)。总的来说,看起来不错,不过,不知道是否有人对代码进行了审计,也很难判断如果发现漏洞是否会很快推出更新版本。我听说 Stack Overflow 由于这些原因不再使用 bcrypt
  • 使用 Argon2 的最佳方法可能是通过绑定到著名的 libsodium 库,例如 https://github.com/adamcaudill/libsodium-net。这个想法是,大部分加密是通过 libsodium 实现的,它有相当大的支持,而“未经测试”的部分非常有限。然而,在密码学中,细节意义重大,因此结合 Argon2 相对较新的情况,我将其视为一个实验选项
  • 长期以来,.NET 通过Rfc2898DeriveBytes类内置了 PBKDF2 的实现 。然而,实现只能使用 SHA-1 哈希函数,目前认为该函数速度太快且不安全
  • 最后,最新的解决方案是 通过 NuGet 提供的Microsoft.AspNetCore.Cryptography.KeyDerivation包。它提供带有 SHA-1、SHA-256 或 SHA-512 哈希函数的 PBKDF2 算法,这比Rfc2898DeriveBytes. 这里最大的优势是该实现是由 Microsoft 提供的,虽然我无法正确评估 Microsoft 开发人员与 BCrypt.net 或 libsodium 开发人员的加密勤奋,但信任它是有意义的,因为如果您正在运行 .NET 应用程序,已经严重依赖微软了。如果发现安全问题,我们也可能期望微软发布更新。希望。

总结到目前为止的研究,虽然 PBKDF2 可能是四种算法中最不受欢迎的算法,但 Microsoft 提供的实现的可用性胜过这一点,因此合理的决定是使用Microsoft.AspNetCore.Cryptography.KeyDerivation.

目前最新的包面向 .NET Standard 2.0,因此可在 .NET Core 2.0 或 .NET Framework 4.6.1 或更高版本中使用。如果您使用早期的框架版本,则可以使用该包的早期版本1.1.3,它面向 .NET Framework 4.5.1 或 .NET Core 1.0。不幸的是,甚至无法在 .NET 的早期版本中使用它。

文档和工作示例可在learn.microsoft.com上获取。但是,不要按原样复制粘贴,开发人员仍然需要做出决定。

第一个决定是使用什么哈希函数。可用选项包括 SHA-1、SHA-256 和 SHA-512。其中,SHA-1 绝对太快而无法保证安全,SHA-256 还不错,但我会推荐 SHA-512,因为据说它的 64 位操作使用使得更难从基于 GPU 的攻击中受益。

然后,您需要选择密码哈希输出长度和盐长度。输出长于哈希函数输出(例如 SHA-512 的 512 位)是没有意义的,并且完全像这样可能是最安全的。对于盐的长度,意见不一。128 位应该足够了,但无论如何,长度超过哈希输出长度肯定不会带来任何好处。

接下来是迭代计数。它越大,密码哈希就越难破解,但用户登录所需的时间就越长。我建议选择它,这样哈希在典型的生产系统上需要 0.25 - 1 秒,并且在任何情况下,它不应低于10000。

通常,您会得到字节数组作为盐和哈希值。使用 Base64 将它们转换为字符串。您可以选择在数据库中使用两个不同的列,或者使用 Base64 中未遇到的分隔符将盐和密码合并在一列中。

不要忘记设计密码哈希存储,以便将来无缝地转向更好的哈希算法。