Now, many .NET developers are probably accustomed to using FormsAuthentication.HashPasswordForStoringInConfigFile() to hash passwords. So it's quite an annoyance that this function only supports two options for hash format: MD5 and SHA-1!
Why is this so? I have no idea. The System.Security.Cryptography namespace contains implementations of the newer SHA-2 hash algorithms.
Let's fire up .NET Reflector and disassemble FormsAuthentication.HashPasswordForStoringInConfigFile()
public static string HashPasswordForStoringInConfigFile(string password, string passwordFormat) { HashAlgorithm algorithm; if (password == null) { throw new ArgumentNullException("password"); } if (passwordFormat == null) { throw new ArgumentNullException("passwordFormat"); } if (StringUtil.EqualsIgnoreCase(passwordFormat, "sha1")) { algorithm = SHA1.Create(); } else { if (!StringUtil.EqualsIgnoreCase(passwordFormat, "md5")) { throw new ArgumentException(SR.GetString("InvalidArgumentValue", new object[] { "passwordFormat" })); } algorithm = MD5.Create(); } return MachineKeySection.ByteArrayToHexString(algorithm.ComputeHash(Encoding.UTF8.GetBytes(password)), 0); }
That's some dodgy code. A hard-coded if-else-if construct to lock it down to only supporting MD5 and SHA-1, and they don't seem to be aware that there is actually an overload HashAlgorithm.Create(string hashName) which takes a hash algorithm name parameter! If they'd just used that, they would have had support for all the SHA-2 hash implementations.
Here's my alternative:
public static string HashString(string inputString, string hashName) { HashAlgorithm algorithm = HashAlgorithm.Create(hashName); if (algorithm == null) { throw new ArgumentException("Unrecognized hash name", "hashName"); } byte[] hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); return Convert.ToBase64String(hash); }
Handles all of the available hash formats (and indeed any new ones that might be added in later versions of .NET, if HashAlgorithm.Create(string hashName) is updated), and additionally returns the result Base64 encoded rather than as a hexadecimal number, so it's shorter for the same hash length.
Good to know. Thanks for the post!
ReplyDeleteGood article! Do you have a list of possible hash names?
ReplyDeleteSee http://msdn.microsoft.com/en-us/library/wet69s13.aspx for a list of valid values for the hashName parameter.
DeleteYour alternative sucks just as much as the original. It's still a saltless single iteration hash-function. Use `Rfc2898DeriveBytes` to hash passwords.
ReplyDeleteIt's not saltless. It hashes a string. Whether that string is a salted password or an unsalted one is entirely up to you.
DeleteShouldn't the exception be: (no quotes around variable hashName)
ReplyDeletethrow new ArgumentException("Unrecognized hash name", hashName);
Also here is the code to get the Hex version (i needed backwards support for existing hashes):
' Create a new Stringbuilder to collect the bytes
' and create a string.
Dim sBuilder As New StringBuilder()
' Loop through each byte of the hashed data
' and format each one as a hexadecimal string.
Dim i As Integer
For i = 0 To hash.Length - 1
sBuilder.Append(hash(i).ToString("x2"))
Next i
' Return the hexadecimal string.
Return sBuilder.ToString().ToUpper()
Good article! Brazilian developers thanks
ReplyDeleteconnectify hotspot pro crack
ReplyDeletejetbrains-phpstorm crack
minitool power data recovery crack
advanced systemcare ultimate crack
letasoft sound booster crack
norton antivirus key generator
microsoft office product key
microsoft office product key
Nice Post 12 Minute Affiliate System
ReplyDelete