Related
I am trying to decrypt a ciphersaber encrypted hexadecimal message using an IV mixing round of 20 with the key MyKey.
The messages is:
bad85d9e7f5aff959b6b332b44af2cc554d8a6eb
I am doing this in pure C# and it should return the message: Hola Mundo
using System;
using System.Text;
public class Program
{
public static void Main(string[] args)
{
// Hexadecimal text
string hexText = "bad85d9e7f5aff959b6b332b44af2cc554d8a6eb";
// Convert hexadecimal text to byte array
byte[] encryptedData = new byte[hexText.Length / 2];
for (int i = 0; i < encryptedData.Length; i++)
{
encryptedData[i] = Convert.ToByte(hexText.Substring(i * 2, 2), 16);
}
// IV length
int ivLength = 1;
// Key loop iterations
int keyIterations = 20;
// Encryption key
string encryptionKey = "MyKey";
// Convert encryption key to byte array
byte[] keyData = Encoding.UTF8.GetBytes(encryptionKey);
// Create an array to store the IV
byte[] ivData = new byte[ivLength];
// Copy the first `ivLength` bytes of the encrypted data to the IV array
Array.Copy(encryptedData, 0, ivData, 0, ivLength);
// Create an array to store the encrypted message
byte[] messageData = new byte[encryptedData.Length - ivLength];
// Copy the remaining bytes of the encrypted data to the message data array
Array.Copy(encryptedData, ivLength, messageData, 0, messageData.Length);
// Create an array to store the decrypted message
byte[] decryptedData = new byte[messageData.Length];
// Perform the decryption
for (int i = 0; i < messageData.Length; i++)
{
decryptedData[i] = (byte)(messageData[i] ^ keyData[i % keyData.Length]);
for (int j = 0; j < keyIterations; j++)
{
decryptedData[i] = (byte)(decryptedData[i] ^ ivData[j % ivData.Length]);
}
}
// Convert the decrypted data to a string and print it
string decryptedMessage = Encoding.UTF8.GetString(decryptedData);
Console.WriteLine("Decrypted message: " + decryptedMessage);
}
}
Now when I try it returns: �$�#���Jf=�I���
What mistake am I making in the code or am I implementing it wrong?
I tested the text with the following site to see if it was ok: https://ruletheweb.co.uk/cgi-bin/saber.cgi
CipherSaber uses as IV the first 10 bytes of the encrypted message. The rest is the actual ciphertext. The IV is appended to the key (giving the key setup input), which is used as input to the CipherSaber key setup, see CipherSaber, Technical description, 1st section.
In the posted code, an IV length of 1 is applied instead of 10, which incorrectly determines IV (and thus key setup input) and actual ciphertext. The correct determination of IV and actual ciphertext is:
private static (byte[], byte[]) SeparateIvCiphertext(byte[] ivCiphertext)
{
int ivLen = 10;
byte[] iv = new byte[ivLen];
Buffer.BlockCopy(ivCiphertext, 0, iv, 0, iv.Length);
byte[] ciphertext = new byte[ivCiphertext.Length - iv.Length];
Buffer.BlockCopy(ivCiphertext, iv.Length, ciphertext, 0, ciphertext.Length);
return (iv, ciphertext);
}
and of the key setup input:
private static byte[] GetKeySetupInput(byte[] key, byte[] iv)
{
byte[] keySetupInput = new byte[key.Length + iv.Length];
Buffer.BlockCopy(key, 0, keySetupInput, 0, key.Length);
Buffer.BlockCopy(iv, 0, keySetupInput, key.Length, iv.Length);
return keySetupInput;
}
Furthermore, the decryption itself seems to be implemented incorrectly or at least incompletely. CipherSaber uses RC4 as its encryption/decryption algorithm, which can be divided into a key setup and the actual encryption/decryption:
The referenced website performs decryption using CipherSaber-2. Compared to the original CipherSaber (referred to as CipherSaber-1), a modified key setup is used in which the CipherSaber-1/RC4 key setup is repeated multiple times, 20 times in the case of the posted data.
A description of the CipherSaber-1/RC4 key setup can be found here, Key-scheduling algorithm (KSA), a possible implementation for CipherSaber-2 is:
private static byte[] sBox = new byte[256];
private static void KeySetup(byte[] input, int iterations)
{
for (int i = 0; i < 256; i++)
{
sBox[i] = (byte)i;
}
int j = 0;
for (int cs2loop = 0; cs2loop < iterations; cs2loop++) // CipherSaber-2 modification
{
for (int i = 0; i < 256; i++)
{
j = (j + sBox[i] + input[i % input.Length]) % 256;
Swap(ref sBox[i], ref sBox[j]);
}
}
}
private static void Swap(ref byte val1, ref byte val2)
{
if (val1 == val2) return;
val1 = (byte)(val1 ^ val2);
val2 = (byte)(val2 ^ val1);
val1 = (byte)(val1 ^ val2);
}
The loop marked CipherSaber-2 modification in the code snippet is the modification compared to CipherSaber-1/RC4!
The actual encryption/decryption is described here, Pseudo-random generation algorithm (PRGA), a possible implememtation is:
private static byte[] Process(byte[] input)
{
int i = 0, j = 0;
byte[] result = new byte[input.Length];
for (int k = 0; k < input.Length; k++)
{
i = (i + 1) % 256;
j = (j + sBox[i]) % 256;
Swap(ref sBox[i], ref sBox[j]);
result[k] = (byte)(sBox[(sBox[i] + sBox[j]) % 256] ^ input[k]);
}
return result;
}
Note that this algorithm is used for both encryption and decryption.
With this, the posted encrypted message can be decrypted as follows:
using System;
using System.Text;
...
byte[] key = Encoding.UTF8.GetBytes("MyKey");
byte[] encryptedData = Convert.FromHexString("bad85d9e7f5aff959b6b332b44af2cc554d8a6eb");
(byte[] iv, byte[] ciphertext) = SeparateIvCiphertext(encryptedData);
byte[] keySetupInput = GetKeySetupInput(key, iv);
int iterations = 20;
KeySetup(keySetupInput, iterations);
byte[] plaintext = Process(ciphertext);
Console.WriteLine(Encoding.UTF8.GetString(plaintext)); // Hola Mundo
which gives Hola Mundo as plaintext.
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 have a project where I have been given a MD5 hash of a number between 1 and 2 billion, and I have to write a distributed program which obtains the number by brute force. I have successfully coded this program and it works. I was wondering if there is a way to speed up the generation of hashes?
Here is my current function to generate the hashes:
static string generateHash(string input)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
Thanks for any help
You could use BitConverter.ToString
static string generateHash(string input)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
return BitConverter.ToString(data);
}
Guys, I'm trying to implement a PBKDF2 function in C# that creates a WPA Shared key. I've found some here: http://msdn.microsoft.com/en-us/magazine/cc163913.aspx that seems to produce a valid result, but it's one byte too short... and the wrong PSK value.
To test the output, I am comparing it to this: http://www.xs4all.nl/~rjoris/wpapsk.html or http://anandam.name/pbkdf2/
I did find one way of getting this to work with a built in library to C# called Rfc2898DeriveBytes. Using this, I get a valid output using:
Rfc2898DeriveBytes k3 = new Rfc2898DeriveBytes(pwd1, salt1, 4096);
byte[] answers = k3.GetBytes(32);
Now, the one limitation I have using Rfc2898DeriveBytes is the "salt" must be 8 octets long. If it is shorter, the Rfc2898DeriveBytes throws an exception. I was thinking all I had to do was pad the salt (if it was shorter) to 8 bytes, and I'd be good. But NO! I've tried pretty much every combination of padding with a shorter salt, but I cannot duplicate the results I get from those two websites above.
So bottom line is, does this mean the Rfc2898DeriveBytes just simply won't work with a source salt shorter than 8 bytes? If so, does anyone know of any C# code I could use that implements PBKDF2 for WPA Preshared key?
Here is an implementation that does not require the 8 byte salt.
You can calculate a WPA key as follows:
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes(name), 4096);
key = rfc2898.GetBytes(32);
public class Rfc2898DeriveBytes : DeriveBytes
{
const int BlockSize = 20;
uint block;
byte[] buffer;
int endIndex;
readonly HMACSHA1 hmacsha1;
uint iterations;
byte[] salt;
int startIndex;
public Rfc2898DeriveBytes(string password, int saltSize)
: this(password, saltSize, 1000)
{
}
public Rfc2898DeriveBytes(string password, byte[] salt)
: this(password, salt, 1000)
{
}
public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
{
if (saltSize < 0)
{
throw new ArgumentOutOfRangeException("saltSize");
}
byte[] data = new byte[saltSize];
new RNGCryptoServiceProvider().GetBytes(data);
Salt = data;
IterationCount = iterations;
hmacsha1 = new HMACSHA1(new UTF8Encoding(false).GetBytes(password));
Initialize();
}
public Rfc2898DeriveBytes(string password, byte[] salt, int iterations) : this(new UTF8Encoding(false).GetBytes(password), salt, iterations)
{
}
public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
{
Salt = salt;
IterationCount = iterations;
hmacsha1 = new HMACSHA1(password);
Initialize();
}
static byte[] Int(uint i)
{
byte[] bytes = BitConverter.GetBytes(i);
byte[] buffer2 = new byte[] {bytes[3], bytes[2], bytes[1], bytes[0]};
if (!BitConverter.IsLittleEndian)
{
return bytes;
}
return buffer2;
}
byte[] DeriveKey()
{
byte[] inputBuffer = Int(block);
hmacsha1.TransformBlock(salt, 0, salt.Length, salt, 0);
hmacsha1.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
byte[] hash = hmacsha1.Hash;
hmacsha1.Initialize();
byte[] buffer3 = hash;
for (int i = 2; i <= iterations; i++)
{
hash = hmacsha1.ComputeHash(hash);
for (int j = 0; j < BlockSize; j++)
{
buffer3[j] = (byte) (buffer3[j] ^ hash[j]);
}
}
block++;
return buffer3;
}
public override byte[] GetBytes(int bytesToGet)
{
if (bytesToGet <= 0)
{
throw new ArgumentOutOfRangeException("bytesToGet");
}
byte[] dst = new byte[bytesToGet];
int dstOffset = 0;
int count = endIndex - startIndex;
if (count > 0)
{
if (bytesToGet < count)
{
Buffer.BlockCopy(buffer, startIndex, dst, 0, bytesToGet);
startIndex += bytesToGet;
return dst;
}
Buffer.BlockCopy(buffer, startIndex, dst, 0, count);
startIndex = endIndex = 0;
dstOffset += count;
}
while (dstOffset < bytesToGet)
{
byte[] src = DeriveKey();
int num3 = bytesToGet - dstOffset;
if (num3 > BlockSize)
{
Buffer.BlockCopy(src, 0, dst, dstOffset, BlockSize);
dstOffset += BlockSize;
}
else
{
Buffer.BlockCopy(src, 0, dst, dstOffset, num3);
dstOffset += num3;
Buffer.BlockCopy(src, num3, buffer, startIndex, BlockSize - num3);
endIndex += BlockSize - num3;
return dst;
}
}
return dst;
}
void Initialize()
{
if (buffer != null)
{
Array.Clear(buffer, 0, buffer.Length);
}
buffer = new byte[BlockSize];
block = 1;
startIndex = endIndex = 0;
}
public override void Reset()
{
Initialize();
}
public int IterationCount
{
get
{
return (int) iterations;
}
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException("value");
}
iterations = (uint) value;
Initialize();
}
}
public byte[] Salt
{
get
{
return (byte[]) salt.Clone();
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
salt = (byte[]) value.Clone();
Initialize();
}
}
}
I get matching results when comparing key-derivation from .NET's Rfc2898DeriveBytes and Anandam's PBKDF2 Javascript implementation.
I put together an example of packaging SlowAES and Anandam's PBKDF2 into Windows Script Components. Using this implementation shows good interop with the .NET RijndaelManaged class and the Rfc2898DeriveBytes class.
See also:
AES in Javascript
Getting SlowAES and RijndaelManaged to play together
All of these go further than what you are asking for. They all show interop of the AES encryption. But to get interop on encryption, it is a necessary pre-requisite to have interop (or matching outputs) on the password-based key derivation.
Looking at the Microsoft link, I made some changes in order to make the PMK the same as those discovered in the links you put forward.
Change the SHA algorithm from SHA256Managed to SHA1Managed for the inner and outer hash.
Change HASH_SIZE_IN_BYTES to equal 20 rather than 34.
This produces the correct WPA key.
I know it's a bit late coming, but I've only just started looking for this sort of informatin and thought I could help others out. If anyone does read this post, any ideas on the PRF function and how to do it within C#?
This expands on Dodgyrabbit's answer and his code helped to fix mine as I developed this. This generic class can use any HMAC-derived class in C#. This is .NET 4 because of the parameters with default values, but if those were changed then this should work down to .NET 2, but I haven't tested that. USE AT YOUR OWN RISK.
I have also posted this on my blog, The Albequerque Left Turn, today.
using System;
using System.Text;
using System.Security.Cryptography;
namespace System.Security.Cryptography
{
//Generic PBKDF2 Class that can use any HMAC algorithm derived from the
// System.Security.Cryptography.HMAC abstract class
// PER SPEC RFC2898 with help from user Dodgyrabbit on StackExchange
// http://stackoverflow.com/questions/1046599/pbkdf2-implementation-in-c-sharp-with-rfc2898derivebytes
// the use of default values for parameters in the functions puts this at .NET 4
// if you remove those defaults and create the required constructors, you should be able to drop to .NET 2
// USE AT YOUR OWN RISK! I HAVE TESTED THIS AGAINST PUBLIC TEST VECTORS, BUT YOU SHOULD
// HAVE YOUR CODE PEER-REVIEWED AND SHOULD FOLLOW BEST PRACTICES WHEN USING CRYPTO-ANYTHING!
// NO WARRANTY IMPLIED OR EXPRESSED, YOU ARE ON YOUR OWN!
// PUBLIC DOMAIN! NO COPYRIGHT INTENDED OR RESERVED!
//constrain T to be any class that derives from HMAC, and that exposes a new() constructor
public class PBKDF2<T>: DeriveBytes where T : HMAC, new()
{
//Internal variables and public properties
private int _blockSize = -1; // the byte width of the output of the HMAC algorithm
byte[] _P = null;
int _C = 0;
private T _hmac;
byte[] _S = null;
// if you called the initializer/constructor specifying a salt size,
// you will need this property to GET the salt after it was created from the crypto rng!
// GET THIS BEFORE CALLING GETBYTES()! OBJECT WILL BE RESET AFTER GETBYTES() AND
// SALT WILL BE LOST!!
public byte[] Salt { get { return (byte[])_S.Clone(); } }
// Constructors
public PBKDF2(string Password, byte[] Salt, int IterationCount = 1000)
{ Initialize(Password, Salt, IterationCount); }
public PBKDF2(byte[] Password, byte[] Salt, int IterationCount = 1000)
{ Initialize(Password, Salt, IterationCount); }
public PBKDF2(string Password, int SizeOfSaltInBytes, int IterationCount = 1000)
{ Initialize(Password, SizeOfSaltInBytes, IterationCount);}
public PBKDF2(byte[] Password, int SizeOfSaltInBytes, int IterationCount = 1000)
{ Initialize(Password, SizeOfSaltInBytes, IterationCount);}
//All Construtors call the corresponding Initialize methods
public void Initialize(string Password, byte[] Salt, int IterationCount = 1000)
{
if (string.IsNullOrWhiteSpace(Password))
throw new ArgumentException("Password must contain meaningful characters and not be null.", "Password");
if (IterationCount < 1)
throw new ArgumentOutOfRangeException("IterationCount");
Initialize(new UTF8Encoding(false).GetBytes(Password), Salt, IterationCount);
}
public void Initialize(byte[] Password, byte[] Salt, int IterationCount = 1000)
{
//all Constructors/Initializers eventually lead to this one which does all the "important" work
if (Password == null || Password.Length == 0)
throw new ArgumentException("Password cannot be null or empty.", "Password");
if (Salt == null)
Salt = new byte[0];
if (IterationCount < 1)
throw new ArgumentOutOfRangeException("IterationCount");
_P = (byte[])Password.Clone();
_S = (byte[])Salt.Clone();
_C = IterationCount;
//determine _blockSize
_hmac = new T();
_hmac.Key = new byte[] { 0 };
byte[] test = _hmac.ComputeHash(new byte[] { 0 });
_blockSize = test.Length;
}
public void Initialize(string Password, int SizeOfSaltInBytes, int IterationCount = 1000)
{
if (string.IsNullOrWhiteSpace(Password))
throw new ArgumentException("Password must contain meaningful characters and not be null.", "Password");
if (IterationCount < 1)
throw new ArgumentOutOfRangeException("IterationCount");
Initialize(new UTF8Encoding(false).GetBytes(Password), SizeOfSaltInBytes, IterationCount);
}
public void Initialize(byte[] Password, int SizeOfSaltInBytes, int IterationCount = 1000)
{
if (Password == null || Password.Length == 0)
throw new ArgumentException("Password cannot be null or empty.", "Password");
if (SizeOfSaltInBytes < 0)
throw new ArgumentOutOfRangeException("SizeOfSaltInBytes");
if (IterationCount < 1)
throw new ArgumentOutOfRangeException("IterationCount");
// You didn't specify a salt, so I'm going to create one for you of the specific byte length
byte[] data = new byte[SizeOfSaltInBytes];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(data);
// and then finish initializing...
// Get the salt from the Salt parameter BEFORE calling GetBytes()!!!!!!!!!!!
Initialize(Password, data, IterationCount);
}
~PBKDF2()
{
//*DOOT* clean up in aisle 5! *KEKERKCRACKLE*
this.Reset();
}
// required by the Derive Bytes class/interface
// this is where you request your output bytes after Initialize
// state of class Reset after use!
public override byte[] GetBytes(int ByteCount)
{
if (_S == null || _P == null)
throw new InvalidOperationException("Object not Initialized!");
if (ByteCount < 1)// || ByteCount > uint.MaxValue * blockSize)
throw new ArgumentOutOfRangeException("ByteCount");
int totalBlocks = (int)Math.Ceiling((decimal)ByteCount / _blockSize);
int partialBlock = (int)(ByteCount % _blockSize);
byte[] result = new byte[ByteCount];
byte[] buffer = null;
// I'm using TT here instead of T from the spec because I don't want to confuse it with
// the generic object T
for (int TT = 1; TT <= totalBlocks; TT++)
{
// run the F function with the _C number of iterations for block number TT
buffer = _F((uint)TT);
//IF we're not at the last block requested
//OR the last block requested is whole (not partial)
// then take everything from the result of F for this block number TT
//ELSE only take the needed bytes from F
if (TT != totalBlocks || (TT == totalBlocks && partialBlock == 0))
Buffer.BlockCopy(buffer, 0, result, _blockSize * (TT - 1), _blockSize);
else
Buffer.BlockCopy(buffer, 0, result, _blockSize * (TT - 1), partialBlock);
}
this.Reset(); // force cleanup after every use! Cannot be reused!
return result;
}
// required by the Derive Bytes class/interface
public override void Reset()
{
_C = 0;
_P.Initialize(); // the compiler might optimize this line out! :(
_P = null;
_S.Initialize(); // the compiler might optimize this line out! :(
_S = null;
if (_hmac != null)
_hmac.Clear();
_blockSize = -1;
}
// the core function of the PBKDF which does all the iterations
// per the spec section 5.2 step 3
private byte[] _F(uint I)
{
//NOTE: SPEC IS MISLEADING!!!
//THE HMAC FUNCTIONS ARE KEYED BY THE PASSWORD! NEVER THE SALT!
byte[] bufferU = null;
byte[] bufferOut = null;
byte[] _int = PBKDF2<T>.IntToBytes(I);
_hmac = new T();
_hmac.Key = (_P); // KEY BY THE PASSWORD!
_hmac.TransformBlock(_S, 0, _S.Length, _S, 0);
_hmac.TransformFinalBlock(_int, 0, _int.Length);
bufferU = _hmac.Hash;
bufferOut = (byte[])bufferU.Clone();
for (int c = 1; c < _C; c++)
{
_hmac.Initialize();
_hmac.Key = _P; // KEY BY THE PASSWORD!
bufferU = _hmac.ComputeHash(bufferU);
_Xor(ref bufferOut, bufferU);
}
return bufferOut;
}
// XOR one array of bytes into another (which is passed by reference)
// this is the equiv of data ^= newData;
private void _Xor(ref byte[] data, byte[] newData)
{
for (int i = data.GetLowerBound(0); i <= data.GetUpperBound(0); i++)
data[i] ^= newData[i];
}
// convert an unsigned int into an array of bytes BIG ENDIEN
// per the spec section 5.2 step 3
static internal byte[] IntToBytes(uint i)
{
byte[] bytes = BitConverter.GetBytes(i);
if (!BitConverter.IsLittleEndian)
{
return bytes;
}
else
{
Array.Reverse(bytes);
return bytes;
}
}
}
}