Created
January 14, 2012 15:30
-
-
Save rofr/1611793 to your computer and use it in GitHub Desktop.
You're not storing passwords in plain text, right? Here's one way to do it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class User | |
{ | |
public string UserId{ protected get; set; } | |
protected string PasswordHash { get; set; } | |
public void SetPassword(string password) | |
{ | |
PasswordHash = CryptoHelper.CreateHashWithRandomSalt(password); | |
} | |
public bool HasPassword(string password) | |
{ | |
return CryptoHelper.VerifyHash(password, PasswordHash); | |
} | |
} | |
public static class CryptoHelper | |
{ | |
public const byte SaltLength = 8; | |
private static byte[] RandomBytes(int size) | |
{ | |
byte[] result = new byte[size]; | |
RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider(); | |
rnd.GetNonZeroBytes(result); | |
return result; | |
} | |
public static string RandomPassword() | |
{ | |
byte[] randombytes = RandomBytes(8); | |
return Convert.ToBase64String(randombytes); | |
} | |
private static string ComputeHash(string plainText, byte[] salt) | |
{ | |
// Convert plain text into a byte array. | |
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); | |
// Allocate array, which will hold plain text and salt. | |
byte[] plainTextWithSaltBytes = | |
new byte[plainTextBytes.Length + salt.Length]; | |
// Copy plain text bytes into resulting array. | |
plainTextBytes.CopyTo(plainTextWithSaltBytes, 0); | |
// Append salt bytes to the resulting array. | |
salt.CopyTo(plainTextWithSaltBytes, plainTextBytes.Length); | |
HashAlgorithm hasher = new SHA512Managed(); | |
// Compute hash value of our plain text with appended salt. | |
byte[] hashBytes = hasher.ComputeHash(plainTextWithSaltBytes); | |
// Create array which will hold hash and original salt bytes. | |
byte[] hashWithSaltBytes = new byte[hashBytes.Length + | |
salt.Length]; | |
// Copy hash bytes into resulting array. | |
for (int i = 0; i < hashBytes.Length; i++) | |
hashWithSaltBytes[i] = hashBytes[i]; | |
// Append salt bytes to the result. | |
for (int i = 0; i < salt.Length; i++) | |
hashWithSaltBytes[hashBytes.Length + i] = salt[i]; | |
// Convert result into a base64-encoded string. | |
return Convert.ToBase64String(hashWithSaltBytes); | |
} | |
public static string CreateHashWithRandomSalt(string plainText) | |
{ | |
byte[] salt = RandomBytes(SaltLength); | |
return ComputeHash(plainText, salt); | |
} | |
public static bool VerifyHash(string plainText, string hashValue) | |
{ | |
// Convert base64-encoded hash value into a byte array. | |
byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue); | |
int hashSizeInBytes = hashWithSaltBytes.Length - 8; | |
// Allocate array to hold original salt bytes retrieved from hash. | |
byte[] salt = new byte[8]; | |
// Copy salt from the end of the hash to the new array. | |
for (int i = 0; i < salt.Length; i++) | |
salt[i] = hashWithSaltBytes[hashSizeInBytes + i]; | |
// Compute a new hash string. | |
string expectedHashString = | |
ComputeHash(plainText, salt); | |
// If the computed hash matches the specified hash, | |
// the plain text value must be correct. | |
return (hashValue == expectedHashString); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment