locked
.NET Framework v4.6 calculates different SHA1 hash than v4.5 RRS feed

  • Question

  • My company has a web based application that uses a SHA1 hash to handle passwords. recently on some of our machines, we started to experience some login failures on this application, and were able to determine that the encrypted password values stored in our database were not matching the encryptions calculated on the fly.

    The hash being generated is simple: 

    FormsAuthentication.HashPasswordForStoringInConfigFile(valueToEncrypt, "SHA1")

    Further investigation has revealed that on machines that have .NET Framework v4.6 (which was installed when Visual Studio 2015 was installed) are generating a different hash value than machines with .NET Framework v4.5!

    I wrote a little test app to prove this. When my "valueToEncrypt" is set to "admin1", these are the results:

    .NET 4.5: 38C6F0B29FBFD4E5A21393B18AFA2939E15EA9E8

    .NET 4.6: 3DBFCC93288CC92A7D1A3FF17778252356844DB0

    This could potentially become a huge issue for many of our larger customers! If they accidentally (or purposely) install .NET 4.6 on their server, none of the uer passwords will work! They will all have to be reset! 

    What happened to this algorithm in .NET 4.6??

    Wednesday, September 23, 2015 7:33 PM

Answers

  • Hi ACordner,

    Thanks for providing more useful demo.

    I've download your project and test on my side. This is not a bug related to .NET Framework v4.6.

    When debug your project, the main issue is in the following code

    string valueToEncrypt = password + (Convert.ToInt32(uid)).ToString("X8").Reverse();

    Since you have different results, as the valueToEncrypt has different value.

    adminSystem.Linq.Enumerable+<ReverseIterator>d__1`1[System.Char]
    adminSystem.Linq.Enumerable+<ReverseIterator>d__a0`1[System.Char]
    

    I am curious about why we get the different value as above.

    Per my understanding, the "valueToEncrypt" is a string, if you want to append a string, It's OK to use "+". But when you press F12 on Reverse() method, it doesn't return a string.

    public static IEnumerable<TSource> Reverse<TSource>(
    	this IEnumerable<TSource> source
    )
    

    So the easier fix way is remove Reverse() method like this, you'll get the same result.

     string valueToEncrypt = password + (Convert.ToInt32(uid)).ToString("X8");

    Have a nice day!

    Kristin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by ACordner Friday, September 25, 2015 2:30 PM
    Friday, September 25, 2015 8:12 AM

All replies

  • I think that when you upgraded in 4.5 you got a warning that this method is Obsolete. Here is a work around, don't know if it will help you! 
    Wednesday, September 23, 2015 8:15 PM
  • It does not help. In fact, I had seen that post already and implemented it to see if I would get the same result. It produces the same value! Here's my code:

    HashAlgorithm algorithm = SHA1.Create();
    byte[] hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(valueToEncrypt));
    StringBuilder hex = new StringBuilder(hash.Length * 2);
    foreach (byte b in hash)
        hex.AppendFormat("{0:x2}", b);
                
    return hex.ToString().ToUpper();

    I would gladly switch to using this code if it produced a result in v4.6 consistent with v4.5, but it does not. 

    Wednesday, September 23, 2015 8:38 PM
  • Hi ACordner,

    >>I wrote a little test app to prove this. When my "valueToEncrypt" is set to "admin1", these are the results:

    .NET 4.5: 38C6F0B29FBFD4E5A21393B18AFA2939E15EA9E8

    .NET 4.6: 3DBFCC93288CC92A7D1A3FF17778252356844DB0

    Based on your result, I also test on my side. Both of .NET4.5 and 4.6 are the same result(looks good):6C7CA345F63F835CB353FF15BD6C5E052EC08E7A

    Pic1: VS2015+.NET4.5+Web project

    Pic2: VS2015+.Net4.6+ Web project

    After checking FormsAuthentication.HashPasswordForStoringInConfigFile Method from MSDN.     Yes, this API is now obsolete. But it does not affect to use.  So I am curious why you get the different reslut? Do I miss something? If yes, please feel free to let me know.

    Have a nice day!

    Kristin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    • Edited by Kristin Xie Thursday, September 24, 2015 3:25 AM
    Thursday, September 24, 2015 3:21 AM
  • Kristin,

    Are these projects both running on the same machine? And the machine has .NET 4.6 installed on it? Can you build the EXE and run the EXE on a machine that does not have .NET 4.6 installed? Do you get the same result on that machine as you do on the machine with .NET 4.6 installed?

    And another question: Shouldn't generating this hash produce the same value on EVERY machine? Why, then, do you get a completely different result than I get? Is there some machine dependency in the generation of this result?

    I ran this code (both ways of calculating the hash) on 8 different machines. 7 of them had various versions of .NET 4.5, one had .NET version 4.6. All 7 of the v4.5 machines produce the same result, but the v4.6 machine produces a different result. Some of these machines are on our domain, some are virtual machines. 

    Here is a link to my app with source code (VS2012 project). If you run this app on your machine, does the result match your app's result? Does it match one of the results I get on my machines? The target framework for this project is .NET Framework 4.5. My machine also has 4.5.1, 4.5.2. and 4.6 installed.

    http://tinyurl.com/orrvbpo

    Thursday, September 24, 2015 2:20 PM
  • Hi ACordner,

    Thanks for providing more useful demo.

    I've download your project and test on my side. This is not a bug related to .NET Framework v4.6.

    When debug your project, the main issue is in the following code

    string valueToEncrypt = password + (Convert.ToInt32(uid)).ToString("X8").Reverse();

    Since you have different results, as the valueToEncrypt has different value.

    adminSystem.Linq.Enumerable+<ReverseIterator>d__1`1[System.Char]
    adminSystem.Linq.Enumerable+<ReverseIterator>d__a0`1[System.Char]
    

    I am curious about why we get the different value as above.

    Per my understanding, the "valueToEncrypt" is a string, if you want to append a string, It's OK to use "+". But when you press F12 on Reverse() method, it doesn't return a string.

    public static IEnumerable<TSource> Reverse<TSource>(
    	this IEnumerable<TSource> source
    )
    

    So the easier fix way is remove Reverse() method like this, you'll get the same result.

     string valueToEncrypt = password + (Convert.ToInt32(uid)).ToString("X8");

    Have a nice day!

    Kristin


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by ACordner Friday, September 25, 2015 2:30 PM
    Friday, September 25, 2015 8:12 AM
  • Wow! Thank you Kristin! That's a pretty embarrassing mistake! Thank you for pointing that out. Although I did not write the original code, it would have been very easy to catch had I simply watched the value being encrypted! Many thanks!

     I believe the original intent of the Reverse() was to reverse the order of the digits in the uid value, which is typically an 8-10 digit number. I'll figure out the proper way of doing that.

    • Edited by ACordner Friday, September 25, 2015 2:31 PM
    Friday, September 25, 2015 2:30 PM