Подтвердить что ты не робот

Хэш-пароль в С#? Bcrypt/PBKDF2

Я просмотрел msdn и другие ресурсы о том, как это сделать, но я не нашел четких решений. Это лучшее, что я нашел http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true

Я хотел бы использовать хэш-коды в С#, используя либо bcrypt, либо PBKDF2 (который, как представляется, связан с bcrypt). Мне нравится экспериментировать с тем, сколько раундов требуется для моего компьютера для хеширования пароля. Однако все, кажется, связано с шифрованием, в то время как все говорят о хешировании. Я не могу понять. Как сделать хэш-пароль? Он больше похож на PBKDF2 (Rfc2898?) - генератор случайных чисел, и я использую GetBytes (amount), чтобы выбрать размер моего хэша.

Я в замешательстве. Как именно я использую пароль с помощью bcrypt/PBKDF?

4b9b3361

Ответ 1

PBKDF2

Вы были действительно близко на самом деле. Ссылка, которую вы дали, показывает вам, как вы можете вызвать функцию Rfc2898DeriveBytes, чтобы получить результаты хэша PBKDF2. Тем не менее, вы были сбиты с толку тем фактом, что в примере использовался производный ключ для целей шифрования (первоначальная мотивация для PBKDF1 и 2 заключалась в создании "производных" функций вывода ключа, пригодных для использования в качестве ключей шифрования). Конечно, мы не хотим использовать выходные данные для шифрования, но в качестве хэша.

Вы можете попробовать библиотеку SimpleCrypto.Net, написанную именно для этой цели, если вы хотите PBKDF2. Если вы посмотрите на реализацию, вы увидите, что это на самом деле просто тонкая оболочка (как вы уже догадались) Rfc2898DeriveBytes.

BCrypt

Вы можете попробовать реализацию С# с именем (что еще) BCrypt.NET, если хотите поэкспериментировать с этим вариантом.

Отказ от ответственности: я не использовал и не проверял ни одну из библиотек, с которыми я связан... YMMV

Ответ 2

У меня ушло навсегда (дни заняли дни), чтобы найти, что на самом деле код, чтобы получить хешированные пароли для работы! поэтому я положил это здесь для удобства.

Вам нужно прочитать документацию и теории1 theory2, а затем некоторые или вы могли бы быть открытыми для лазеек безопасности. Безопасность это очень большая тема! Предостережение для покупателя!

Добавьте пакет NuGet BCrypt.Net к решению

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 

Вы должны настроить WorkFactor в соответствии с тем, что подходит для обсуждения. Это функция log2

"Число - log2, поэтому каждый раз, когда компьютеры удваивают скорость, добавьте 1 к номеру по умолчанию".

Затем вы сохраняете хешированный пароль в вашей базе данных как passwordFromLocalDB и проверяете входящий password следующим образом:

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)

Удачи!

Ответ 3

В начале этого года я искал то же самое для создания хэшей для нашего проекта ASP.NET Web Forms, я хотел сделать это так же, как MVC-проекты делают это из коробки.

Я наткнулся на этот вопрос = > ASP.NET Identity по умолчанию Password Hasher, как он работает и безопасен? Затем я нашел источник с методом ByteArraysEqual здесь = > http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140327/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Crypto.cs?ImageName=Microsoft.AspNet.Identity.Core

Ответ 5

PBKDF2 использует HMACSHA1, если вы хотите более современное и настраиваемое решение, вы должны посмотреть на этот API, используя HMACSHA256 или 512 с растяжением клавиш, как PBKDF2

https://sourceforge.net/projects/pwdtknet/

Пример GUI, включенный в исходный код, показал, как получить хэш из пароля, включая создание крипто случайной соли..... наслаждайтесь:)

Ответ 6

У Microsoft есть страница с примером кода с использованием PBKDF2 для всех, кто использует .Net Core:

Хэш-пароли в 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=
 */

Ответ 7

PBKDF2

В примере в http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx, когда вы попадаете в строку" Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes (pwd1, salt1, myIterations); ", k1 - хэш. Примером для шифрования является то, что Rfc2898DeriveBytes изначально был предназначен для создания ключей шифрования.

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

В соответствии с OWASP (https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2) базовое использование SHA1 с помощью Rfc2898DeriveBytes означает, что он хорош только для хэшей до 160 бит в длина. Если вы создаете более длинный хэширование, злоумышленнику по-прежнему приходится беспокоиться только о первых 160 бит, но вы сделали более правдоподобным для вас хеширование/аутентификацию паролей без усиления.

Вот пример кода для хэширования паролей Rfc2898DeriveBytes (сохранение хэша, соли и итераций в БД):

public class Rfc2898PasswordEncoder
{
    private int _byteLength = 160 / 8; // 160 bit hash length

    public class EncodedPassword
    {
        public byte[] Hash { get; set; }
        public byte[] Salt { get; set; }
        public int Iterations { get; set; }
    }

    public EncodedPassword EncodePassword(string password, int iterations)
    {
        var populatedPassword = new EncodedPassword
        {
            Salt = CreateSalt(),
            Iterations = iterations
        };

        // Add Hash
        populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);

        return populatedPassword;
    }

    public bool ValidatePassword(string password, EncodedPassword encodedPassword)
    {
        // Create Hash
        var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);

        return testHash == encodedPassword.Hash;
    }

    public byte[] CreateSalt()
    {
        var salt = new byte[_byteLength]; // Salt should be same length as hash

        using (var saltGenerator = new RNGCryptoServiceProvider())
        {
            saltGenerator.GetBytes(salt);
        }

        return salt;
    }

    private byte[] CreateHash(string password, byte[] salt, long iterations)
    {
        byte[] hash;
        using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
        {
            hash = hashGenerator.GetBytes(_byteLength);
        }

        return hash;
    }
} 

Ответ 8

меня интересовали ответы, в которых не было никаких библиотек.

Я прочитал эту статью https://crackstation.net/hashing-security.htm, которая связывает реализацию на разных языках С#, среди которых я тоже буду ссылаться здесь

https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs

Интересно, что он использует Rfc2898DeriveBytes, как упоминалось здесь несколько раз.

private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes){
    using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt)) {
        pbkdf2.IterationCount = iterations;
        return pbkdf2.GetBytes(outputBytes);
    }
}

Ответ 9

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

Не используйте сторонние пакеты и непроверенные компоненты OSS или любой другой код, который вы только что скопировали из Интернета.

Для .NET используйте PBKDF2, а не bCrypt, потому что нет сертифицированной реализации bCrypt для .NET

Я не имею в виду неуважение к любым благородным разработчикам с открытым исходным кодом (я сам являюсь им), но вы никогда не можете быть уверены, что их сайт не будет взломан через 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
}

Если вам нужно строковое представление хеша (не байтового массива) - вы можете использовать этот класс сверхбыстрого преобразования из этого ответа fooobar.com/info/10949/...