Senhas Hash e Salt em C #


178

Eu estava lendo um dos artigos de DavidHayden sobre Hashing User Senhas .

Realmente não consigo o que ele está tentando alcançar.

Aqui está o código dele:

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

Existe algum outro método C # para fazer hash de senhas e adicionar sal a ela?


aqui é uma biblioteca que faz o hash com sal encrypto.codeplex.com
Omu

6
O que você deve passar para o tamanho no primeiro método para gerar sal?
Shane LeBlanc

6
Link quebrado.
Osmanraifgunes

@ShaneLeBlanc Você deve ter pelo menos tantos bits quanto as saídas de função. SHA1não é de nível criptográfico, então você deve pelo menos usar SHA256, que gera 256 bits ou 32 bytes. MAS, 256 bits NÃO são facilmente convertíveis na base 64, porque cada caractere base64 codifica 6 bits e 256 não é totalmente divisível por 6. Portanto, você precisa de um denominador comum de 6 (para base64) e 8 (para bits em um byte) mais de 256 bits, ou seja, 264 picadas ou 33 bytes. TLDR: Use 33.
VSO

Respostas:


248

Na verdade, isso é meio estranho, com as conversões de strings - que o provedor de associação faz para colocá-las em arquivos de configuração. Hashes e sais são blobs binários, você não precisa convertê-los em strings, a menos que queira colocá-los em arquivos de texto.

No meu livro, Beginning ASP.NET Security , (finalmente, uma desculpa para dar uma olhada no livro), faço o seguinte

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

A geração de sal é como o exemplo da pergunta. Você pode converter texto em matrizes de bytes usando Encoding.UTF8.GetBytes(string). Se você precisar converter um hash em sua representação de cadeia, poderá usá-lo Convert.ToBase64Stringe Convert.FromBase64Stringconvertê-lo novamente.

Você deve observar que não pode usar o operador de igualdade em matrizes de bytes, ele verifica as referências e, portanto, basta percorrer as duas matrizes verificando cada byte para

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

Sempre use um novo sal por senha. Os sais não precisam ser mantidos em segredo e podem ser armazenados ao lado do próprio hash.


3
Obrigado por este conselho - realmente me ajudou a começar. Também encontrei este link < dijksterhuis.org/creating-salted-hash-values-in-c > que achei bons conselhos práticos e espelha muito do que foi dito neste post
Alex P

18
refator de instrução LINQ bacana para CompareByteArraysreturn array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
hunter

6
@Brettski Tecnicamente, sim, mas ter um sal único para cada usuário torna o Rainbow Tables (geralmente aceito como a maneira mais eficiente de quebrar senhas com hash) praticamente inútil. Esta é uma rápida visualização rápida que fornece uma visão geral detalhada, mas não esmagadora, de como armazenar senhas com segurança e por que / como tudo funciona.
Ranger

3
@ hunter: você deve adicionar um .ToList () para torná-lo constante. por exemplo: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); Senão, o LINQ retornará assim que encontrar um byte que não seja igual.
Alex Rouillard

17
-1 para usar uma função hash rápida. Use uma construção lenta como PBKDF2, bcrypt ou scrypt.
CodesInChaos

48

O que o blowdart disse, mas com um pouco menos de código. Use Linq ou CopyTopara concatenar matrizes.

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

O Linq também oferece uma maneira fácil de comparar suas matrizes de bytes.

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

    return _passwordHash.SequenceEqual(passwordHash);
}

Antes de implementar isso, no entanto, confira esta postagem . Para hash de senha, convém um algoritmo de hash lento, não rápido.

Para esse fim, há a Rfc2898DeriveBytesclasse que é lenta (e pode ser mais lenta) e pode responder à segunda parte da pergunta original, na medida em que ela pode pegar uma senha e salt e retornar um hash. Veja esta pergunta para mais informações. Observe que o Stack Exchange está usando oRfc2898DeriveBytes hash de senha (código-fonte aqui ).


6
@MushinNoShin SHA256 é um hash rápido. O hash de senha precisa de um hash lento, como PBKDF2, bcrypt ou scrypt. Consulte Como fazer o hash de senhas com segurança? em security.se para obter detalhes.
CodesInChaos 31/07

32

Eu tenho lido que funções de hash como SHA256 não foram realmente destinadas ao uso de senhas de armazenamento: https://patrickmn.com/security/storing-passwords-security/#notpasswordhashes

Em vez disso, funções de derivação de chave adaptáveis ​​como PBKDF2, bcrypt ou scrypt foram. Aqui está um baseado em PBKDF2 que a Microsoft escreveu para PasswordHasher em sua biblioteca 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]));
}

Observe que isso requer o pacote de nuget Microsoft.AspNetCore.Cryptography.KeyDerivation instalado, que requer o .NET Standard 2.0 (.NET 4.6.1 ou superior). Para versões anteriores do .NET, consulte a classe Crypto da biblioteca System.Web.Helpers da Microsoft.

Atualização de novembro de 2015
Resposta atualizada para usar uma implementação de uma biblioteca diferente da Microsoft que usa o hash PBKDF2-HMAC-SHA256 em vez do PBKDF2-HMAC-SHA1 (observe que PBKDF2-HMAC-SHA1 ainda é seguro se iterCount for alto o suficiente). Você pode verificar a origem da qual o código simplificado foi copiado, pois ele lida com a validação e atualização de hashes implementados a partir da resposta anterior, útil se você precisar aumentar o iterCount no futuro.


1
Observe que talvez valha a pena aumentar PBKDF2IterCount para um número maior, consulte security.stackexchange.com/q/3959 para obter mais informações.
6283 Michael

2
1) Reduza PBKDF2SubkeyLengthpara 20 bytes. Esse é o tamanho natural de SHA1 e aumentá-lo além do que desacelera o defensor sem desacelerar o atacante. 2) Eu recomendo aumentar a contagem de iterações. Eu recomendo 10.000 a 100.000, dependendo do seu orçamento de desempenho. 3) Uma comparação de tempo constante também não faria mal, mas não tem muito impacto prático.
CodesInChaos

KeyDerivationPrf, KeyDerivation e BlockCopy não são definidos, quais são as suas classes?
mrbengi

@mrbengi Você instalou o pacote de nuget Microsoft.AspNet.Cryptography.KeyDerivation mencionado? Se isso não for adequado, aqui está uma versão que não requer o pacote nuget. Buffer.BlockCopy deve existir, faz parte do System.
Michael

1
O pacote nuget agora é Microsoft.AspNetCore.Cryptography.KeyDerivation.
James Blake

25

O sal é usado para adicionar um nível extra de complexidade ao hash, para dificultar a trinca por força bruta.

De um artigo no Sitepoint :

Um hacker ainda pode executar o que é chamado de ataque de dicionário. As partes mal-intencionadas podem fazer um ataque ao dicionário, pegando, por exemplo, 100.000 senhas que eles sabem que as pessoas usam com freqüência (por exemplo, nomes de cidades, equipes esportivas etc.), as misturam e depois comparam cada entrada no dicionário com cada linha do banco de dados tabela. Se os hackers encontrarem uma partida, bingo! Eles têm sua senha. Para resolver esse problema, no entanto, precisamos apenas salgar o hash.

Para saltar um hash, simplesmente criamos uma sequência de texto de aparência aleatória, concatenamos com a senha fornecida pelo usuário e, em seguida, misturamos a sequência e a senha geradas aleatoriamente juntas como um valor. Em seguida, salvamos o hash e o sal como campos separados na tabela Usuários.

Nesse cenário, não apenas um hacker precisaria adivinhar a senha, mas também teria que adivinhar o sal. A adição de salt ao texto não criptografado melhora a segurança: agora, se um hacker tenta um ataque de dicionário, ele deve misturar suas 100.000 entradas com o salt de cada linha do usuário. Embora ainda seja possível, as chances de sucesso nos hackers diminuem radicalmente.

Não existe um método para fazer isso automaticamente no .NET, então você terá a solução acima.


Os sais são usados ​​para se defender de coisas como mesas de arco-íris. Para se defender contra ataques de dicionário um fator trabalho (também conhecido como alongamento de chave) é necessária como qualquer bom KDF: en.wikipedia.org/wiki/Key_stretching
Erwan Legrand

11

Eu criei uma classe que tem o seguinte método:

  1. Criar sal
  2. Entrada Hash
  3. Validar entrada

    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

Criei uma biblioteca SimpleHashing.Net para facilitar o processo de hash com as classes básicas fornecidas pela Microsoft. SHA comum não é realmente suficiente para ter senhas armazenadas com segurança.

A biblioteca usa a ideia do formato hash do Bcrypt, mas como não há implementação oficial do MS, prefiro usar o que está disponível na estrutura (por exemplo, PBKDF2), mas é um pouco difícil de usar.

Este é um exemplo rápido de como usar a biblioteca:

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

É assim que faço .. Crio o hash e o armazeno usando a 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);
        }
    }

Como chamá-lo durante o salvamento e quando comparado mais tarde?
SearchForKnowledge

2

Eu li todas as respostas e eu acho que aqueles suficiente, especialmente @ Michael artigos com hashing lento e @CodesInChaos bons comentários, mas eu decidi compartilhar o meu trecho de código para hash / validação de que pode ser útil e não requer [ 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;
                }
            }

Por favor, preste atenção à função SlowEquals que é tão importante. Finalmente, espero que ajude e, por favor, não hesite em me aconselhar sobre melhores abordagens.


Em vez de criar um loop ocupado, por que não colocar um atraso artificial não ocupado. por exemplo, usando Task.Delay. Isso atrasará uma tentativa de força bruta, mas não bloqueará o encadeamento ativo.
gburton

@gburton Obrigado pelo seu conselho. Vou verificar.
Qmaster

Há um erro de digitação no CreateHash: você está concanando Convert.ToBase64String (hash) para si mesmo, em vez do salt. Fora isso, é uma boa resposta que aborda praticamente todas as questões levantadas nos comentários de outras respostas.
ZeRemz 27/03

2

Use o System.Web.Helpers.Cryptopacote NuGet da Microsoft.Ele adiciona automaticamente sal ao hash.

Você hash uma senha como esta: var hash = Crypto.HashPassword("foo");

Você verifica uma senha como esta: var verified = Crypto.VerifyHashedPassword(hash, "foo");


1

Se você não usa o núcleo asp.net ou .net, também há uma maneira fácil em projetos = = .Net Standard 2.0.

Primeiro, você pode definir o tamanho desejado do número de hash, sal e iteração que está relacionado à duração da geração de hash:

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

Para gerar a senha e o sal, você pode usar algo como isto:

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

Para verificar se a senha digitada pelo usuário é válida, verifique os valores em seu banco de dados:

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

O seguinte teste de unidade mostra o uso:

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 Origem


-1

Em resposta a esta parte da pergunta original "Existe algum outro método C # para hash de senhas" Você pode fazer isso usando o 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);
  }

outro método é senha cadeia = 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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.