PBKDF2 с использованием SHA 256 в .NET

Мне нужно обновить некоторый код, который использует реализацию PBKDF2 в .Net, Rfc2898DeriveBytes для хеширования учетных данных пользователя. Насколько я понимаю, эта функция использует SHA-1 под капотом. Мне нужно обновить базовый алгоритм хеширования системных паролей, чтобы использовать SHA-256 (это требование клиента IT-SEC).

Прочитав немного, кажется, что лучше продолжать использовать функцию деривации ключа, однако PBKDF2 не позволяет вам диктовать алгоритм, который следует использовать, что, очевидно, является проблемой для меня.

Наша система использует .NET 4.5.1, и в настоящее время нет возможности обновить ее, и я достаточно уверен, что нельзя ссылаться на какие-либо новые библиотеки .NET core .dll, которые, как я слышал, содержат новую реализацию PBKDF2, которая позволяет вам указать свой алгоритм.

Я хочу любой ценой избегать самодельных реализаций, так как это первое правило Crypto-Club, верно?

Буду признателен за любые рекомендации о том, что является наилучшей практикой.

Спасибо


person Dave    schedule 11.06.2018    source источник
comment
Если вы посмотрите на исходный код реализации PBKDF2, вы можете обнаружить, что он использует ОС для создания учетных данных. Тогда остается только создать собственную реализацию для использования более поздней версии вызовов ОС. Возможно, где-то есть P/Invoke, и все готово.   -  person Neil    schedule 11.06.2018
comment
Если вы не можете обновить .NET (что действительно является вашим лучшим вариантом), вы можете использовать Bouncy Castle.   -  person Jeroen Mostert    schedule 11.06.2018
comment
Наша система использует .NET 4.5.1, и в настоящее время нет возможности обновить ее Так и должно быть, Microsoft прекратила поддержку .NET 4.5.1 12 января 2016 г. Как вы обеспечиваете безопасность? обновления??? blogs.msdn.microsoft.com/dotnet/2015/12/09/   -  person ta.speot.is    schedule 11.06.2018
comment
Простое обновление, конечно же, 4.5.2, все еще поддерживается. Но не решение этой проблемы. Стоять на месте так же опасно, как и идти вперед.   -  person bommelding    schedule 11.06.2018
comment
@ta.speot.is Приложения, ориентированные на версию .NET Framework, которая больше не поддерживается, не нуждаются в перенацеливании или перекомпиляции в более новую версию, поскольку их можно запускать в более поздней версии .NET Framework. не вариант. По крайней мере, не тот, о котором я могу принять решение.   -  person Dave    schedule 11.06.2018
comment
Если ваш клиент достаточно заботится о безопасности, чтобы потребовать новый алгоритм хеширования, вероятно, не слишком сложно попросить его использовать последнюю (а также более безопасную) версию .NET, поэтому то, на что нацелено ваше приложение, не должно быть проблемой. Если ваше приложение должно поддерживать старую платформу дополнительно и вы не хотите поддерживать два двоичных файла (хотя вы могли бы с помощью условной компиляции), оно может ориентироваться на .NET 4.5.1 и использовать отражение во время выполнения для узнать, присутствует ли новая функциональность. Однако такой код хрупок и труден для написания. В конечном итоге проблемы с безопасностью заставят обновиться.   -  person Jeroen Mostert    schedule 11.06.2018


Ответы (3)


Я скажу вам, что я бы сделал: я бы взял источник самого нового (не совсем самого нового, потому что он использует Span<>... Просто немного старше :-)) Rfc2898DeriveBytes из corefx github

Вам понадобится полный код:

плюс два метода (GenerateRandom и WriteInt) из

Затем у вас будет несколько вызовов SR.*something*, которые вам придется заменить на некоторые сообщения, такие как "some error", плюс SR.Format, который вы должны заменить на string.Format.

Тогда у вас будет (почти) самая новая версия Rfc2898DeriveBytes, в которой есть конструктор, принимающий в качестве параметра HashAlgorithmName.SHA256.

Это должно быть конечным результатом: https://ideone.com/lb2Qya

У меня была плохая идея поместить исходный код в пространство имен My.System... плохая плохая идея... Мне пришлось добавлять префикс global:: ко всем пространствам имен :-(

person xanatos    schedule 11.06.2018

Вы можете P/Invoke для BCryptDeriveKeyPBKDF2, если вы используете Win7+.

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;
        }
    }
}
person bartonjs    schedule 11.06.2018