Паролі хешу та солі в C #


178

Я щойно переглядав одну зі статей DavidHayden про Hashing User Passwords .

Дійсно, я не можу отримати те, що він намагається досягти.

Ось його код:

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
Ому,

6
Що слід вказати для розміру в першому методі для отримання солі?
Шейн ЛеБлан

6
Посилання розірвано.
osmanraifgunes

@ShaneLeBlanc Ви повинні принаймні стільки бітів, скільки має функція виходів. SHA1не є криптовалютою, тому ви повинні принаймні використовувати SHA256, яка видає 256 біт або 32 байти. АЛЕ, 256 біт НЕ легко конвертується в базу 64, тому що кожен base64 char кодує 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 для CompareByteArrays return 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]));
}

Зауважте, для цього потрібен пакунок Microsoft.AspNetCore.Cryptography.KeyDerivation, для якого потрібен .NET Standard 2.0 (.NET 4.6.1 або вище). Для більш ранніх версій .NET див. Клас Crypto з бібліотеки System.Web.Helpers від Microsoft.

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


1
Зверніть увагу, що, можливо, варто збільшити PBKDF2IterCount на більшу кількість, див. Security.stackexchange.com/q/3959 для отримання додаткової інформації.
Майкл

2
1) Зменшіть PBKDF2SubkeyLengthдо 20 байт. Це натуральний розмір f SHA1, а його збільшення за те, що уповільнює захисника, не уповільнюючи нападника. 2) Я рекомендую збільшити кількість ітерацій. Я рекомендую від 10 до 100 тис., Залежно від вашого бюджету. 3) Постійне порівняння часу також не зашкодить, але не має особливого практичного впливу.
CodesInChaos

KeyDerivationPrf, KeyDerivation та BlockCopy не визначено, які їх класи?
mrbengi

@mrbengi Ви встановили згаданий нульовий пакет Microsoft.AspNet.Cryptography.KeyDerivation? Якщо це не підходить тут версія , яка не вимагає пакета NuGet. Buffer.BlockCopy повинен існувати, це частина системи.
Майкл

1
У пакеті nuget тепер Microsoft.AspNetCore.Cryptography.KeyDerivation.
Джеймс Блейк

25

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

З статті про Sitepoint :

Хакер все ще може виконувати те, що називається словниковою атакою. Зловмисні учасники можуть здійснити атаку на словник, взявши, наприклад, 100 000 паролів, які вони знають, люди часто використовують (наприклад, назви міст, спортивні команди тощо), хеш-пам'ять, а потім порівнюють кожен запис у словнику з кожним рядком у базі даних стіл. Якщо хакери знайдуть збіг, бінго! У них є ваш пароль. Однак для вирішення цієї проблеми нам потрібно лише солити хеш.

Щоб солити хеш, ми просто придумуємо текстовий рядок, який виглядає випадковим чином, з'єднуємо його з паролем, наданим користувачем, а потім з’єднуємо обидва випадково створені рядки та пароль разом як одне значення. Потім ми зберігаємо і хеш, і сіль як окремі поля в таблиці користувачів.

У цьому сценарії не тільки хакеру потрібно було б вгадати пароль, вони також мали б вгадати сіль. Додавання солі до прозорого тексту покращує безпеку: тепер, якщо хакер спробує атаку на словник, він повинен хешировать свої 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. Це затримає грубу спробу, але не блокує активну нитку.
gburton

@gburton Дякую за пораду. Я це перевірю.
QMaster

У CreateHash є помилка друку: ви зводить Convert.ToBase64String (хеш) до себе замість солі. Крім цього, це приємна відповідь, яка стосується майже кожного питання, порушеного в коментарях до інших відповідей.
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


-1

У відповідь на цю частину оригінального запитання "Чи є інший метод C # для хешування паролів" Ви можете досягти цього за допомогою ASP.NET Identity v3.0 https://www.nuget.org/packages/Microsoft.AspNet.Identity. EntityFramework / 3.0.0-rc1-final

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);
  }

інший метод - рядок пароля = HashPasswordForStoringInConfigFile (TextBox1.Text, SHA1)
ankush shukla

-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.