Contraseñas de hash y sal en C #


178

Estaba leyendo uno de los artículos de DavidHayden sobre Hashing User Passwords .

Realmente no puedo entender lo que está tratando de lograr.

Aquí está su código:

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

¿Hay algún otro método de C # para cambiar las contraseñas y agregarle sal?


aquí hay una biblioteca que hace el hashing con salt encrypto.codeplex.com
Omu

66
¿Qué debe pasar para el tamaño en el primer método para generar sal?
Shane LeBlanc

66
El enlace está roto.
osmanraifgunes

@ShaneLeBlanc Debería tener al menos tantos bits como salidas de función. SHA1no es de grado criptográfico, por lo que al menos debería usarlo SHA256, que genera 256 bits o 32 bytes. PERO, 256 bits NO es fácilmente convertible a base 64, porque cada carácter base64 codifica 6 bits, y 256 no es divisible por 6. Por lo tanto, necesita un denominador común de 6 (para base64) y 8 (para bits en un byte) más de 256 bits, que son 264 mordidas o 33 bytes. TLDR: uso 33.
VSO

Respuestas:


248

En realidad, esto es un poco extraño, con las conversiones de cadenas, que el proveedor de membresía hace para colocarlas en archivos de configuración. Los hashes y las sales son blobs binarios, no es necesario convertirlos en cadenas a menos que desee colocarlos en archivos de texto.

En mi libro, Beginning ASP.NET Security , (oh, finalmente, una excusa para enredar el libro) hago lo siguiente

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 generación de sal es como el ejemplo en la pregunta. Puede convertir texto en matrices de bytes usando Encoding.UTF8.GetBytes(string). Si debe convertir un hash a su representación de cadena, puede usarlo Convert.ToBase64Stringy Convert.FromBase64Stringvolverlo a convertir.

Debe tener en cuenta que no puede usar el operador de igualdad en las matrices de bytes, comprueba las referencias y, por lo tanto, simplemente debe recorrer ambas matrices comprobando cada byte de esta manera

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

Utilice siempre una nueva sal por contraseña. Las sales no tienen que mantenerse en secreto y pueden almacenarse junto con el hash mismo.


3
Gracias por este consejo, realmente me ayudó a comenzar. También me encontré con este enlace < dijksterhuis.org/creating-salted-hash-values-in-c > que encontré fue un buen consejo práctico y refleja mucho de lo que se dijo en esta publicación
Alex P

18
ingenioso refactor de la declaración LINQ para CompareByteArrays return array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
hunter

66
@Brettski Técnicamente, sí, pero tener una sal única para cada usuario hace que Rainbow Tables (generalmente aceptado como la forma más eficiente de descifrar contraseñas hash) sea prácticamente inútil. Esta es una visión general rápida que ofrece una descripción detallada pero no abrumadora de cómo almacenar las contraseñas de forma segura y por qué / cómo funciona todo.
Guardabosques

3
@hunter: debe agregar un .ToList () para que sea un tiempo constante. por ejemplo: return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); De lo contrario, LINQ volverá tan pronto como encuentre un byte que no sea igual.
Alex Rouillard el

17
-1 para usar una función hash rápida. Use una construcción lenta como PBKDF2, bcrypt o scrypt.
CodesInChaos

48

Lo que dijo Blowdart, pero con un poco menos de código. Use Linq o CopyTopara concatenar matrices.

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 también tiene una manera fácil de comparar sus conjuntos de bytes.

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

    return _passwordHash.SequenceEqual(passwordHash);
}

Sin embargo, antes de implementar algo de esto, mira esta publicación . Para el hash de contraseñas, es posible que desee un algoritmo de hash lento, no uno rápido.

Para ese fin está la Rfc2898DeriveBytesclase que es lenta (y puede hacerse más lenta), y puede responder a la segunda parte de la pregunta original en que puede tomar una contraseña y sal y devolver un hash. Vea esta pregunta para más información. Tenga en cuenta que Stack Exchange está utilizandoRfc2898DeriveBytes para el hash de contraseña (código fuente aquí ).


66
@MushinNoShin SHA256 es un hash rápido. El hash de contraseña necesita un hash lento, como PBKDF2, bcrypt o scrypt. Consulte ¿Cómo hacer un hash seguro de las contraseñas? en security.se para más detalles.
CodesInChaos

32

He estado leyendo que las funciones de hash como SHA256 en realidad no estaban destinadas al uso para almacenar contraseñas: https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

En cambio, las funciones de derivación de teclas adaptativas como PBKDF2, bcrypt o scrypt eran. Aquí hay uno basado en PBKDF2 que Microsoft escribió para PasswordHasher en su 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]));
}

Tenga en cuenta que esto requiere el paquete nuget Microsoft.AspNetCore.Cryptography.KeyDerivation instalado que requiere .NET Standard 2.0 (.NET 4.6.1 o superior). Para versiones anteriores de .NET ver Crypto clase de la biblioteca System.Web.Helpers de Microsoft.

Actualización de noviembre de 2015
Respuesta actualizada para usar una implementación de una biblioteca de Microsoft diferente que utiliza el hashing PBKDF2-HMAC-SHA256 en lugar de PBKDF2-HMAC-SHA1 (tenga en cuenta que PBKDF2-HMAC-SHA1 sigue siendo seguro si iterCount es lo suficientemente alto). Puede consultar la fuente desde la que se copió el código simplificado, ya que en realidad maneja la validación y la actualización de los hash implementados de la respuesta anterior, útil si necesita aumentar iterCount en el futuro.


1
Tenga en cuenta que tal vez valga la pena aumentar PBKDF2IterCount a un número mayor, consulte security.stackexchange.com/q/3959 para obtener más información.
Michael

2
1) Reducir PBKDF2SubkeyLengtha 20 bytes. Ese es el tamaño natural f SHA1 y aumentarlo más allá de eso ralentiza al defensor sin ralentizar al atacante. 2) Recomiendo aumentar el recuento de iteraciones. Recomiendo 10k a 100k dependiendo de su presupuesto de rendimiento. 3) Una comparación de tiempo constante tampoco haría daño, pero no tiene mucho impacto práctico.
CodesInChaos

KeyDerivationPrf, KeyDerivation y BlockCopy no está definido, ¿cuáles son sus clases?
mrbengi

@mrbengi ¿Ha instalado el paquete nuget Microsoft.AspNet.Cryptography.KeyDerivation mencionado? Si eso no es adecuado, aquí hay una versión que no requiere el paquete nuget. Buffer.BlockCopy debería existir, es parte del sistema.
Michael

1
El paquete nuget ahora es Microsoft.AspNetCore.Cryptography.KeyDerivation.
James Blake

25

La sal se usa para agregar un nivel adicional de complejidad al hash, para dificultar el craqueo por fuerza bruta.

De un artículo en Sitepoint :

Un hacker todavía puede realizar lo que se llama un ataque de diccionario. Las partes malintencionadas pueden atacar el diccionario tomando, por ejemplo, 100,000 contraseñas que saben que la gente usa con frecuencia (por ejemplo, nombres de ciudades, equipos deportivos, etc.), descifrarlas y luego comparar cada entrada en el diccionario con cada fila de la base de datos mesa. Si los hackers encuentran una pareja, ¡bingo! Ellos tienen tu contraseña. Sin embargo, para resolver este problema, solo necesitamos salar el hash.

Para obtener un hash, simplemente creamos una cadena de texto de aspecto aleatorio, la concatenamos con la contraseña provista por el usuario, luego juntamos la cadena y la contraseña generadas aleatoriamente como un valor. Luego guardamos tanto el hash como la sal como campos separados dentro de la tabla Usuarios.

En este escenario, un hacker no solo necesitaría adivinar la contraseña, sino que también tendría que adivinar la sal. Agregar sal al texto claro mejora la seguridad: ahora, si un pirata informático intenta un ataque de diccionario, debe mezclar sus 100,000 entradas con la sal de cada fila de usuario. Aunque todavía es posible, las posibilidades de éxito de piratería disminuyen radicalmente.

No hay ningún método que haga esto automáticamente en .NET, por lo que tendrá que ir con la solución anterior.


Las sales se usan para defenderse de cosas como las mesas de arcoiris. Para defenderse de los ataques de diccionario se requiere un factor de trabajo (también conocido como estiramiento de teclas) como cualquier buen KDF: en.wikipedia.org/wiki/Key_stretching
Erwan Legrand

11

Creé una clase que tiene el siguiente método:

  1. Crear sal
  2. Entrada de 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

He creado una biblioteca SimpleHashing.Net para facilitar el proceso de hashing con las clases básicas proporcionadas por Microsoft. SHA ordinario ya no es suficiente para tener las contraseñas almacenadas de forma segura.

La biblioteca usa la idea del formato hash de Bcrypt, pero como no hay una implementación oficial de MS, prefiero usar lo que está disponible en el marco (es decir, PBKDF2), pero es un poco demasiado difícil de usar.

Este es un ejemplo rápido de cómo usar la 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

Así es como lo hago. Creo el hash y lo ProtectedDataalmaceno usando la 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);
        }
    }

¿Cómo lo llamo mientras guardo y cuando comparo más tarde?
SearchForKnowledge

2

Leí todas las respuestas y creo que son suficientes, especialmente los artículos de @Michael con hashing lento y los buenos comentarios de @CodesInChaos , pero decidí compartir mi fragmento de código para el hashing / validación que puede ser útil y no requiere [ 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;
                }
            }

Preste atención a la función SlowEquals que es tan importante. Finalmente, espero que esto ayude y no dude en aconsejarme acerca de mejores enfoques.


En lugar de crear un ciclo ocupado, ¿por qué no poner un retraso artificial no ocupado? por ejemplo, usando Task.Delay. Esto retrasará un intento de fuerza bruta pero no bloqueará el hilo activo.
gburton

@gburton Gracias por tu consejo. Yo lo comprobare.
QMaster

Hay un error tipográfico en CreateHash: estás concatenando Convert.ToBase64String (hash) consigo mismo en lugar de la sal. Aparte de eso, esta es una buena respuesta que aborda casi todos los problemas planteados en los comentarios sobre otras respuestas.
ZeRemz

2

Use el System.Web.Helpers.Cryptopaquete NuGet de Microsoft. Agrega automáticamente sal al hachís.

Hash una contraseña como esta: var hash = Crypto.HashPassword("foo");

Verifica una contraseña como esta: var verified = Crypto.VerifyHashedPassword(hash, "foo");


1

Si no usa asp.net o .net core, también hay una manera fácil en proyectos> = .Net Standard 2.0.

Primero puede establecer el tamaño deseado del hash, sal y número de iteración que está relacionado con la duración de la generación del hash:

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

Para generar la contraseña hash y salt puedes usar algo como esto:

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 si la contraseña que ingresó el usuario es válida, puede verificar los valores en su base de datos:

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

La siguiente prueba unitaria muestra el 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 Source


-1

En respuesta a esta parte de la pregunta original "¿Existe algún otro método de C # para contraseñas hash"? Puede lograr esto usando 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);
  }

otro método es string 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.