Password hash e salt in C #


178

Stavo solo esaminando uno degli articoli di DavidHayden su Hashing User Password .

Davvero non riesco a ottenere quello che sta cercando di ottenere.

Ecco il suo codice:

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

Esiste un altro metodo C # per eseguire l'hashing delle password e aggiungere sale?


ecco una libreria che esegue l'hashing con salt crittoto.codeplex.com
Omu

6
Cosa dovresti passare per la dimensione nel primo metodo per generare sale?
Shane LeBlanc,

6
Il collegamento è interrotto.
osmanraifgunes,

@ShaneLeBlanc Dovresti almeno tanti bit quanti sono gli output delle funzioni. SHA1non è crittografato, quindi dovresti almeno usarlo SHA256, che genera 256 bit o 32 byte. MA, 256 bit NON è facilmente convertibile in base 64, poiché ogni carattere base64 codifica 6 bit e 256 non è completamente divisibile per 6. Quindi è necessario un denominatore comune di 6 (per base64) e 8 (per bit in un byte) oltre 256 bit, ovvero 264 morsi o 33 byte. TLDR: utilizzare 33.
VSO

Risposte:


248

In realtà questo è un po 'strano, con le conversioni di stringa - che il provider di appartenenza fa per metterle in file di configurazione. Hash e sali sono BLOB binari, non è necessario convertirli in stringhe a meno che non si desideri inserirli in file di testo.

Nel mio libro, Beginning ASP.NET Security , (oh finalmente, una scusa per magnaccia il libro) Faccio quanto segue

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

La generazione di sale è come esempio nella domanda. È possibile convertire il testo in array di byte utilizzando Encoding.UTF8.GetBytes(string). Se devi convertire un hash nella sua rappresentazione di stringa, puoi usarlo Convert.ToBase64Stringe Convert.FromBase64Stringriconvertirlo.

Si noti che non è possibile utilizzare l'operatore di uguaglianza su array di byte, controlla i riferimenti e quindi è sufficiente passare in rassegna entrambi gli array controllando così ogni byte

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

Usa sempre un nuovo sale per password. I sali non devono essere tenuti segreti e possono essere conservati insieme all'hash stesso.


3
Grazie per questo consiglio - mi ha davvero aiutato a iniziare. Mi sono anche imbattuto in questo link < dijksterhuis.org/creating-salted-hash-values-in-c > che ho trovato un buon consiglio pratico e rispecchia molto di ciò che è stato detto in questo post
Alex P

18
nifty refactor statement LINQ per CompareByteArrays return array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
cacciatore

6
@Brettski Tecnicamente sì, ma avere un sale unico per ogni utente rende le tabelle Rainbow (generalmente accettate come il modo più efficiente per decifrare le password con hash) praticamente inutili. Questa rapida panoramica fornisce una panoramica approfondita ma non schiacciante di come archiviare le password in modo sicuro e perché / come funziona.
Ranger,

3
@hunter: dovresti aggiungere un .ToList () per renderlo a tempo costante. ad es .: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); Altrimenti, LINQ tornerà non appena trova un byte che non è uguale.
Alex Rouillard,

17
-1 per l'utilizzo di una funzione hash veloce. Usa una costruzione lenta come PBKDF2, bcrypt o scrypt.
CodesInChaos

48

Cosa ha detto Blowdart, ma con un po 'meno codice. Utilizzare Linq o CopyToper concatenare le matrici.

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 ha anche un modo semplice per confrontare i tuoi array di byte.

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

    return _passwordHash.SequenceEqual(passwordHash);
}

Prima di implementare uno di questi, consulta questo post . Per l'hash della password potresti volere un algoritmo di hash lento, non veloce.

A tal fine c'è la Rfc2898DeriveBytesclasse che è lenta (e può essere resa più lenta) e può rispondere alla seconda parte della domanda originale in quanto può prendere una password e salt e restituire un hash. Vedi questa domanda per maggiori informazioni. Nota: Stack Exchange sta usandoRfc2898DeriveBytes per l'hash della password ( qui il codice sorgente ).


6
@MushinNoShin SHA256 è un hash veloce. L'hash delle password richiede un hash lento, come PBKDF2, bcrypt o scrypt. Vedi Come eseguire l'hashing sicuro delle password? su security.se per i dettagli.
CodesInChaos,

32

Ho letto che le funzioni di hashing come SHA256 non erano realmente destinate all'uso con la memorizzazione di password: https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

Invece erano le funzioni di derivazione chiave adattativa come PBKDF2, bcrypt o scrypt. Ecco uno basato su PBKDF2 che Microsoft ha scritto per PasswordHasher nella loro libreria 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]));
}

Nota che questo richiede il pacchetto nuget Microsoft.AspNetCore.Cryptography.KeyDerivation installato che richiede .NET Standard 2.0 (.NET 4.6.1 o successivo). Per le versioni precedenti di .NET, consultare la classe Crypto dalla libreria System.Web.Helpers di Microsoft.

Aggiornamento Nov 2015
Risposta aggiornata per utilizzare un'implementazione da un'altra libreria Microsoft che utilizza l'hash PBKDF2-HMAC-SHA256 anziché l'hashing PBKDF2-HMAC-SHA1 (notare che PBKDF2-HMAC-SHA1 è ancora sicuro se iterCount è abbastanza alto). Puoi controllare l' origine da cui è stato copiato il codice semplificato poiché gestisce effettivamente la convalida e l'aggiornamento degli hash implementati dalla risposta precedente, utile se è necessario aumentare iterCount in futuro.


1
Nota che forse vale la pena aumentare PBKDF2IterCount a un numero più alto, vedi security.stackexchange.com/q/3959 per ulteriori informazioni.
Michael,

2
1) Ridurre PBKDF2SubkeyLengtha 20 byte. Questa è la dimensione naturale di SHA1 e aumentarla oltre ciò rallenta il difensore senza rallentare l'attaccante. 2) Consiglio di aumentare il conteggio delle iterazioni. Raccomando da 10k a 100k a seconda del budget prestazionale. 3) Un confronto costante dei tempi non farebbe male, ma non ha un grande impatto pratico.
Codici A Caos

KeyDerivationPrf, KeyDerivation e BlockCopy non sono definiti, quali sono le loro classi?
Mrbengi,

@mrbengi Hai installato il pacchetto nuget Microsoft.AspNet.Cryptography.KeyDerivation menzionato? Se questo non è adatto, ecco una versione che non richiede il pacchetto nuget. Buffer.BlockCopy dovrebbe esistere fa parte del sistema.
Michael

1
Il pacchetto nuget è ora Microsoft.AspNetCore.Cryptography.KeyDerivation.
James Blake,

25

Il sale viene utilizzato per aggiungere un ulteriore livello di complessità all'hash, per rendere più difficile il crack con forza bruta.

Da un articolo su Sitepoint :

Un hacker può comunque eseguire quello che viene chiamato un attacco da dizionario. Le parti dannose possono attaccare il dizionario prendendo, ad esempio, 100.000 password che sanno che le persone usano frequentemente (ad esempio nomi di città, squadre sportive, ecc.), Li hash e quindi confrontano ogni voce nel dizionario con ogni riga del database tavolo. Se gli hacker trovano una corrispondenza, bingo! Hanno la tua password. Per risolvere questo problema, tuttavia, dobbiamo solo salare l'hash.

Per salare un hash, creiamo semplicemente una stringa di testo dall'aspetto casuale, lo concateniamo con la password fornita dall'utente, quindi hash insieme la stringa e la password generate casualmente insieme come un valore. Quindi salviamo sia l'hash che il salt come campi separati nella tabella Users.

In questo scenario, non solo un hacker dovrebbe indovinare la password, ma dovrebbe anche indovinare il sale. L'aggiunta di salt al testo chiaro migliora la sicurezza: ora, se un hacker tenta un attacco con un dizionario, deve eseguire l'hash delle sue 100.000 voci con il sale di ogni riga dell'utente. Sebbene sia ancora possibile, le possibilità di hackerare il successo diminuiscono radicalmente.

Non esiste alcun metodo per farlo automaticamente in .NET, quindi dovrai andare con la soluzione sopra.


I sali sono usati per difendersi da cose come i tavoli arcobaleno. Per difendersi dagli attacchi dei dizionari è necessario un fattore di lavoro (noto anche come key stretching) come ogni buon KDF: en.wikipedia.org/wiki/Key_stretching
Erwan Legrand

11

Ho creato una classe che ha il seguente metodo:

  1. Crea sale
  2. Hash Input
  3. Convalida input

    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

Ho creato una libreria SimpleHashing.Net per semplificare il processo di hash con le classi di base fornite da Microsoft. SHA ordinario non è abbastanza per archiviare le password in modo sicuro.

La libreria usa l'idea del formato hash di Bcrypt, ma poiché non esiste un'implementazione ufficiale di MS, preferisco usare ciò che è disponibile nel framework (cioè PBKDF2), ma è un po 'troppo difficile.

Questo è un breve esempio di come usare la libreria:

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

Ecco come lo faccio .. Creo l'hash e lo memorizzo usando l' 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);
        }
    }

Come chiamarlo durante il salvataggio e quando si confronta in seguito?
SearchForKnowledge

2

Ho letto tutte le risposte e penso che quelli abbastanza, specialmente @ Michael articoli con lenti hashing e @CodesInChaos buoni commenti, ma ho deciso di condividere il mio frammento di codice per l'hash / Convalida che può essere utile e non richiede [ 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;
                }
            }

Prestare attenzione alla funzione SlowEquals che è così importante, infine, spero che questo aiuto e non esitate a consigliarmi su approcci migliori.


Invece di creare un circuito occupato, perché non mettere un ritardo artificiale non occupato. ad es. usando Task.Delay. Ciò ritarderà un tentativo di forza bruta ma non bloccherà il thread attivo.
Gburton,

@gburton Grazie per il tuo consiglio. Lo controllerò.
QMaster

C'è un errore di battitura in CreateHash: stai concanettando Convert.ToBase64String (hash) su se stesso invece che salt. A parte questo, questa è una bella risposta che risolve praticamente ogni problema sollevato nei commenti su altre risposte.
ZeRemz,

2

Utilizzare il System.Web.Helpers.Cryptopacchetto NuGet di Microsoft. Aggiunge automaticamente sale all'hash.

Hai una password come questa: var hash = Crypto.HashPassword("foo");

Verifica una password come questa: var verified = Crypto.VerifyHashedPassword(hash, "foo");


1

Se non usi asp.net o .net core c'è anche un modo semplice nei progetti> = .Net Standard 2.0.

Per prima cosa puoi impostare la dimensione desiderata di hash, salt e numero di iterazione che è correlato alla durata della generazione dell'hash:

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

Per generare la password hash e salt puoi usare qualcosa del genere:

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

Per verificare se la password immessa dall'utente è valida, è possibile verificare con i valori nel database:

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

Il seguente test unitario mostra l'utilizzo:

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

Origine Microsoft Rfc2898DeriveBytes


-1

In risposta a questa parte della domanda originale "Esiste un altro metodo C # per le password di hashing" È possibile ottenere ciò utilizzando ASP.NET Identity v3.0 https://www.nuget.org/packages/Microsoft.AspNet.Identity. EntityFramework / 3.0.0-rc1-finale

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

l'altro metodo è stringa password = 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.