首页 > 解决方案 > 在 .NET 中使用 SHA 256 的 PBKDF2

问题描述

我需要更新一些在 .Net 中使用 PBKDF2 实现的代码,Rfc2898DeriveBytes以散列用户凭据。据我了解,此功能在后台使用 SHA-1。我需要更新系统密码散列的底层散列算法以使用 SHA-256(这是客户端 IT-SEC 要求)。

做了一些阅读后,继续使用密钥派生函数似乎是最佳实践,但是 PBKDF2 不允许您指定应该使用的算法,这对我来说显然是个问题。

我们的系统正在使用 .NET 4.5.1,目前还不能升级它,我有理由相信它不是引用任何新的 .NET 核心 .dll 的选项,我听说它包含一个新的 PBKDF2 实现,它允许你指定你的算法。

我想不惜一切代价避免自制实施,因为这是 Crypto-Club 的第一条规则,对吗?

任何关于最佳实践的指导将不胜感激。

谢谢

标签: c#.nethashsha256pbkdf2

解决方案


假设您使用的是 Win7+,您可以 P/Invoke 到BCryptDeriveKeyPBKDF2 。

private static void PBKDF2(
    string password,
    byte[] salt,
    int iterationCount,
    string hashName,
    byte[] output)
{
    int status = SafeNativeMethods.BCryptOpenAlgorithmProvider(
        out SafeNativeMethods.SafeBCryptAlgorithmHandle hPrf,
        hashName,
        null,
        SafeNativeMethods.BCRYPT_ALG_HANDLE_HMAC_FLAG);

    using (hPrf)
    {
        if (status != 0)
        {
            throw new CryptographicException(status);
        }

        byte[] passBytes = Encoding.UTF8.GetBytes(password);

        status = SafeNativeMethods.BCryptDeriveKeyPBKDF2(
            hPrf,
            passBytes,
            passBytes.Length,
            salt,
            salt.Length,
            iterationCount,
            output,
            output.Length,
            0);

        if (status != 0)
        {
            throw new CryptographicException(status);
        }
    }
}

[SuppressUnmanagedCodeSecurity]
private static class SafeNativeMethods
{
    private const string BCrypt = "bcrypt.dll";
    internal const int BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008;

    [DllImport(BCrypt, CharSet = CharSet.Unicode)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern int BCryptDeriveKeyPBKDF2(
        SafeBCryptAlgorithmHandle hPrf,
        byte[] pbPassword,
        int cbPassword,
        byte[] pbSalt,
        int cbSalt,
        long cIterations,
        byte[] derivedKey,
        int cbDerivedKey,
        int dwFlags);

    [DllImport(BCrypt)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    private static extern int BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, int flags);

    [DllImport(BCrypt, CharSet = CharSet.Unicode)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    internal static extern int BCryptOpenAlgorithmProvider(
        out SafeBCryptAlgorithmHandle phAlgorithm,
        string pszAlgId,
        string pszImplementation,
        int dwFlags);

    internal sealed class SafeBCryptAlgorithmHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        public SafeBCryptAlgorithmHandle() : base(true)
        {
        }

        protected override bool ReleaseHandle()
        {
            return BCryptCloseAlgorithmProvider(handle, 0) == 0;
        }
    }
}

推荐阅读