Hasła i hasła w C #

178

Właśnie przeglądałem jeden z artykułów DavidaHaydena na temat Hashing User Passwords .

Naprawdę nie mogę dostać tego, co on chce osiągnąć.

Oto jego kod:

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

Czy istnieje inna metoda C # do mieszania haseł i dodawania do nich soli?

ACP
źródło
tutaj jest biblioteka, która robi haszowanie solą encrypto.codeplex.com
Omu
6
Co powinieneś przekazać dla wielkości w pierwszej metodzie generowania soli?
Shane LeBlanc
6
Link jest zepsuty.
osmanraifgunes
@ShaneLeBlanc Powinieneś mieć co najmniej tyle bitów, ile ma wyjść funkcji. SHA1nie jest klasy kryptograficznej, więc powinieneś przynajmniej użyć SHA256, która wyprowadza 256 bitów lub 32 bajty. ALE 256 bitów NIE można łatwo przekonwertować na bazę 64, ponieważ każdy znak base64 koduje 6 bitów, a 256 nie można podzielić w całości przez 6. Zatem potrzebujesz wspólnego mianownika 6 (dla base64) i 8 (dla bitów w bajcie) ponad 256 bitów, co oznacza 264 bitów lub 33 bajty. TLDR: Użyj 33.
VSO

Odpowiedzi:

248

W rzeczywistości jest to trochę dziwne, z konwersjami ciągów - które dostawca członkostwa robi, aby umieścić je w plikach konfiguracyjnych. Skróty i sole są binarnymi blokami BLOB, nie trzeba konwertować ich na ciągi, chyba że chcesz umieścić je w plikach tekstowych.

W mojej książce „ Beginning ASP.NET Security” (och, wreszcie pretekst do zepsucia książki) wykonuję następujące czynności

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

Wytwarzanie soli jest przykładem tego pytania. Możesz przekonwertować tekst na tablice bajtów za pomocą Encoding.UTF8.GetBytes(string). Jeśli musisz przekonwertować skrót na jego ciąg znaków, możesz go użyć Convert.ToBase64Stringi Convert.FromBase64Stringprzekonwertować z powrotem.

Należy zauważyć, że nie można używać operatora równości na tablicach bajtów, sprawdza on referencje, dlatego należy po prostu zapętlić obie tablice sprawdzając każdy bajt w ten sposób

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

Zawsze używaj nowej soli na hasło. Sole nie muszą być trzymane w tajemnicy i mogą być przechowywane obok samego skrótu.

strzałka do dmuchawki
źródło
3
Dzięki za tę radę - naprawdę pomogło mi zacząć. Natknąłem się również na ten link < dijksterhuis.org/creating-salted-hash-values-in-c >, który okazał się dobrą praktyczną radą i odzwierciedla wiele z tego, co zostało powiedziane w tym poście
Alex P
18
niezły refaktor instrukcji LINQ dla CompareByteArraysreturn array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
łowca
6
@Brettski Technicznie tak, ale posiadanie unikalnej soli dla każdego użytkownika sprawia, że ​​Rainbow Tables (ogólnie akceptowane jako najbardziej efektywny sposób łamania zaszyfrowanych haseł) są praktycznie bezużyteczne. To krótkie omówienie daje dogłębny, ale nie przytłaczający przegląd bezpiecznego przechowywania haseł i dlaczego / jak to wszystko działa.
Ranger
3
@hunter: należy dodać .ToList (), aby stała się stała. np .: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); W przeciwnym razie LINQ powróci, gdy tylko znajdzie jeden bajt, który nie jest równy.
Alex Rouillard
17
-1 do korzystania z szybkiej funkcji skrótu. Użyj powolnej konstrukcji, takiej jak PBKDF2, bcrypt lub scrypt.
CodesInChaos
48

Co powiedział cios, ale z nieco mniejszym kodem. Użyj Linq lub CopyTodo łączenia tablic.

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 ma również łatwy sposób na porównanie tablic bajtów.

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

    return _passwordHash.SequenceEqual(passwordHash);
}

Zanim jednak wdrożysz którykolwiek z tych elementów, sprawdź ten post . W przypadku mieszania haseł może być potrzebny powolny algorytm mieszania, a nie szybki.

W tym celu istnieje Rfc2898DeriveBytesklasa, która jest powolna (i może być spowolniona) i może odpowiedzieć na drugą część pierwotnego pytania, ponieważ może wziąć hasło i sól i zwrócić skrót. Zobacz to pytanie, aby uzyskać więcej informacji. Uwaga: Stack Exchange używaRfc2898DeriveBytes do mieszania haseł ( tutaj kod źródłowy ).

Adam Boddington
źródło
6
@MushinNoShin SHA256 to szybki skrót. Haszowanie hasła wymaga wolnego hashowania, takiego jak PBKDF2, bcrypt lub scrypt. Zobacz Jak bezpiecznie hashować hasła? na security.se po szczegóły.
CodesInChaos
32

Czytałem, że funkcje mieszające, takie jak SHA256, nie były tak naprawdę przeznaczone do przechowywania haseł: https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

Zamiast tego działały funkcje adaptacyjnego pozyskiwania kluczy, takie jak PBKDF2, bcrypt lub scrypt. Oto PBKDF2, który Microsoft napisał dla PasswordHasher w swojej bibliotece 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]));
}

Uwaga: wymaga to zainstalowanego pakietu Microsoft.AspNetCore.Cryptography.KeyDerivation , który wymaga .NET Standard 2.0 (.NET 4.6.1 lub nowszy). W przypadku wcześniejszych wersji .NET zobacz klasę Crypto z biblioteki System.Web.Helpers Microsoftu.

Aktualizacja z listopada 2015 r.
Zaktualizowana odpowiedź w celu użycia implementacji z innej biblioteki Microsoft, która używa mieszania PBKDF2-HMAC-SHA256 zamiast PBKDF2-HMAC-SHA1 (uwaga: PBKDF2-HMAC-SHA1 jest nadal bezpieczny, jeśli iterCount jest wystarczająco wysoki). Możesz sprawdzić źródło, z którego został skopiowany uproszczony kod, ponieważ faktycznie obsługuje sprawdzanie poprawności i aktualizację skrótów zaimplementowanych z poprzedniej odpowiedzi, przydatne, jeśli chcesz zwiększyć iterCount w przyszłości.

Michael
źródło
1
Zauważ, że może warto zwiększyć PBKDF2IterCount do wyższej liczby, więcej informacji na stronie security.stackexchange.com/q/3959 .
Michael,
2
1) Zmniejsz PBKDF2SubkeyLengthdo 20 bajtów. To naturalny rozmiar SHA1, a zwiększenie go poza to spowalnia obrońcę bez spowalniania atakującego. 2) Polecam zwiększenie liczby iteracji. Polecam od 10 do 100 000 w zależności od budżetu na wydajność. 3) Ciągłe porównywanie czasu również nie zaszkodzi, ale nie ma większego praktycznego wpływu.
CodesInChaos
KeyDerivationPrf, KeyDerivation i BlockCopy są niezdefiniowane, jakie są ich klasy?
mrbengi
@mrbengi Czy zainstalowałeś wspomniany pakiet Microsoft.AspNet.Cryptography.KeyDerivation? Jeśli to nie jest odpowiednie , jest to wersja, która nie wymaga pakietu nuget. Buffer.BlockCopy powinien istnieć, jest częścią Systemu.
Michael
1
Pakiet nuget to teraz Microsoft.AspNetCore.Cryptography.KeyDerivation.
James Blake
25

Sól służy do dodawania dodatkowego stopnia złożoności skrótu, aby utrudnić pękanie metodą brute-force.

Z artykułu na temat Sitepoint :

Haker może nadal wykonywać atak słownikowy. Złośliwe strony mogą zaatakować słownik, biorąc na przykład 100 000 haseł, o których wiedzą, że ludzie często je wykorzystują (np. Nazwy miast, drużyny sportowe itp.), Mieszają je, a następnie porównują każdy wpis w słowniku z każdym wierszem w bazie danych stół. Jeśli hakerzy znajdą dopasowanie, bingo! Mają twoje hasło. Aby rozwiązać ten problem, potrzebujemy jednak tylko skrótu.

Aby zasolić skrót, po prostu wymyślamy losowo wyglądający ciąg tekstu, łączymy go z hasłem podanym przez użytkownika, a następnie mieszamy losowo wygenerowany ciąg i hasło jako jedną wartość. Następnie zapisujemy zarówno skrót, jak i sól jako osobne pola w tabeli Użytkownicy.

W tym scenariuszu haker musiałby nie tylko odgadnąć hasło, ale także odgadnąć sól. Dodanie soli do zwykłego tekstu poprawia bezpieczeństwo: teraz, jeśli haker spróbuje zaatakować słownikiem, musi mieszać swoje 100 000 wpisów z solą każdego wiersza użytkownika. Chociaż nadal jest to możliwe, szanse na hakowanie radykalnie się zmniejszają.

Żadna metoda nie robi tego automatycznie w .NET, więc skorzystasz z powyższego rozwiązania.

Seb Nilsson
źródło
Sole służą do obrony przed takimi rzeczami, jak tęczowe stoły. Aby bronić się przed atakami słownikowymi, wymagany jest współczynnik pracy (znany również jako rozciąganie klawiszy), jak każdy dobry KDF: en.wikipedia.org/wiki/Key_stretching
Erwan Legrand
11

Utworzyłem klasę, która ma następującą metodę:

  1. Utwórz sól
  2. Hash Input
  3. Zatwierdź dane wejściowe

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

    `

Bamidele Alegbe
źródło
3

Zrobiłem bibliotekę SimpleHashing.Net, aby ułatwić haszowanie za pomocą podstawowych klas dostarczonych przez Microsoft. Zwykłe SHA nie wystarcza do bezpiecznego przechowywania haseł.

Biblioteka korzysta z pomysłu formatu skrótu z Bcrypt, ale ponieważ nie ma oficjalnej implementacji MS, wolę używać tego, co jest dostępne w ramach (tj. PBKDF2), ale jest to trochę zbyt trudne po wyjęciu z pudełka.

To jest szybki przykład korzystania z biblioteki:

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);
Ilya Chernomordik
źródło
2

Tak to robię. Tworzę skrót i przechowuję go za pomocą ProtectedDatainterfejsu API:

    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);
        }
    }
JGU
źródło
Jak zadzwonić podczas zapisywania i porównywania później?
SearchForKnowledge
2

Czytam wszystkie odpowiedzi i myślę, że wystarczy, szczególnie artykuły @Michael z powolnym haszowaniem i dobre komentarze @CodesInChaos , ale postanowiłem udostępnić mój fragment kodu do haszowania / sprawdzania poprawności, które mogą być przydatne i nie wymagają [ 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;
                }
            }

Proszę zwrócić uwagę na funkcję SlowEquals, która jest tak ważna. Wreszcie, mam nadzieję, że ta pomoc i proszę nie wahaj się doradzić mi o lepszych podejściach.

QMaster
źródło
Zamiast tworzyć pętlę zajętości, dlaczego nie wprowadzić sztucznego opóźnienia braku zajętości. np. za pomocą Task.Delay. Opóźni to próbę użycia siły, ale nie zablokuje aktywnego wątku.
gburton,
@gburton Dzięki za radę. Sprawdzę to.
QMaster
W CreateHash występuje literówka: łączysz Convert.ToBase64String (hash) z samym sobą zamiast z solą. Poza tym, jest to ładna odpowiedź, która dotyczy praktycznie każdego problemu poruszonego w komentarzach do innych odpowiedzi.
ZeRemz
2

Użyj System.Web.Helpers.Cryptopakietu NuGet firmy Microsoft. Automatycznie dodaje sól do mieszania.

Masz hash takie jak to: var hash = Crypto.HashPassword("foo");

Weryfikujesz hasło w ten sposób: var verified = Crypto.VerifyHashedPassword(hash, "foo");

Kai Hartmann
źródło
1

Jeśli nie używasz rdzenia asp.net lub .net, istnieje również prosty sposób w projektach> = .Net Standard 2.0.

Najpierw możesz ustawić żądany rozmiar skrótu, soli i numeru iteracji, który jest związany z czasem trwania generowania skrótu:

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

Aby wygenerować skrót hasła i sól, możesz użyć czegoś takiego:

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

Aby sprawdzić, czy hasło wprowadzone przez użytkownika jest prawidłowe, możesz sprawdzić wartości w bazie danych:

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

Poniższy test jednostkowy pokazuje użycie:

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

eugstman
źródło
-1

W odpowiedzi na tę część pierwotnego pytania „Czy istnieje inna metoda C # do mieszania haseł” Można to osiągnąć za pomocą 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"));

        }
    }


}
Dave Cornall
źródło
-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);
  }
ankush shukla
źródło
inną metodą jest ciąg hasło = 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)
ehsan
źródło