Хэш и соль пароли в C #


178

Я только что просматривал одну из статей Дэвида Хейдена о хешировании паролей пользователей .

На самом деле я не могу получить то, что он пытается достичь.

Вот его код:

private static string CreateSalt(int size)
{
    //Generate a cryptographic random number.
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] buff = new byte[size];
    rng.GetBytes(buff);

    // Return a Base64 string representation of the random number.
    return Convert.ToBase64String(buff);
}

private static string CreatePasswordHash(string pwd, string salt)
{
    string saltAndPwd = String.Concat(pwd, salt);
    string hashedPwd =
        FormsAuthentication.HashPasswordForStoringInConfigFile(
        saltAndPwd, "sha1");
    return hashedPwd;
}

Есть ли другой метод C # для хеширования паролей и добавления соли к нему?


Вот библиотека, которая выполняет хеширование с солью encrypto.codeplex.com
Omu

6
Что вы должны передать для размера в первом методе для создания соли?
Шейн Леблан

6
Ссылка не работает.
osmanraifgunes

@ShaneLeBlanc Вы должны как минимум столько же бит, сколько имеет выходы функции. SHA1это не криптографический класс, поэтому вы должны по крайней мере использовать SHA256, который выводит 256 бит или 32 байта. НО 256 бит НЕ легко конвертируются в base 64, потому что каждый символ base64 кодирует 6 бит, а 256 не делится полностью на 6. Таким образом, вам нужен общий знаменатель 6 (для base64) и 8 (для бит в байте) более 256 бит, что составляет 264 байта или 33 байта. TLDR: использовать 33.
VSO

Ответы:


248

На самом деле это довольно странно с преобразованиями строк - которые провайдер членства делает, чтобы поместить их в конфигурационные файлы. Хэши и соли - это двоичные двоичные объекты, вам не нужно преобразовывать их в строки, если вы не хотите помещать их в текстовые файлы.

В моей книге « Начало безопасности ASP.NET» (о, наконец, оправдание для того, чтобы подтолкнуть книгу) я делаю следующее

static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
  HashAlgorithm algorithm = new SHA256Managed();

  byte[] plainTextWithSaltBytes = 
    new byte[plainText.Length + salt.Length];

  for (int i = 0; i < plainText.Length; i++)
  {
    plainTextWithSaltBytes[i] = plainText[i];
  }
  for (int i = 0; i < salt.Length; i++)
  {
    plainTextWithSaltBytes[plainText.Length + i] = salt[i];
  }

  return algorithm.ComputeHash(plainTextWithSaltBytes);            
}

Образование соли является примером в этом вопросе. Вы можете конвертировать текст в байтовые массивы, используя Encoding.UTF8.GetBytes(string). Если вам необходимо преобразовать хеш в его строковое представление, вы можете использовать его Convert.ToBase64Stringи Convert.FromBase64Stringдля обратного преобразования.

Вы должны заметить, что вы не можете использовать оператор равенства в байтовых массивах, он проверяет ссылки, и поэтому вы должны просто пройти через оба массива, проверяя каждый байт таким образом

public static bool CompareByteArrays(byte[] array1, byte[] array2)
{
  if (array1.Length != array2.Length)
  {
    return false;
  }

  for (int i = 0; i < array1.Length; i++)
  {
    if (array1[i] != array2[i])
    {
      return false;
    }
  }

  return true;
}

Всегда используйте новую соль для каждого пароля. Соли не должны храниться в секрете и могут храниться вместе с самим хешем.


3
Спасибо за этот совет - действительно помог мне начать. Я также натолкнулся на эту ссылку < dijksterhuis.org/creating-salted-hash-values-in-c >, которую я нашел, был хорошим практическим советом и отражает большую часть того, что было сказано в этом посте
Alex P

18
отличный рефакторинг операторов LINQ для CompareByteArraysreturn array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
охотник

6
@Brettski Технически, да, но наличие уникальной соли для каждого пользователя делает Rainbow Tables (общепринятым как наиболее эффективный способ взлома хешированных паролей) практически бесполезным. Это быстрый обзор дает подробный, но не исчерпывающий обзор того, как надежно хранить пароли и почему / как все это работает.
Рейнджер

3
@hunter: вы должны добавить .ToList (), чтобы сделать его постоянным. Например: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); Иначе, LINQ вернется, как только найдет один байт, который не равен.
Алекс Руайяр

17
-1 для использования быстрой хэш-функции. Используйте медленную конструкцию, такую ​​как PBKDF2, bcrypt или scrypt.
CodesInChaos

48

Что сказал Blowdart, но с немного меньшим количеством кода. Используйте Linq или CopyToдля объединения массивов.

public static byte[] Hash(string value, byte[] salt)
{
    return Hash(Encoding.UTF8.GetBytes(value), salt);
}

public static byte[] Hash(byte[] value, byte[] salt)
{
    byte[] saltedValue = value.Concat(salt).ToArray();
    // Alternatively use CopyTo.
    //var saltedValue = new byte[value.Length + salt.Length];
    //value.CopyTo(saltedValue, 0);
    //salt.CopyTo(saltedValue, value.Length);

    return new SHA256Managed().ComputeHash(saltedValue);
}

У Linq также есть простой способ сравнить ваши байтовые массивы.

public bool ConfirmPassword(string password)
{
    byte[] passwordHash = Hash(password, _passwordSalt);

    return _passwordHash.SequenceEqual(passwordHash);
}

Однако, прежде чем реализовывать что-либо из этого, проверьте этот пост . Для хеширования пароля вам может понадобиться медленный алгоритм хеширования, а не быстрый.

Для этого существует Rfc2898DeriveBytesкласс, который работает медленно (и его можно сделать медленнее) и может ответить на вторую часть исходного вопроса в том смысле, что он может взять пароль и соль и вернуть хеш. Смотрите этот вопрос для получения дополнительной информации. Обратите внимание, Stack Exchange используетRfc2898DeriveBytes для хеширования паролей (исходный код здесь ).


6
@MushinNoShin SHA256 - быстрый хеш. Хеширование паролей требует медленного хеширования, такого как PBKDF2, bcrypt или scrypt. См. Как надежно хешировать пароли? на security.se для деталей.
CodesInChaos

32

Я читал, что такие функции хеширования, как SHA256, не были предназначены для хранения паролей: https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

Вместо этого были использованы адаптивные функции вывода ключей, такие как PBKDF2, bcrypt или scrypt. Вот основанный на PBKDF2 файл, который Microsoft написала для PasswordHasher в своей библиотеке Microsoft.AspNet.Identity:

/* =======================
 * HASHED PASSWORD FORMATS
 * =======================
 * 
 * Version 3:
 * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
 * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
 * (All UInt32s are stored big-endian.)
 */

public string HashPassword(string password)
{
    var prf = KeyDerivationPrf.HMACSHA256;
    var rng = RandomNumberGenerator.Create();
    const int iterCount = 10000;
    const int saltSize = 128 / 8;
    const int numBytesRequested = 256 / 8;

    // Produce a version 3 (see comment above) text hash.
    var salt = new byte[saltSize];
    rng.GetBytes(salt);
    var subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

    var outputBytes = new byte[13 + salt.Length + subkey.Length];
    outputBytes[0] = 0x01; // format marker
    WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
    WriteNetworkByteOrder(outputBytes, 5, iterCount);
    WriteNetworkByteOrder(outputBytes, 9, saltSize);
    Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
    Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
    return Convert.ToBase64String(outputBytes);
}

public bool VerifyHashedPassword(string hashedPassword, string providedPassword)
{
    var decodedHashedPassword = Convert.FromBase64String(hashedPassword);

    // Wrong version
    if (decodedHashedPassword[0] != 0x01)
        return false;

    // Read header information
    var prf = (KeyDerivationPrf)ReadNetworkByteOrder(decodedHashedPassword, 1);
    var iterCount = (int)ReadNetworkByteOrder(decodedHashedPassword, 5);
    var saltLength = (int)ReadNetworkByteOrder(decodedHashedPassword, 9);

    // Read the salt: must be >= 128 bits
    if (saltLength < 128 / 8)
    {
        return false;
    }
    var salt = new byte[saltLength];
    Buffer.BlockCopy(decodedHashedPassword, 13, salt, 0, salt.Length);

    // Read the subkey (the rest of the payload): must be >= 128 bits
    var subkeyLength = decodedHashedPassword.Length - 13 - salt.Length;
    if (subkeyLength < 128 / 8)
    {
        return false;
    }
    var expectedSubkey = new byte[subkeyLength];
    Buffer.BlockCopy(decodedHashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

    // Hash the incoming password and verify it
    var actualSubkey = KeyDerivation.Pbkdf2(providedPassword, salt, prf, iterCount, subkeyLength);
    return actualSubkey.SequenceEqual(expectedSubkey);
}

private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value)
{
    buffer[offset + 0] = (byte)(value >> 24);
    buffer[offset + 1] = (byte)(value >> 16);
    buffer[offset + 2] = (byte)(value >> 8);
    buffer[offset + 3] = (byte)(value >> 0);
}

private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
{
    return ((uint)(buffer[offset + 0]) << 24)
        | ((uint)(buffer[offset + 1]) << 16)
        | ((uint)(buffer[offset + 2]) << 8)
        | ((uint)(buffer[offset + 3]));
}

Обратите внимание, что для этого требуется установленный пакет nuget Microsoft.AspNetCore.Cryptography.KeyDerivation , для которого требуется .NET Standard 2.0 (.NET 4.6.1 или выше). Для более ранних версий .NET см. Crypto Класс из библиотеки Microsoft System.Web.Helpers от Microsoft.

Обновление: ноябрь 2015 г.
Обновленный ответ для использования реализации из другой библиотеки Microsoft, в которой вместо PBKDF2-HMAC-SHA1 используется хеширование PBKDF2-HMAC-SHA1 (обратите внимание, что PBKDF2-HMAC-SHA1 по- прежнему безопасен, если iterCount достаточно высок). Вы можете проверить источник, из которого был скопирован упрощенный код, так как он фактически обрабатывает проверку и обновление хэшей, реализованных из предыдущего ответа, что полезно, если вам нужно увеличить iterCount в будущем.


1
Обратите внимание, что, возможно, стоит увеличить PBKDF2IterCount до более высокого значения, подробнее см. Security.stackexchange.com/q/3959 .
Майкл

2
1) Уменьшить PBKDF2SubkeyLengthдо 20 байт. Это естественный размер SHA1 и увеличение его сверх того, что замедляет защитника, не замедляя атакующего. 2) Я рекомендую увеличить количество итераций. Я рекомендую от 10 000 до 100 000 в зависимости от вашего бюджета производительности. 3) Сравнение с постоянным временем также не повредит, но не оказывает большого практического влияния.
CodesInChaos

KeyDerivationPrf, KeyDerivation и BlockCopy не определены, каковы их классы?
mrbengi

@mrbengi Вы установили упомянутый пакет Nuget Microsoft.AspNet.Cryptography.KeyDerivation? Если это не подходит, вот версия, которая не требует пакета nuget. Buffer.BlockCopy должен существовать, он является частью системы.
Майкл

1
Пакет nuget теперь называется Microsoft.AspNetCore.Cryptography.KeyDerivation.
Джеймс Блейк

25

Соль используется для добавления дополнительного уровня сложности к хешу, чтобы сделать его более сложным для взлома.

Из статьи на Sitepoint :

Хакер все еще может выполнить то, что называется атакой по словарю. Злоумышленники могут осуществить словарную атаку, взяв, например, 100 000 паролей, которые, как они знают, люди часто используют (например, названия городов, спортивные команды и т. Д.), Хешируют их, а затем сравнивают каждую запись в словаре с каждой строкой в ​​базе данных. стол. Если хакеры найдут совпадение, бинго! У них есть ваш пароль. Однако для решения этой проблемы нам нужно только посолить хеш.

Чтобы засолить хеш, мы просто придумали произвольно выглядящую строку текста, объединили ее с паролем, предоставленным пользователем, а затем хешировали случайно сгенерированную строку и пароль вместе в одно значение. Затем мы сохраняем и хэш, и соль как отдельные поля в таблице Users.

В этом сценарии хакеру нужно будет не только угадать пароль, но и соль. Добавление соли в открытый текст повышает безопасность: теперь, если хакер пытается атаковать по словарю, он должен хешировать свои 100 000 записей с солью каждой строки пользователя. Хотя это все еще возможно, шансы на успех взлома радикально уменьшаются.

В .NET нет метода, автоматически делающего это, поэтому вам придется воспользоваться решением выше.


Соли используются для защиты от таких вещей, как радужные столы. Для защиты от атак по словарю требуется рабочий фактор (также известный как растяжение ключа), как и любой хороший KDF: en.wikipedia.org/wiki/Key_stretching
Эрван Легран

11

Я создал класс, который имеет следующий метод:

  1. Создать соль
  2. Хеширование
  3. Подтвердить ввод

    public class CryptographyProcessor
    {
        public string CreateSalt(int size)
        {
            //Generate a cryptographic random number.
              RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
             byte[] buff = new byte[size];
             rng.GetBytes(buff);
             return Convert.ToBase64String(buff);
        }
    
    
          public string GenerateHash(string input, string salt)
          { 
             byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
             SHA256Managed sHA256ManagedString = new SHA256Managed();
             byte[] hash = sHA256ManagedString.ComputeHash(bytes);
             return Convert.ToBase64String(hash);
          }
    
          public bool AreEqual(string plainTextInput, string hashedInput, string salt)
          {
               string newHashedPin = GenerateHash(plainTextInput, salt);
               return newHashedPin.Equals(hashedInput); 
          }
     }

    `



3

Я сделал библиотеку SimpleHashing.Net, чтобы облегчить процесс хеширования с помощью базовых классов, предоставляемых Microsoft. Обычного SHA на самом деле недостаточно для безопасного хранения паролей.

В библиотеке используется идея формата хэша от Bcrypt, но, поскольку нет официальной реализации MS, я предпочитаю использовать то, что доступно в фреймворке (например, PBKDF2), но это слишком сложно из коробки.

Это быстрый пример использования библиотеки:

ISimpleHash simpleHash = new SimpleHash();

// Creating a user hash, hashedPassword can be stored in a database
// hashedPassword contains the number of iterations and salt inside it similar to bcrypt format
string hashedPassword = simpleHash.Compute("Password123");

// Validating user's password by first loading it from database by username
string storedHash = _repository.GetUserPasswordHash(username);
isPasswordValid = simpleHash.Verify("Password123", storedHash);

2

Вот как я это делаю .. Я создаю хэш и сохраняю его с помощью ProtectedDataAPI:

    public static string GenerateKeyHash(string Password)
    {
        if (string.IsNullOrEmpty(Password)) return null;
        if (Password.Length < 1) return null;

        byte[] salt = new byte[20];
        byte[] key = new byte[20];
        byte[] ret = new byte[40];

        try
        {
            using (RNGCryptoServiceProvider randomBytes = new RNGCryptoServiceProvider())
            {
                randomBytes.GetBytes(salt);

                using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000))
                {
                    key = hashBytes.GetBytes(20);
                    Buffer.BlockCopy(salt, 0, ret, 0, 20);
                    Buffer.BlockCopy(key, 0, ret, 20, 20);
                }
            }
            // returns salt/key pair
            return Convert.ToBase64String(ret);
        }
        finally
        {
            if (salt != null)
                Array.Clear(salt, 0, salt.Length);
            if (key != null)
                Array.Clear(key, 0, key.Length);
            if (ret != null)
                Array.Clear(ret, 0, ret.Length);
        } 
    }

    public static bool ComparePasswords(string PasswordHash, string Password)
    {
        if (string.IsNullOrEmpty(PasswordHash) || string.IsNullOrEmpty(Password)) return false;
        if (PasswordHash.Length < 40 || Password.Length < 1) return false;

        byte[] salt = new byte[20];
        byte[] key = new byte[20];
        byte[] hash = Convert.FromBase64String(PasswordHash);

        try
        {
            Buffer.BlockCopy(hash, 0, salt, 0, 20);
            Buffer.BlockCopy(hash, 20, key, 0, 20);

            using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000))
            {
                byte[] newKey = hashBytes.GetBytes(20);

                if (newKey != null)
                    if (newKey.SequenceEqual(key))
                        return true;
            }
            return false;
        }
        finally
        {
            if (salt != null)
                Array.Clear(salt, 0, salt.Length);
            if (key != null)
                Array.Clear(key, 0, key.Length);
            if (hash != null)
                Array.Clear(hash, 0, hash.Length);
        }
    }

    public static byte[] DecryptData(string Data, byte[] Salt)
    {
        if (string.IsNullOrEmpty(Data)) return null;

        byte[] btData = Convert.FromBase64String(Data);

        try
        {
            return ProtectedData.Unprotect(btData, Salt, DataProtectionScope.CurrentUser);
        }
        finally
        {
            if (btData != null)
                Array.Clear(btData, 0, btData.Length);
        }
    }

    public static string EncryptData(byte[] Data, byte[] Salt)
    {
        if (Data == null) return null;
        if (Data.Length < 1) return null;

        byte[] buffer = new byte[Data.Length];

        try
        {
            Buffer.BlockCopy(Data, 0, buffer, 0, Data.Length);
            return System.Convert.ToBase64String(ProtectedData.Protect(buffer, Salt, DataProtectionScope.CurrentUser));
        }
        finally
        {
            if (buffer != null)
                Array.Clear(buffer, 0, buffer.Length);
        }
    }

Как мне это назвать при сохранении и при сравнении позже?
SearchForKnowledge

2

Я прочитал все ответы и думаю, что достаточно, особенно статьи @Michael с медленным хешированием и @CodesInChaos хорошими комментариями, но я решил поделиться своим фрагментом кода для хеширования / проверки, который может быть полезен и не требует [ Microsoft.AspNet.Cryptography .KeyDerivation .

    private static bool SlowEquals(byte[] a, byte[] b)
            {
                uint diff = (uint)a.Length ^ (uint)b.Length;
                for (int i = 0; i < a.Length && i < b.Length; i++)
                    diff |= (uint)(a[i] ^ b[i]);
                return diff == 0;
            }

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

    private static string CreateHash(string value, int salt_bytes, int hash_bytes, int pbkdf2_iterations)
            {
                // Generate a random salt
                RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
                byte[] salt = new byte[salt_bytes];
                csprng.GetBytes(salt);

                // Hash the value and encode the parameters
                byte[] hash = PBKDF2(value, salt, pbkdf2_iterations, hash_bytes);

                //You need to return the salt value too for the validation process
                return Convert.ToBase64String(hash) + ":" + 
                       Convert.ToBase64String(hash);
            }

    private static bool ValidateHash(string pureVal, string saltVal, string hashVal, int pbkdf2_iterations)
            {
                try
                {
                    byte[] salt = Convert.FromBase64String(saltVal);
                    byte[] hash = Convert.FromBase64String(hashVal);

                    byte[] testHash = PBKDF2(pureVal, salt, pbkdf2_iterations, hash.Length);
                    return SlowEquals(hash, testHash);
                }
                catch (Exception ex)
                {
                    return false;
                }
            }

Пожалуйста, обратите внимание на функцию SlowEquals, которая так важна. Наконец, я надеюсь, что это поможет, и, пожалуйста, не стесняйтесь, советуйте мне о лучших подходах.


Вместо того, чтобы создавать занятый цикл, почему бы не поставить искусственную задержку не занятости. например, используя Task.Delay. Это задержит попытку перебора, но не заблокирует активный поток.
19

@gburton Спасибо за ваш совет. Я проверю.
QMaster

В CreateHash есть опечатка: вы используете Convert.ToBase64String (hash) для себя вместо соли. Помимо этого, это хороший ответ, который затрагивает практически все вопросы, поднятые в комментариях к другим ответам.
ZeRemz

2

Используйте System.Web.Helpers.Cryptoпакет NuGet от Microsoft. Это автоматически добавляет соль к хешу.

Вы хэш-пароль, как это: var hash = Crypto.HashPassword("foo");

Вы подтверждаете пароль как это: var verified = Crypto.VerifyHashedPassword(hash, "foo");


1

Если вы не используете ядро ​​asp.net или .net, в проектах> = .Net Standard 2.0 также есть простой способ.

Сначала вы можете установить желаемый размер хеша, соли и номера итерации, который связан с длительностью генерации хеша:

private const int SaltSize = 32;
private const int HashSize = 32;
private const int IterationCount = 10000;

Для генерации хэша и соли пароля вы можете использовать что-то вроде этого:

public static string GeneratePasswordHash(string password, out string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        byte[] saltData = rfc2898DeriveBytes.Salt;
        salt = Convert.ToBase64String(saltData);
        return Convert.ToBase64String(hashData);
    }
}

Чтобы проверить, является ли пароль, введенный пользователем, действительным, вы можете проверить значения в вашей базе данных:

public static bool VerifyPassword(string password, string passwordHash, string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        rfc2898DeriveBytes.Salt = Convert.FromBase64String(salt);
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        return Convert.ToBase64String(hashData) == passwordHash;
    }
}

Следующий модульный тест показывает использование:

string password = "MySecret";

string passwordHash = PasswordHasher.GeneratePasswordHash(password, out string salt);

Assert.True(PasswordHasher.VerifyPassword(password, passwordHash, salt));
Assert.False(PasswordHasher.VerifyPassword(password.ToUpper(), passwordHash, salt));

Microsoft Rfc2898DeriveBytes Source


-1

В ответ на эту часть исходного вопроса «Существует ли какой-либо другой метод C # для хеширования паролей», этого можно добиться с помощью ASP.NET Identity v3.0 https://www.nuget.org/packages/Microsoft.AspNet.Identity. EntityFramework / 3.0.0-RC1-конечная

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Security.Principal;

namespace HashTest{


    class Program
    {
        static void Main(string[] args)
        {

            WindowsIdentity wi = WindowsIdentity.GetCurrent();

            var ph = new PasswordHasher<WindowsIdentity>();

            Console.WriteLine(ph.HashPassword(wi,"test"));

            Console.WriteLine(ph.VerifyHashedPassword(wi,"AQAAAAEAACcQAAAAEA5S5X7dmbx/NzTk6ixCX+bi8zbKqBUjBhID3Dg1teh+TRZMkAy3CZC5yIfbLqwk2A==","test"));

        }
    }


}

-1
 protected void m_GenerateSHA256_Button1_Click(objectSender, EventArgs e)
{
string salt =createSalt(10);
string hashedPassword=GenerateSHA256Hash(m_UserInput_TextBox.Text,Salt);
m_SaltHash_TextBox.Text=Salt;
 m_SaltSHA256Hash_TextBox.Text=hashedPassword;

}
 public string createSalt(int size)
{
 var rng= new System.Security.Cyptography.RNGCyptoServiceProvider();
 var buff= new byte[size];
rng.GetBytes(buff);
 return Convert.ToBase64String(buff);
}


 public string GenerateSHA256Hash(string input,string salt)
{
 byte[]bytes=System.Text.Encoding.UTF8.GetBytes(input+salt);
 new System.Security.Cyptography.SHA256Managed();
 byte[]hash=sha256hashString.ComputedHash(bytes);
 return bytesArrayToHexString(hash);
  }

другой метод - строка password = HashPasswordForStoringInConfigFile (TextBox1.Text, SHA1)
анкуш шукла

-6
create proc [dbo].[hash_pass] @family nvarchar(50), @username nvarchar(50), @pass nvarchar(Max),``` @semat nvarchar(50), @tell nvarchar(50)

as insert into tbl_karbar values (@family,@username,(select HASHBYTES('SHA1' ,@pass)),@semat,@tell)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.