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!