Related
How do I further encrypt a MD5 hash by XOR'ing it with a string of variable size (not bigger than 32 characters) ?
I would like the result of the XOR to be a 32 character string as well.
What i have tried so far is:
convert the md5 string to binary
convert second string to binary
pad second binary with 0's (to the left) until both binaries are of equal length
iterate the binary representations and XOR them
convert the XOR'ed result to a string
The approach may be wrong, im not sure how to do it. My problem is, when converting the result of the XOR, it is not a 32 character long string, as I would like it to be.
Sample code (equal length strings in this case):
class Program
{
static void Main(string[] args)
{
var md51 = ToBinary(ConvertToByteArray(CalculateMD5Hash("Maaa"), Encoding.ASCII));
var md52 = ToBinary(ConvertToByteArray(CalculateMD5Hash("Moo"), Encoding.ASCII));
List<int> xoredResult = new List<int>();
for (int i = 0; i < md51.Length; i++)
{
var string1 = md51[i];
var string2 = md52[i];
var xor = string1 ^ string2;
xoredResult.Add(xor);
}
var resultingString = string.Join("", xoredResult);
Console.WriteLine(resultingString.Length);
var data = GetBytesFromBinaryString(resultingString);
var text = Encoding.ASCII.GetString(data);
}
public static byte[] ConvertToByteArray(string str, Encoding encoding)
{
return encoding.GetBytes(str);
}
public static String ToBinary(Byte[] data)
{
return string.Join("", data.Select(byt => Convert.ToString(byt, 2).PadLeft(8, '0')));
}
public static Byte[] GetBytesFromBinaryString(String binary)
{
var list = new List<Byte>();
for (int i = 0; i < binary.Length; i += 8)
{
String t = binary.Substring(i, 8);
list.Add(Convert.ToByte(t, 2));
}
return list.ToArray();
}
public static string CalculateMD5Hash(string input)
{
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
}
xoring a string with what is essentially random bytes is not guaranteed to give you a valid string as a output. Your var text = Encoding.ASCII.GetString(data); is likely failing because you are passing it a non valid string in byte form. You must use something like var text = Convert.ToBase64String(data) to be able to represent the random data without loss of information in the process.
I was just going through one of DavidHayden's articles on Hashing User Passwords.
Really I can't get what he is trying to achieve.
Here is his code:
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;
}
Is there any other C# method for hashing passwords and adding salt to it?
Actually this is kind of strange, with the string conversions - which the membership provider does to put them into config files. Hashes and salts are binary blobs, you don't need to convert them to strings unless you want to put them into text files.
In my book, Beginning ASP.NET Security, (oh finally, an excuse to pimp the book) I do the following
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);
}
The salt generation is as the example in the question. You can convert text to byte arrays using Encoding.UTF8.GetBytes(string). If you must convert a hash to its string representation you can use Convert.ToBase64String and Convert.FromBase64String to convert it back.
You should note that you cannot use the equality operator on byte arrays, it checks references and so you should simply loop through both arrays checking each byte thus
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;
}
Always use a new salt per password. Salts do not have to be kept secret and can be stored alongside the hash itself.
What blowdart said, but with a little less code. Use Linq or CopyTo to concatenate arrays.
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 has an easy way to compare your byte arrays too.
public bool ConfirmPassword(string password)
{
byte[] passwordHash = Hash(password, _passwordSalt);
return _passwordHash.SequenceEqual(passwordHash);
}
Before implementing any of this however, check out this post. For password hashing you may want a slow hash algorithm, not a fast one.
To that end there is the Rfc2898DeriveBytes class which is slow (and can be made slower), and may answer the second part of the original question in that it can take a password and salt and return a hash. See this question for more information. Note, Stack Exchange is using Rfc2898DeriveBytes for password hashing (source code here).
I've been reading that hashing functions like SHA256 weren't really intended for use with storing passwords:
https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes
Instead adaptive key derivation functions like PBKDF2, bcrypt or scrypt were. Here is a PBKDF2 based one that Microsoft wrote for PasswordHasher in their Microsoft.AspNet.Identity library:
/* =======================
* 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]));
}
Note this requires Microsoft.AspNetCore.Cryptography.KeyDerivation nuget package installed which requires .NET Standard 2.0 (.NET 4.6.1 or higher). For earlier versions of .NET see the Crypto class from Microsoft's System.Web.Helpers library.
Update Nov 2015
Updated answer to use an implementation from a different Microsoft library which uses PBKDF2-HMAC-SHA256 hashing instead of PBKDF2-HMAC-SHA1 (note PBKDF2-HMAC-SHA1 is still secure if iterCount is high enough). You can check out the source the simplified code was copied from as it actually handles validating and upgrading hashes implemented from previous answer, useful if you need to increase iterCount in the future.
Salt is used to add an extra level of complexity to the hash, to make it harder to brute-force crack.
From an article on Sitepoint:
A hacker can still perform
what's called a dictionary attack.
Malicious parties may make a
dictionary attack by taking, for
instance, 100,000 passwords that they
know people use frequently (e.g. city
names, sports teams, etc.), hash them,
and then compare each entry in the
dictionary against each row in the
database table. If the hackers find a
match, bingo! They have your password.
To solve this problem, however, we
need only salt the hash.
To salt a hash, we simply come up with
a random-looking string of text,
concatenate it with the password
supplied by the user, then hash both
the randomly generated string and
password together as one value. We
then save both the hash and the salt
as separate fields within the Users
table.
In this scenario, not only would a
hacker need to guess the password,
they'd have to guess the salt as well.
Adding salt to the clear text improves
security: now, if a hacker tries a
dictionary attack, he must hash his
100,000 entries with the salt of every
user row. Although it's still
possible, the chances of hacking
success diminish radically.
There is no method automatically doing this in .NET, so you'll have go with the solution above.
I created a class that has the following method:
Create Salt
Hash Input
Validate 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);
}
}
Use the System.Web.Helpers.Crypto NuGet package from Microsoft. It automatically adds salt to the hash.
You hash a password like this: var hash = Crypto.HashPassword("foo");
You verify a password like this: var verified = Crypto.VerifyHashedPassword(hash, "foo");
I have made a library SimpleHashing.Net to make the process of hashing easy with basic classes provided by Microsoft. Ordinary SHA is not really enough to have passwords stored securely anymore.
The library use the idea of hash format from Bcrypt, but since there is no official MS implementation I prefer to use what's available in the framework (i.e. PBKDF2), but it's a bit too hard out of the box.
This is a quick example how to use the library:
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);
2022 (.NET 6+) solution:
Most of the other answers here (including the accepted answer) are using the SHA-256 hashing algorithm, which is NOT suited for storing user passwords anymore, even if you use salts. You instead should opt for slower hashing functions for this purpose, such as Bcrypt, Argon2, Scrypt, or PBKDF2; the latter being the only one that's natively available in .NET.
You can find helper methods and whatnot to create PBKDF2 hashes primarily in this other question, but the one I'm providing below has the following advantages over those provided in that question or even some here, such as this one.
Pros:
Uses the new static Rfc2898DeriveBytes.Pbkdf2() method introduced in .NET 6, eliminating the need to instantiate and also dispose the object every single time.
Uses the new RandomNumberGenerator class and its static GetBytes method — introduced in .NET 6 — to generate the salt. The RNGCryptoServiceProvider class used in the original question and many of the answers here is obsolete.
Uses the CryptographicOperations.FixedTimeEquals method (introduced in .NET Core 2.1) for comparing the key bytes in the Verify method, instead of doing the comparison by hand — like the accepted answer is doing. This, in addition to removing a lot of noisy boilerplate, also nullifies timing attacks.
Uses SHA-256 instead of the default SHA-1 as the underlying algorithm, just to be on the safe side, as the latter is a more robust and reliable algorithm.
The string that the Hash method returns (and by extension the string that the Verify method receives) has the following structure:
[key]:[salt]:[iterations]:[algorithm]
This is the most important advantage of this particular solution; this means that we're basically including metadata about the configurations used to create the hash in the final string. This effectively allows us to change the settings (such as the number of iterations, salt/key size, etc.) in our hasher class in the future, without breaking previous hashes created with the old settings. This is something that most of the other solutions I've come across (that are using PBKDF2) tend to neglect and not actually take into account, although it's crucial. They instead typically rely on the current configuration values to verify hashes, which means that as soon as you decide to change any of the configuration values, any previously-created hashes will no longer be verified properly.
Other points:
I'm using the hexadecimal representation of the key and the salt in the returned hash string. You can instead use base64 if you prefer, simply by changing every occurrence of Convert.ToHexString and Convert.FromHexString to Convert.ToBase64 and Convert.FromBase64 respectively. The rest of the logic remains exactly the same.
The often recommended salt size is 64 bits or above. I've set it to 128 bits.
The key size should normally be the same as the natural output size of your chosen algorithm — see this comment. In our case, as I mentioned earlier, the underlying algorithm is SHA-256, whose output size is 256 bits, which is precisely what we're setting our key size to.
If you plan to use this for storing user passwords, it's usually recommended to use at least 10,000 iterations or more. I've set the default value to 50,000, which you can of course change as you see fit.
The code:
public static class SecretHasher
{
private const int _saltSize = 16; // 128 bits
private const int _keySize = 32; // 256 bits
private const int _iterations = 100000;
private static readonly HashAlgorithmName _algorithm = HashAlgorithmName.SHA256;
private const char segmentDelimiter = ':';
public static string Hash(string input)
{
byte[] salt = RandomNumberGenerator.GetBytes(_saltSize);
byte[] hash = Rfc2898DeriveBytes.Pbkdf2(
input,
salt,
_iterations,
_algorithm,
_keySize
);
return string.Join(
segmentDelimiter,
Convert.ToHexString(hash),
Convert.ToHexString(salt),
_iterations,
_algorithm
);
}
public static bool Verify(string input, string hashString)
{
string[] segments = hashString.Split(segmentDelimiter);
byte[] hash = Convert.FromHexString(segments[0]);
byte[] salt = Convert.FromHexString(segments[1]);
int iterations = int.Parse(segments[2]);
HashAlgorithmName algorithm = new HashAlgorithmName(segments[3]);
byte[] inputHash = Rfc2898DeriveBytes.Pbkdf2(
input,
salt,
iterations,
algorithm,
hash.Length
);
return CryptographicOperations.FixedTimeEquals(inputHash, hash);
}
}
Usage:
// Hash:
string password = "...";
string hashed = SecretHasher.Hash(password);
// Verify:
string enteredPassword = "...";
bool isPasswordCorrect = SecretHasher.Verify(enteredPassword, hashed);
Bah, this is better! http://sourceforge.net/projects/pwdtknet/ and it is better because ..... it performs Key Stretching AND uses HMACSHA512 :)
If you dont use asp.net or .net core there is also an easy way in >= .Net Standard 2.0 projects.
First you can set the desired size of the hash, salt and iteration number which is related to the duration of the hash generation:
private const int SaltSize = 32;
private const int HashSize = 32;
private const int IterationCount = 10000;
To generare the password hash and salt you can use something like this:
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);
}
}
To verify if the password which the user entered is valid you can check with the values in your 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;
}
}
The following unit test shows the usage:
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
This is how I do it.. I create the hash and store it using the ProtectedData 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);
}
}
I read all answers and I think those enough, specially #Michael articles with slow hashing and #CodesInChaos good comments, but I decided to share my code snippet for hashing/validating that may be useful and it does not require [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;
}
}
Please pay attention SlowEquals function that is so important, Finally, I hope this help and Please don't hesitate to advise me about better approaches.
I use this in .netcore6
public class Encryption
{
public string CreateSalt(int size)
{
//Generate a cryptographic random number.
byte[] buff = new byte[size];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
public string GenerateHash(string input, string salt)
{
byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
SHA256 sha = SHA256.Create();
byte[] hash = sha.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public bool Equals(string plainTextInput, string hashedInput, string salt)
{
string newHashedPin = GenerateHash(plainTextInput, salt);
return newHashedPin.Equals(hashedInput);
}
}
There are already good answers to the original question, but I would like to add, that the "SequenceEqual" enables the possibility of a timing attack.
The normal way to check for sequences (of bytes) are the same, is to compare every byte in the order with the second one. The first one that is out of order stops the comparison and "false" is returned.
byte[] hash1 = ...
byte[] hash2 = ...
// can be exploited with a timing attack
bool equals = hash1.SequenceEqual(hash2);
With that, an attacker needs 256 strings with every possible starting byte. He runs every string against the mechanism and the one that takes the longest to get a result is the one with the correct first byte. The attack can then be continued in a similar manner on the next byte... and so on.
I found here a better way of doing it, with a nice explanation.
[MethodImpl(MethodImplOptions.NoOptimization)]
private static bool slowEquals(byte[] a, byte[] b)
{
int diff = a.Length ^ b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
In answer to this part of the original question "Is there any other C# method for hashing passwords" You can achieve this using 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"));
}
}
}
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)
I was just going through one of DavidHayden's articles on Hashing User Passwords.
Really I can't get what he is trying to achieve.
Here is his code:
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;
}
Is there any other C# method for hashing passwords and adding salt to it?
Actually this is kind of strange, with the string conversions - which the membership provider does to put them into config files. Hashes and salts are binary blobs, you don't need to convert them to strings unless you want to put them into text files.
In my book, Beginning ASP.NET Security, (oh finally, an excuse to pimp the book) I do the following
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);
}
The salt generation is as the example in the question. You can convert text to byte arrays using Encoding.UTF8.GetBytes(string). If you must convert a hash to its string representation you can use Convert.ToBase64String and Convert.FromBase64String to convert it back.
You should note that you cannot use the equality operator on byte arrays, it checks references and so you should simply loop through both arrays checking each byte thus
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;
}
Always use a new salt per password. Salts do not have to be kept secret and can be stored alongside the hash itself.
What blowdart said, but with a little less code. Use Linq or CopyTo to concatenate arrays.
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 has an easy way to compare your byte arrays too.
public bool ConfirmPassword(string password)
{
byte[] passwordHash = Hash(password, _passwordSalt);
return _passwordHash.SequenceEqual(passwordHash);
}
Before implementing any of this however, check out this post. For password hashing you may want a slow hash algorithm, not a fast one.
To that end there is the Rfc2898DeriveBytes class which is slow (and can be made slower), and may answer the second part of the original question in that it can take a password and salt and return a hash. See this question for more information. Note, Stack Exchange is using Rfc2898DeriveBytes for password hashing (source code here).
I've been reading that hashing functions like SHA256 weren't really intended for use with storing passwords:
https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes
Instead adaptive key derivation functions like PBKDF2, bcrypt or scrypt were. Here is a PBKDF2 based one that Microsoft wrote for PasswordHasher in their Microsoft.AspNet.Identity library:
/* =======================
* 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]));
}
Note this requires Microsoft.AspNetCore.Cryptography.KeyDerivation nuget package installed which requires .NET Standard 2.0 (.NET 4.6.1 or higher). For earlier versions of .NET see the Crypto class from Microsoft's System.Web.Helpers library.
Update Nov 2015
Updated answer to use an implementation from a different Microsoft library which uses PBKDF2-HMAC-SHA256 hashing instead of PBKDF2-HMAC-SHA1 (note PBKDF2-HMAC-SHA1 is still secure if iterCount is high enough). You can check out the source the simplified code was copied from as it actually handles validating and upgrading hashes implemented from previous answer, useful if you need to increase iterCount in the future.
Salt is used to add an extra level of complexity to the hash, to make it harder to brute-force crack.
From an article on Sitepoint:
A hacker can still perform
what's called a dictionary attack.
Malicious parties may make a
dictionary attack by taking, for
instance, 100,000 passwords that they
know people use frequently (e.g. city
names, sports teams, etc.), hash them,
and then compare each entry in the
dictionary against each row in the
database table. If the hackers find a
match, bingo! They have your password.
To solve this problem, however, we
need only salt the hash.
To salt a hash, we simply come up with
a random-looking string of text,
concatenate it with the password
supplied by the user, then hash both
the randomly generated string and
password together as one value. We
then save both the hash and the salt
as separate fields within the Users
table.
In this scenario, not only would a
hacker need to guess the password,
they'd have to guess the salt as well.
Adding salt to the clear text improves
security: now, if a hacker tries a
dictionary attack, he must hash his
100,000 entries with the salt of every
user row. Although it's still
possible, the chances of hacking
success diminish radically.
There is no method automatically doing this in .NET, so you'll have go with the solution above.
I created a class that has the following method:
Create Salt
Hash Input
Validate 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);
}
}
Use the System.Web.Helpers.Crypto NuGet package from Microsoft. It automatically adds salt to the hash.
You hash a password like this: var hash = Crypto.HashPassword("foo");
You verify a password like this: var verified = Crypto.VerifyHashedPassword(hash, "foo");
I have made a library SimpleHashing.Net to make the process of hashing easy with basic classes provided by Microsoft. Ordinary SHA is not really enough to have passwords stored securely anymore.
The library use the idea of hash format from Bcrypt, but since there is no official MS implementation I prefer to use what's available in the framework (i.e. PBKDF2), but it's a bit too hard out of the box.
This is a quick example how to use the library:
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);
2022 (.NET 6+) solution:
Most of the other answers here (including the accepted answer) are using the SHA-256 hashing algorithm, which is NOT suited for storing user passwords anymore, even if you use salts. You instead should opt for slower hashing functions for this purpose, such as Bcrypt, Argon2, Scrypt, or PBKDF2; the latter being the only one that's natively available in .NET.
You can find helper methods and whatnot to create PBKDF2 hashes primarily in this other question, but the one I'm providing below has the following advantages over those provided in that question or even some here, such as this one.
Pros:
Uses the new static Rfc2898DeriveBytes.Pbkdf2() method introduced in .NET 6, eliminating the need to instantiate and also dispose the object every single time.
Uses the new RandomNumberGenerator class and its static GetBytes method — introduced in .NET 6 — to generate the salt. The RNGCryptoServiceProvider class used in the original question and many of the answers here is obsolete.
Uses the CryptographicOperations.FixedTimeEquals method (introduced in .NET Core 2.1) for comparing the key bytes in the Verify method, instead of doing the comparison by hand — like the accepted answer is doing. This, in addition to removing a lot of noisy boilerplate, also nullifies timing attacks.
Uses SHA-256 instead of the default SHA-1 as the underlying algorithm, just to be on the safe side, as the latter is a more robust and reliable algorithm.
The string that the Hash method returns (and by extension the string that the Verify method receives) has the following structure:
[key]:[salt]:[iterations]:[algorithm]
This is the most important advantage of this particular solution; this means that we're basically including metadata about the configurations used to create the hash in the final string. This effectively allows us to change the settings (such as the number of iterations, salt/key size, etc.) in our hasher class in the future, without breaking previous hashes created with the old settings. This is something that most of the other solutions I've come across (that are using PBKDF2) tend to neglect and not actually take into account, although it's crucial. They instead typically rely on the current configuration values to verify hashes, which means that as soon as you decide to change any of the configuration values, any previously-created hashes will no longer be verified properly.
Other points:
I'm using the hexadecimal representation of the key and the salt in the returned hash string. You can instead use base64 if you prefer, simply by changing every occurrence of Convert.ToHexString and Convert.FromHexString to Convert.ToBase64 and Convert.FromBase64 respectively. The rest of the logic remains exactly the same.
The often recommended salt size is 64 bits or above. I've set it to 128 bits.
The key size should normally be the same as the natural output size of your chosen algorithm — see this comment. In our case, as I mentioned earlier, the underlying algorithm is SHA-256, whose output size is 256 bits, which is precisely what we're setting our key size to.
If you plan to use this for storing user passwords, it's usually recommended to use at least 10,000 iterations or more. I've set the default value to 50,000, which you can of course change as you see fit.
The code:
public static class SecretHasher
{
private const int _saltSize = 16; // 128 bits
private const int _keySize = 32; // 256 bits
private const int _iterations = 100000;
private static readonly HashAlgorithmName _algorithm = HashAlgorithmName.SHA256;
private const char segmentDelimiter = ':';
public static string Hash(string input)
{
byte[] salt = RandomNumberGenerator.GetBytes(_saltSize);
byte[] hash = Rfc2898DeriveBytes.Pbkdf2(
input,
salt,
_iterations,
_algorithm,
_keySize
);
return string.Join(
segmentDelimiter,
Convert.ToHexString(hash),
Convert.ToHexString(salt),
_iterations,
_algorithm
);
}
public static bool Verify(string input, string hashString)
{
string[] segments = hashString.Split(segmentDelimiter);
byte[] hash = Convert.FromHexString(segments[0]);
byte[] salt = Convert.FromHexString(segments[1]);
int iterations = int.Parse(segments[2]);
HashAlgorithmName algorithm = new HashAlgorithmName(segments[3]);
byte[] inputHash = Rfc2898DeriveBytes.Pbkdf2(
input,
salt,
iterations,
algorithm,
hash.Length
);
return CryptographicOperations.FixedTimeEquals(inputHash, hash);
}
}
Usage:
// Hash:
string password = "...";
string hashed = SecretHasher.Hash(password);
// Verify:
string enteredPassword = "...";
bool isPasswordCorrect = SecretHasher.Verify(enteredPassword, hashed);
Bah, this is better! http://sourceforge.net/projects/pwdtknet/ and it is better because ..... it performs Key Stretching AND uses HMACSHA512 :)
If you dont use asp.net or .net core there is also an easy way in >= .Net Standard 2.0 projects.
First you can set the desired size of the hash, salt and iteration number which is related to the duration of the hash generation:
private const int SaltSize = 32;
private const int HashSize = 32;
private const int IterationCount = 10000;
To generare the password hash and salt you can use something like this:
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);
}
}
To verify if the password which the user entered is valid you can check with the values in your 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;
}
}
The following unit test shows the usage:
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
This is how I do it.. I create the hash and store it using the ProtectedData 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);
}
}
I read all answers and I think those enough, specially #Michael articles with slow hashing and #CodesInChaos good comments, but I decided to share my code snippet for hashing/validating that may be useful and it does not require [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;
}
}
Please pay attention SlowEquals function that is so important, Finally, I hope this help and Please don't hesitate to advise me about better approaches.
I use this in .netcore6
public class Encryption
{
public string CreateSalt(int size)
{
//Generate a cryptographic random number.
byte[] buff = new byte[size];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
public string GenerateHash(string input, string salt)
{
byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
SHA256 sha = SHA256.Create();
byte[] hash = sha.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public bool Equals(string plainTextInput, string hashedInput, string salt)
{
string newHashedPin = GenerateHash(plainTextInput, salt);
return newHashedPin.Equals(hashedInput);
}
}
There are already good answers to the original question, but I would like to add, that the "SequenceEqual" enables the possibility of a timing attack.
The normal way to check for sequences (of bytes) are the same, is to compare every byte in the order with the second one. The first one that is out of order stops the comparison and "false" is returned.
byte[] hash1 = ...
byte[] hash2 = ...
// can be exploited with a timing attack
bool equals = hash1.SequenceEqual(hash2);
With that, an attacker needs 256 strings with every possible starting byte. He runs every string against the mechanism and the one that takes the longest to get a result is the one with the correct first byte. The attack can then be continued in a similar manner on the next byte... and so on.
I found here a better way of doing it, with a nice explanation.
[MethodImpl(MethodImplOptions.NoOptimization)]
private static bool slowEquals(byte[] a, byte[] b)
{
int diff = a.Length ^ b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
In answer to this part of the original question "Is there any other C# method for hashing passwords" You can achieve this using 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"));
}
}
}
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)
i used this functions to compute the hash value:
public string GetSHA512(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA512 shaM = new SHA512Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetSHA256(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA256 shaM = new SHA256Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetSHA1(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA1 shaM = new SHA1Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetMD5(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (MD5 shaM = new MD5CryptoServiceProvider())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
but now i have few questions:
hash functions are supposed to create the fix output length for any kind of strings.(no matter my input length is 4 or 10000 the output always has a fix size) aren't they? but when my input length changes the output length changes too!! i guess my hash functions doesn't work.
if i want save the result in the database, my hash value filed type should be what?
which one of the hash functions usually used in web applications?
thank you.
Currently you're just returning the decimal representation of all the bytes, concatenated together. So { 0, 0, 0 } ends up as "000" whereas { 123, 123, 123 } ends up as "123123123". So yes, both those hashes will give the same output size for any input (SHA-1 will give 20 bytes; MD5 will give 16) but your string representations will currently vary in length.
I would recommend using either a hex representation or base64 - in particular, base64 requires rather less work:
public string GetSHA1(string input)
{
byte[] data = Encoding.UTF8.GetBytes(input);
using (SHA512 shaM = new SHA512Managed())
{
byte[] result = shaM.ComputeHash(data);
return Convert.ToBase64String(result);
}
}
Hex has the advantage of being a more common way of representing hashes. (Base64 is more usually used for transporting arbitrary binary data, e.g. images.) For hex, you could use:
return BitConverter.ToString(result).Replace("-", "");
(Note that I've declared local variables - you appear to be using fields for data and result, which is a bad idea - calling these methods shouldn't affect the state of the instance, IMO.)
Alternatively, you could just return a byte[] and store that directly in the database as a blob. Using base64 or hex is probably simpler though - it's easier to examine the data that way, and frankly easier to query. Strings are just simpler to handle :)
In terms of which hash you should use - I probably wouldn't use either SHA-1 or MD5 unless I had to; I'd default to SHA-256, although it depends on what you're trying to do. If this is hashing passwords for example, you probably want an HMAC of some description - or better yet, don't roll your own, and use an off-the-shelf authentication package.
Each hash algorithm (md5/sha1/etc) has its own fixed size;
Don't convert the output hash to string, keep it as byte[].
In order to store the hash, create a blob column in your db and use SQLParameter to insert it properly
The common practise is to convert the byte array of the hashcode to a base64 encoding, with ToBase64String()
This is how passwords are stored too. The base64 encoding is a string of fixed length, given a fixed number of bytes. It takes 4 characters for each 3 bytes, plus some padding
Assume that I have a string containing a hex value. For example:
string command "0xABCD1234";
How can I convert that string into another string (for example, string codedString = ...) such that this new string's ASCII-encoded representation has the same binary as the original strings contents?
The reason I need to do this is because I have a library from a hardware manufacturer that can transmit data from their piece of hardware to another piece of hardware over SPI. Their functions take strings as an input, but when I try to send "AA" I am expecting the SPI to transmit the binary 10101010, but instead it transmits the ascii representation of AA which is 0110000101100001.
Also, this hex string is going to be 32 hex characters long (that is, 256-bits long).
string command = "AA";
int num = int.Parse(command,NumberStyles.HexNumber);
string bits = Convert.ToString(num,2); // <-- 10101010
I think I understand what you need... here is the main code part.. asciiStringWithTheRightBytes is what you would send to your command.
var command = "ABCD1234";
var byteCommand = GetBytesFromHexString(command);
var asciiStringWithTheRightBytes = Encoding.ASCII.GetString(byteCommand);
And the subroutines it uses are here...
static byte[] GetBytesFromHexString(string str)
{
byte[] bytes = new byte[str.Length * sizeof(byte)];
for (var i = 0; i < str.Length; i++)
bytes[i] = HexToInt(str[i]);
return bytes;
}
static byte HexToInt(char hexChar)
{
hexChar = char.ToUpper(hexChar); // may not be necessary
return (byte)((int)hexChar < (int)'A' ?
((int)hexChar - (int)'0') :
10 + ((int)hexChar - (int)'A'));
}