【问题标题】:How do I use SHA-512 with Rfc2898DeriveBytes in my salt & hash code?如何在我的盐和哈希码中使用带有 Rfc2898DeriveBytes 的 SHA-512?
【发布时间】:2014-11-11 23:42:59
【问题描述】:

我对密码学完全陌生,但正在学习。我从网上的研究中总结了许多不同的建议,并创建了自己的类来处理哈希、盐、键拉伸以及相关数据的比较/转换。

在研究了用于密码学的内置 .NET 库后,我发现我所拥有的仍然只有 SHA-1。但我得出的结论是,这还不错,因为我使用了哈希过程的多次迭代。对吗?

但是,如果我想从更强大的 SHA-512 开始,我该如何在下面的代码中实现它?提前致谢。

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;

public class CryptoSaltAndHash
{
    private string strHash;
    private string strSalt;
    public const int SaltSizeInBytes = 128;
    public const int HashSizeInBytes = 1024;
    public const int Iterations = 3000;

    public string Hash { get { return strHash; } }
    public string Salt { get { return strSalt; } }

    public CryptoSaltAndHash(SecureString ThisPassword)
    {
        byte[] bytesSalt = new byte[SaltSizeInBytes];
        using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
        {
            crypto.GetBytes(bytesSalt);
        }
        strSalt = Convert.ToBase64String(bytesSalt);
        strHash = ComputeHash(strSalt, ThisPassword);
    }

    public static string ComputeHash(string ThisSalt, SecureString ThisPassword)
    {
        byte[] bytesSalt = Convert.FromBase64String(ThisSalt);
        Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(
            convertSecureStringToString(ThisPassword), bytesSalt, Iterations);
        using (pbkdf2)
        {
            return Convert.ToBase64String(pbkdf2.GetBytes(HashSizeInBytes));
        }
    }

    public static bool Verify(string ThisSalt, string ThisHash, SecureString ThisPassword)
    {
        if (slowEquals(getBytes(ThisHash), getBytes(ComputeHash(ThisSalt, ThisPassword))))
        {
            return true;
        }
        return false;
    }

    private static string convertSecureStringToString(SecureString MySecureString)
    {
        IntPtr ptr = IntPtr.Zero;
        try
        {
            ptr = Marshal.SecureStringToGlobalAllocUnicode(MySecureString);
            return Marshal.PtrToStringUni(ptr);
        }
        finally
        {
            Marshal.ZeroFreeGlobalAllocUnicode(ptr);
        }
    }

    private static bool slowEquals(byte[] A, byte[] B)
    {
        int intDiff = A.Length ^ B.Length;
        for (int i = 0; i < A.Length && i < B.Length; i++)
        {
            intDiff |= A[i] ^ B[i];
        }
        return intDiff == 0;
    }

    private static byte[] getBytes(string MyString)
    {
        byte[] b = new byte[MyString.Length * sizeof(char)];
        System.Buffer.BlockCopy(MyString.ToCharArray(), 0, b, 0, b.Length);
        return b;
    }
}

注意:我参考了https://crackstation.net/hashing-security.htm 的很多做法。 slowEquals 比较方法是通过防止分支来规范执行时间。 SecureString 的用途是在这个类和我的 Web 应用程序中的其他类和页面之间使用加密形式的密码传递。虽然此站点将通过 HTTPS 进行,但最好多做一点以确保事情尽可能安全,同时仍在合理范围内。

在我的代码中,我将密钥字符串设置为 128 字节(尽管有时它会变大,这很好),哈希大小设置为 1KB,迭代次数设置为 3,000。它比典型的 64 字节盐、512 字节哈希和 1,000 或 2,000 次迭代要大一些,但登录速度和应用性能仍然是一个极低的优先级。

想法?

【问题讨论】:

标签: c# hash cryptography salt sha


【解决方案1】:
  1. 3000 次迭代非常低。即使是10000也很低。但是,您需要权衡额外迭代的安全收益与攻击者通过经常尝试登录来拒绝您的服务器的风险,这会为每次尝试触发昂贵的哈希值。
  2. 盐分大于 128 位/16 字节是没有意义的。盐应该是独一无二的,仅此而已。
  3. 哈希大小大于本机大小(SHA-1 为 20 字节)会降低防御者的性能,但不会降低攻击者的性能。由于这意味着您可以负担更少的迭代次数,因此实际上会削弱安全性。

    例如,以与 3000 次迭代的 1024 字节哈希相同的成本,您可以负担 156000 次迭代的 20 字节哈希,破解成本要高 52 倍。

  4. 要使用 SHA-2,您需要完全不同的 PBKDF2 实现,.net 中包含的实现是硬编码以使用 SHA-1。

    如果您费心使用第三方库,我宁愿使用 bcrypt 库,因为它对基于 GPU 的攻击者更强大。

  5. 您的 API 难以使用,因为您将 salt 管理推送给调用者,而不是在 Create/Verify 函数中处理它。

  6. 使用SecureString 然后将其转换为String 是愚蠢的。这抵消了首先使用SecureString 的全部意义。

    我个人不会在典型应用程序中使用SecureString。仅当您将其与广泛的全栈安全审查相结合时才值得,以检查密码从未存储在 String 中,并且在不再需要时始终从可变存储中删除。

  7. 我不会在实例变量中存储密码/盐。只需将它们保留在相关功能的本地即可。我只会将配置存储在实例变量中(例如迭代计数)。

  8. 虽然 SHA-1 在加密上被削弱,但攻击会产生冲突。因为密码散列冲突无关紧要,您关心的是第一次原像攻击。 SHA-1 在这方面仍然相当强大。

    SHA-512 的主要优势不在于它在密码学上更强大(尽管如此),而是 64 位算法对攻击者的成本高于防御者,因为防御者可能会使用 64 位 Intel CPU,它提供快速 64位算术。

【讨论】:

  • 很好的建议,非常感谢!如果我从不将 SecureString 转换为代码中的字符串,我会记得只使用它。至于我的 API 使用起来很尴尬,它似乎工作得很好。实例化该类以创建 salt 和 has,或静态调用它以验证先前创建的哈希。那里没有管理人员向来电者施加压力。但是我的问题围绕着你的#4 点。您能否详细说明该建议以及如何在 .NET 环境中实现它(例如:选择您推荐的 SHA-2 库)。再次感谢!
  • 我从不费心研究 PBKDF2-HMAC-SHA-2 的 C# 实现,所以我真的不知道。我猜bouncycastle支持它。就个人而言,我宁愿评估 bcrypt.net 和其他 bcrypt 实现。
【解决方案2】:

如果有人通过搜索遇到这个问题,现在微软提供了Microsoft.AspNetCore.Cryptography.KeyDerivation NuGet 包,它允许使用带有 SHA-256 和 SHA-512 哈希函数的 PBKDF2。文档可通过docs.microsoft.com 获取。

【讨论】:

  • 谢谢你,ovolko。我的问题很老了,所以它肯定已经过时了,你获取微软支持的库和函数的链接非常有帮助!我将此标记为正确的、更现代的答案。
【解决方案3】:

回答问题:从“SecurityDriven.NET”一书中下载免费代码示例。找到采用 HMAC 工厂的 PBKDF2 类。 HMACSHA512 工厂可用,等等。

由于您是密码学的新手,我也强烈建议您阅读这本书(例如,充分理解 CodesInChaos 提出的观点)。

【讨论】:

  • 谢谢。虽然这些示例使用 .NET 4.5,但我使用的是 .NET 4.0。但是,它们应该以最小的变化同时适用于两者。这些示例引用了我需要的加密类:msdn.microsoft.com/en-us/library/…
【解决方案4】:

对于那些通过搜索得到的人来说,答案是Rfc2898DeriveBytes 构造函数将哈希算法作为参数,HashAlgorithmName.SHA512 是一个受支持的选项。所以,这行得通:

var pbkdf2 = new Rfc2898DeriveBytes(passwordBytes, bytesSalt, 1000000, HashAlgorithmName.SHA512);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-23
    • 2014-05-12
    • 2013-04-26
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    相关资源
    最近更新 更多