with salted password hashed generate encrypt and c# hash passwords salt

salted - Contraseñas hash y salt en C#



password salt generator (10)

Así es como lo hago ... Creo el hash y lo almaceno usando la API ProtectedData :

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

Estaba repasando uno de los artículos de DavidHayden sobre contraseñas de usuario Hashing.

Realmente no puedo entender lo que él 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 cifrar contraseñas y agregarle sal?



En realidad, esto es un poco extraño, con las conversiones de cadenas, que el proveedor de membresía hace para ponerlas en los 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, por fin, una excusa para proxeneta del 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 utilizando Encoding.UTF8.GetBytes(string) . Si debe convertir un hash a su representación de cadena, puede usar Convert.ToBase64String y Convert.FromBase64String para convertirlo.

Debe tener en cuenta que no puede usar el operador de igualdad en las matrices de bytes, verifica las referencias y, por lo tanto, simplemente debe recorrer ambas matrices comprobando cada 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; }

Use siempre una sal nueva por contraseña. Las sales no tienen que mantenerse en secreto y se pueden almacenar junto con el hash.


En respuesta a esta parte de la pregunta original "¿Hay algún otro método 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")); } } }


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

La biblioteca usa la idea del formato hash de Bcrypt, pero como no existe una implementación oficial de MS, prefiero usar lo que está disponible en el framework (es decir, PBKDF2), pero es un poco 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);


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

En cambio, las funciones de derivación de clave adaptativa como PBKDF2, bcrypt o scrypt sí lo fueron. 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 Microsoft.AspNet.Cryptography.KeyDerivation nuget paquete instalado que requiere .NET 4.5.1 o superior. Para versiones anteriores de .NET, vea la clase Crypto de la biblioteca System.Web.Helpers de Microsoft.

Actualización nov 2015
Respuesta actualizada para usar una implementación de una biblioteca diferente de Microsoft que usa hash PBKDF2-HMAC-SHA256 en lugar de PBKDF2-HMAC-SHA1 (la nota PBKDF2-HMAC-SHA1 sigue siendo segura si iterCount es suficientemente alto). Puede verificar la PasswordHasher la cual se copió el código simplificado, ya que en realidad maneja la validación y actualización de los hashes implementados a partir de la respuesta anterior, lo cual es útil si necesita aumentar iterCount en el futuro.


La sal se usa para agregar un nivel extra de complejidad al hash, para hacer más difícil el crack de fuerza bruta.

De un artículo en Sitepoint :

Un hacker aún puede realizar lo que se llama un ataque de diccionario. Las partes malintencionadas pueden atacar un diccionario tomando, por ejemplo, 100.000 contraseñas que conocen personas que usan con frecuencia (nombres de ciudades, equipos deportivos, etc.), hash y luego comparar cada entrada del diccionario con cada fila en la base de datos. mesa. Si los piratas informáticos encuentran una coincidencia, ¡bingo! Ellos tienen tu contraseña Para resolver este problema, sin embargo, solo necesitamos sal el hash.

Para obtener un hash, simplemente encontramos una cadena de texto de aspecto aleatorio, lo concatenamos con la contraseña proporcionada por el usuario y luego combinamos la cadena y la contraseña generadas aleatoriamente como un solo valor. Luego guardamos tanto el hash como el salt como campos separados dentro de la tabla Usuarios.

En este escenario, un hacker no solo tendría que 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 hash sus 100.000 entradas con la sal de cada fila de usuarios. Aunque todavía es posible, las posibilidades de piratear el éxito 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.


Lo que dijo blowdart, pero con un poco menos de código. Use Linq o CopyTo para 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 tus matrices de bytes.

public bool ConfirmPassword(string password) { byte[] passwordHash = Hash(password, _passwordSalt); return _passwordHash.SequenceEqual(passwordHash); }

Antes de implementar cualquiera de estos sin embargo, revisa esta publicación . Para el hash de contraseñas, puede querer un algoritmo hash lento, no uno rápido.

Para ello existe la clase Rfc2898DeriveBytes que es lenta (y puede hacerse más lenta), y puede responder a la segunda parte de la pregunta original, ya 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á utilizando Rfc2898DeriveBytes para el hash de la contraseña (código fuente here ).


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


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)