mostlylucid

scott galloway's personal blog...
posts - 906, comments - 722, trackbacks - 11

My Links

News

Archives

Post Categories

Misc. Coding

Gimme some Hash!

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!

Print | posted on Monday, January 31, 2005 4:48 PM | Filed Under [ .NET Code Snippets Security ]

Feedback

Gravatar

# re: Gimme some Hash!

Why 4096 bits of salt for a 256 bit hash? It seems like you have many orders of magnitude more entropy than you need.
2/1/2005 7:34 AM | Eric Lippert
Gravatar

# re: Gimme some Hash!

Er, 2048 bits of salt, I meant to say. Still, overkill, no?
2/1/2005 7:35 AM | Eric Lippert
Gravatar

# re: Gimme some Hash!

Hi Eric, thanks for the comment - umm...yes...wish I could say there was some good reason but there really isn't - that's why I made it adjustable. In addition the use of SHA256 is probably overkill as well; as it's pretty much as slow as AES encryption... Ah well, did say it wasn't perfect ;-)
2/1/2005 8:17 AM | Scott Galloway
Gravatar

# re: Gimme some Hash!

Nice.
2/1/2005 1:57 PM | Darrell
Gravatar

# re: Gimme some Hash!

test
2/1/2005 10:44 PM | tester
Gravatar

# re: Gimme some Hash!

Shouldn't comByt have passwordBytes copied into it ? Or am I being stoopid ? :)
2/1/2005 10:46 PM | i/Noodle
Gravatar

# re: Gimme some Hash!

i/Noodle (your parents must have some wierd sense of humour...) you're dead right, missed a line out when I rewrote...fixed now
2/1/2005 11:20 PM | Scott Galloway
Gravatar

# re: Gimme some Hash!

Phew, glad I wasn't talking nonsense :)


Ok, I've been reading up on all the salting definitions around, and I still don't quite understand how it makes a dictionary attack any less feasible.
If I have access to the database, I now have access to the salt, and the hashed password.
Surely a simple fn like this would work: ??? Anyone ? Is it simply that we are relying on the fn below taking up more cpu?

foreach (dictionaryWord dw)
{
foreach(password hashedPwd, and relatedSalt salt)
{
if (hash(dw + salt) == hashedPwd)
{
foundPwd = true;
}
}
}



2/2/2005 6:35 PM | i/Noodle
Gravatar

# re: Gimme some Hash!

It makes the dictionary attack less feasible because it requires an all-new attack on every password. Without a salt, you can dictionary-attack EVERY password hash at the SAME TIME.
2/8/2005 8:24 AM | Eric Lippert
Gravatar

# re: Gimme some Hash!

Thanks Eric. I'm now fully salted :)
Scott, I think the code above isn't clr compliant btw - having same method signatures, only differing by out parameter.
At least thats what vs told me :)
Also, should you be calling Clear() on the HashAlgorithm after using it ? Disposing stuff n all that ?
Thanks again.
i/Noodle

ps... posting comments from firefox here, I always have to copy paste and submit them twice, the first seems to disappear... not sure whatsup...
2/15/2005 12:07 PM | i/Noodle
Gravatar

# re: Gimme some Hash!

i/Noodle - fair enough - it's example code, feel free to send me a celaned up version and I'll bung it on the post!
2/15/2005 12:54 PM | Scott Galloway
Comments have been closed on this topic.

Powered by: