Just been reading what looks like the second part in a series on security from
Eric Lippert on the use of hashes for
protecting password information (
first part is here) . I find this especially interesting since I've recently designed a system which uses salted-hash (as opposed to sticky-black hash which is a whole different thing ;-)) as a method to protect user passwords. As it turned out it wasn't all that easy to do this in .NET ; of course it might just be me...anyway here's the little function I came up with for hashing passwords (with a dash of salt...)
UPDATE: Simpler version is below with much of the duplication removed - in addition, the defaults are smaller and quicker (16 byte salt and SHA-1 hashing algorithm), you can change either of these - any length of salt and any of the HashAlgorithms (SHA256, MD5, etc...). Hope someone finds it useful... using System;
using System.Security.Cryptography;
using System.Text;
namespace HashMaker
{
public sealed class PasswordHasher
{
private const int DEFAULTBYTECOUNT = 16;
public static string GetRandomString()
{
return Convert.ToBase64String(GetRandomBytes(DEFAULTBYTECOUNT));
}
private static HashAlgorithm GetAlgorithm()
{
return new SHA1Managed();
}
public static byte[] GetRandomBytes(int byteCount)
{
byte[] byteBuff = new byte[byteCount];
RNGCryptoServiceProvider rn = new RNGCryptoServiceProvider();
rn.GetNonZeroBytes(byteBuff);
return byteBuff;
}
public static byte[] GetHashedPasswordBytes(byte[] passwordBytes, out byte[] saltBytes)
{
saltBytes = GetRandomBytes(DEFAULTBYTECOUNT);
return GetHashedPasswordBytes(passwordBytes, saltBytes);
}
public static byte[] GetHashedPasswordBytes(byte[] passwordBytes, byte[] saltBytes)
{
byte[] combByt = new byte[passwordBytes.Length + saltBytes.Length];
passwordBytes.CopyTo(combByt,0);
saltBytes.CopyTo(combByt,passwordBytes.Length);
Array.Reverse(combByt);
HashAlgorithm sm = GetAlgorithm();
byte[] buffArr = sm.ComputeHash(combByt,0,combByt.Length);
return buffArr;
}
public static byte[] GetHashedPasswordBytes(string password, out byte[] saltBytes)
{
byte[] passByt = UnicodeEncoding.Unicode.GetBytes(password);
return GetHashedPasswordBytes(passByt, out saltBytes);
}
public static byte[] GetHashedPasswordBytes(string password, byte[] saltBytes)
{
byte[] passByt = UnicodeEncoding.Unicode.GetBytes(password);
return GetHashedPasswordBytes(passByt, saltBytes);
}
}
}
UPDATE...AGAIN: Umm...I'm going for the 'most updates to a single post' award OK? Anyway, just realised I forgot the little byte array comparison method after I updated this - in this context you'd need this script when comparing the stored array to freshly calculated one from the data entered by the user - you could convert to a Base64 string then just do string.Compare...but this is faster:
private bool CompareArrays(byte[] Arr1, byte[] Arr2)
{
if (Arr1.Length == Arr2.Length)
{
int i = 0;
while ((i < Arr1.Length) && (Arr1[i] == Arr2[i]))
i += 1;
if (i == Arr1.Length)
return true;
}
return false;
}
Right, that's it, not more updates...promise!