views:

208

answers:

2

I am currently trying to upgrade a project of mine from .NET 3.5 to .NET 4.0

Everything was going really well, all code compiled, all tests passed.
Then I hit a problem deploying to my staging environment.
Suddenly my logins were no longer working.

It seems my SHA1 hashed passwords are being hashed differently in .NET 4.

I am using the SHA1CryptoServiceProvider:

SHA1CryptoServiceProvidercryptoTransformSHA1 = new SHA1CryptoServiceProvider();

To test I created a new Visual Studio project with 2 console applications.
The first targeted at .NET Framework 3.5 and the second at 4.0.
I ran exactly the same hashing code in both and different results were produced.

Why is this happening and how can I fix this?
I obviously cannot go update all of my users passwords considering I do not know what they are.

Any help would be greatly appreciated.

CODE SAMPLE

public static class SHA1Hash
{

    public static string Hash(string stringToHash)
    {
        return (Hash(stringToHash, Encoding.Default));
    }

    public static string Hash(string stringToHash, Encoding enc)
    {
        byte[] buffer = enc.GetBytes(stringToHash + stringToHash.Reverse());
        var cryptoTransformSHA1 = new SHA1CryptoServiceProvider();
        string hash = BitConverter.ToString(cryptoTransformSHA1.ComputeHash(buffer));
        return hash;
    }
}
A: 

Sounds like it might be character encoding problem. Ensure that the string being hashed is in the encoding [utf8, ansi etc] you expect (and if it is, ensure that the old environment is too.)

-Oisin

x0n
I've been using Encoding.Default. I tried specifying an Encoding and none of the following worked:Encoding.ASCII, Encoding.BigEndianUnicode, Encoding.Unicode, Encoding.UTF32, Encoding.UTF7, Encoding.UTF8
WebDude
hashing works at the byte stream level - I'm not sure if you understand me. You are specifying encoding where? All that matters is that both systems are verified to be feeding the same _bytes_ to the sha1 class.
x0n
please see the code sample which is the method I call.Both sites are running on exactly the same server so I'm not sure where the encoding would be changing. How can I verify that both systems are feeding the same bytes to the sha1 class?as per my above code sample, can I just check buffer.Length ?
WebDude
Encoding.Default may be different on each system (while your users hashes are obviously invariable.) Verify the default encoding with a simple console app (or use powershell) on each system. My default encoding is windows-1252; someone else's may differ.
x0n
(and btw, if the hash is different - you must assume the byte streams are different. sha1 algorithm didn't change between frameworks)
x0n
duly noted and lesson learnt. Thanks for the assistance
WebDude
A: 

One of the comments led me onto finding the bug in my code.
When creating my byte array to be hashed, I was trying to append the string with a reversed version of itself.

E.g. given "password" to hash I would actually hash "passworddrowssap"

However my code has a slight bug in it:

byte[] buffer = enc.GetBytes(stringToHash + stringToHash.Reverse()); 

.Reverse() is a Linq extension method that can reverse a string.
However it doesn't return a string, it returns:

IEnumerable<Char>

Calling .ToString() on this type actually returns:

System.Linq.Enumerable+d__99`1[System.Char]

Doing the same thing in .NET 4.0 returns

System.Linq.Enumerable+d__a0`1[System.Char]

Hence my passwords were being hashed differently.
What I should have done to create by byte array was:

byte[] buffer = enc.GetBytes(stringToHash + new String(stringToHash.Reverse().ToArray()));
WebDude