ViewState Encryption doesn't work with mixed algorithms - asp.net

I have a client who wants to turn on ViewState encryption in an ASP.NET Web Forms application. They are not able to use the default algorithms because of FIPS compliance. The initial request from the client was to use 3DES/AES as follows, which I added to the web.config file:
<machineKey validationKey="..." decryptionKey="..." validation="3DES" decryption="AES" />
Putting in this configuration caused the application to stop working with the following error:
[HttpException (0x80004005): Unable to validate data.]
System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Boolean useValidationSymAlgo, Boolean useLegacyMode, IVType ivType, Boolean signData) +1090
System.Web.UI.Page.EncryptString(String s, Purpose purpose) +150
[...]
By switching both keys to 3DES, I was able to get the system working.
Why does the system fail when the two different algorithms are used?

Not quite sure why that's failing - perhaps some error with the length of the key provided? The inner exception should be able to tell you more if there's one present.
Regardless, you should be aware that 3DES is being phased out by NIST and that ASP.NET does not use 3DES in a FIPS-compliant fashion. (Reference: http://csrc.nist.gov/publications/nistpubs/800-67-Rev1/SP-800-67-Rev1.pdf. See in particular the foreword, which states that we're in a transitional period for customers to move off of 3DES and on to AES. Also see Section 3.5; ASP.NET does not limit the number of invocations of the block cipher algorithm, so our particular usage of this algorithm makes it non-FIPS-compliant.)
The best course of action would be to use AES for encryption / decryption and HMACSHA256 for validation. This combination is FIPS-compliant and provides better security than 3DES / SHA1 (which is what was being used earlier). To do this, set:
<machineKey validation="HMACSHA256" validationKey="256 bits worth of hex digits (64 hex chars)" decryption="AES" decryptionKey="256 bits worth of hex digits (64 hex chars)" />
Then also set <pages viewStateEncryptionMode="Always" /> in Web.config to tell ASP.NET to use view state encryption using the algorithms you just provided in the <machineKey> element.

Related

Decrypting data that was encrypted with FormsAuthentication.Encrypt

I am encrypting data into a cookie via FormsAuthentication.Encrypt(data) in a .Net 4.0 ASP.Net web application deployed on a development web farm. I have specified a machineKey attribute to hard-code the ValidationKey, DecryptionKey, and Decryption (algorithm).
Now, I am trying to decrypt that cookie using an application i built on my development workstation. I am able to get the cookie via Request.Cookies["CookieName"] but when I attempt to decrypt the value via FormsAuthentication.Decrypt(encCookie), I get the following error:
Unable to validate data. at
System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean
fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length,
Boolean useValidationSymAlgo, Boolean useLegacyMode, IVType ivType,
Boolean signData) at
System.Web.Security.FormsAuthentication.Decrypt(String
encryptedTicket) at TuoVanitySite.Default.Page_Load(Object sender,
EventArgs e) in
c:\src\ets_2008\main\ebtDev\Sandboxes\rrozinov\TuoVanitySite\TuoVanitySite\Default.aspx.cs:line
22
Here is blurp from my web config (keys were removed):
<machineKey
validationKey="keyA"
decryptionKey="keyB"
decryption="3DES"
compatibilityMode="Framework20SP1"/>
Anyone has dealt with this situation where machineKey was not enough?
Ok, I was able to find a solution for my problem however i am not sure why this works.
I had to add the validation attribute to the machineKey:
<machineKey
validationKey="keyA"
decryptionKey="keyB"
validation="SHA1"
decryption="3DES"
compatibilityMode="Framework20SP1"/>
What makes it a bit interesting is the fact that regardless whether i put SHA1 or 3DES, my code can decrypt just fine. I did confirm that server is using default SHA1. I am still open to find a root cause for educational purposes.
as is mentioned in the "How To: Configure MachineKey in ASP.NET 2.0" article :
HMACSHA1 is used even if validation is set to AES or 3DES
So it may be the case that if the compatibility mode is set to Framework20SP1 or Framework20SP2 then it uses SHA1 regardless of what is set in the validation attribute.
I'm struggling with similar task at the moment - setting up single sign on between ASP.Net 4.0 and 3.5SP1 web applications that are deployed on IIS8 on Windows Server 2012. It gets more complicated because Win2k12 has .Net 4.5.1 which is an "in-place" upgrade to 4.0...

Viewstate Validation fails in web-farm - Usual suspects eliminated

I think that I've tried all of the standard responses to this problem, and I know that I've read hundreds of questions and posts about this problem, but none of them seem to have resolved it or shed any light on what the cause is in my scenario. (I'm 5 hours down and no nearer :-( )
I have a web-farm of 2 servers.
I have set the machine key and validation key in machine.config on both machines
Encryption: SHA1, Decryption: AES - These are the defaults, could it help to change them?
I have verified that no other config files in the chain (web.cfg, apphost etc.) have a setting for these values.
I have added a page to the site (based on this SO) that spits the machine key values back out, and verified that they are the same across requests to both machines and match the values that are in machine .config
The server side session state is in a shared state-server, I have verified that sessionid remains constant between requests to the 2 servers.
I have verified that the page is completely loaded and the __EVENTVALIDATION hidden field has been rendered into the page before initiating the post. The viewstate size is not too bad at 7.64kb
When a page is rendered from a request to server 1 and then posted back to server 2, I get the dreaded...
Error Message:
Unable to validate data.
at System.Web.Configuration.MachineKeySection.GetDecodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Int32& dataLength)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) HttpApplication.RecordError => HttpApplication.RaiseOnError => global_asax.Application_Error
The post is triggered by a standard, unadulterated asp linkbutton, there is no ajax going on on the page.
Any and all help will be greatly appreciated.
Setting enableViewStateMAC = false is not a solution :-)
Having inherited the servers in the state that they were configured, I never questioned the validity of the keys!!! ...Just checked that they matched on both servers...
Leaving all the encryption / decryption and validation algorithm settings as they were, I generated new keys using this tool which has a few more options than the others.
Problem solved
Moral of the story: If in doubt, generate new keys
... but why and how? Some postbacks with viewstate were working just fine with the old keys, it was only when the postback was to a different server that the problem became evident. If the keys were invalid - missing a character or something - then every postback should have failed - I think
If you've established that the machine keys are the same on both boxes, could it be the encryption/decryption thereof ?
Have you tried using Triple DES and setting the decryptionKey in the machine.config on both servers?
Check here
Also a easy way of making sure the machineKeys are the same is to add a line like this in the web.config.
NB: Assuming you have the same web.config on both servers and making sure that the validationKey and decryptionKey is valid
You can use http://aspnetresources.com/tools/machineKey to generate it.
<system.web>
<machineKey validationKey="*D9B0EDEA69D81A89BF5FBA2B08BAF691013F86B89A1F6BA8068C6ECC9539074" decryptionKey="*AE2B1966AF65D08F03EDFB" validation="SHA1" decryption="AES" />

Forms Authentication 4.0 on Web Farm

This is quite literally driving me bananas - I'm on holiday as from tomorrow but if I can't get this working today then it's under threat - so any help much appreciated!
Firstly, my website has a manually defined <machinekey /> element defined so that both web servers in the web farm are kept in sync. I have verified this with IIS manager (hence why I'm asking, despite the similarity with so many other questions). It looks like this (keys elided - but they are the correct length):
<machineKey validationKey="[512 bit hex]"
decryptionKey="[256-bit hex]"
validation="SHA1"
decryption="AES" />
The website is running Asp.Net MVC3 and I am using Forms authentication in 'normal' mode (i.e. not 2.0 compat mode). I'm using Forms Authentication to create an authentication ticket - using code like the following:
FormsAuthentication.SetAuthCookie(userName, false);
My Forms Auth config is very simple; there are no IIS or server-wide settings in place that override the documented defaults:
<authentication mode="Forms">
<forms defaultUrl="~/Unauthorised"
loginUrl="~/Unauthorised"
ticketCompatibilityMode="Framework40" />
</authentication>
And then I've hijacked the cookie-reading functionality as per this MSDN topic so that I can create the principal and identity that I want.
Problem is - only one half of the web farm is able to decrypt the authentication cookie, the other half (i.e. whichever one didn't authenticate the user) just gives:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.
With this as the top-part of the stack trace:
[CryptographicException: Length of the data to decrypt is invalid.]
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) +12521039
System.Security.Cryptography.CryptoStream.FlushFinalBlock() +53
System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Boolean useValidationSymAlgo, Boolean useLegacyMode, IVType ivType) +331
System.Web.Security.FormsAuthentication.Decrypt(String encryptedTicket) +293
We are using a slightly ancient (but very reliable) Load balancer - which does not modify the HTTP traffic - and the traffic in this case is HTTPs; I'm able to verify that it's always one server and not both by having used Fiddler to decrypt and inspect the traffic.
This clearly points to out-of-sync machineKeys - but they are not - so any idea what's going on!!?
Thanks in advance!
When different servers have different patches, it has the potential to alter the behavior of encryption (/decryption), therefore possibly causing this runtime exception:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.
More information regarding this issue can be found here: http://blog.evonet.com.au/post/SystemSecurityCryptographyCryptographicException-Length-of-the-data-to-decrypt-is-invalid.aspx

ASP.NET machineKey config section default location

Where do I find the machineKey config section for ASP.NET?
I don't have one in my application Web.config, there isn't one in the root Web.config and there isn't one in my machine.config.
Does this mean there is some other default hardcoded into ASP.NET? If so, what are the defaults? (For .NET 2 and 4)
Having read this: http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx
i was expecting to find something like this, somewhere:
<machineKey
validationKey="AutoGenerate,IsolateApps"
decryptionKey="AutoGenerate,IsolateApps"
/>
Edit: the 1.1 docs seem fairly clear wrt default values: http://msdn.microsoft.com/en-us/library/w8h3skw9(VS.71).aspx but the 4 docs are rather ambiguous http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx
machineKey is situated under System.web entry in web.config
Refer MSDN link for web.config Schema.
If you dont see it in your web.config, you can just add it there.
From MSDN again :-)
To provide tamper proof ViewState, a hashed message authentication code (HMAC) is generated from the ViewState content and the hash is compared on subsequent requests. The validation attribute of the indicates which hashing algorithm to use, and it defaults to SHA1, which uses the HMACSHA1 algorithm. Valid choices for hashing include SHA1 or MD5, although SHA1 is preferable because it produces a larger hash and is considered cryptographically stronger than MD5. The validationKey attribute of is used in conjunction with the ViewState content to produce the HMAC. If your application is installed in a Web farm, you need to change the validationKey from AutoGenerate,IsolateApps to a specific manually generated key value.
The default settings for the <pages> and <machineKey> elements are defined in the machine-level web.config.comments file.
For machineKey, they are
<machineKey validationKey="AutoGenerate,IsolateApps"
decryptionKey="AutoGenerate,IsolateApps"
validation="SHA1" decryption="Auto" />
EDIT :
For .NET 4.0 the default algorithm has been changed to SHA256
I think that the easiest way of finding the defaults is to see the entry in the MSDN for this config value.
MSDN 4.0 for machinekey is as below. The values selected are the default values.
The values in [] are the other optional values that the field can take.
I remember reading someplace this is the typical way in MSDN of denoting defaults for the config values.
<machineKey
validationKey="AutoGenerate,IsolateApps" [String]
decryptionKey="AutoGenerate,IsolateApps" [String]
validation="HMACSHA256" [SHA1 | MD5 | 3DES | AES | HMACSHA256 |
HMACSHA384 | HMACSHA512 | alg:algorithm_name]
decryption="Auto" [Auto | DES | 3DES | AES | alg:algorithm_name]
/>

ViewState Encryption in ASP.Net

Why is it that I see the same hash value generated when I use different algorithms for viewstate encryption.
I have added below lines to the web.config file
pages viewstateEncryptionMode="Always" enableViewStateMac="true".../>
machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps" validation="AES" decryption="Auto" />
Also, compilation debug="false" ... > is set.
No matter what I use (AES, MD5, SHA1, 3DES), it generates the same hash. Is there something I am missing out.
Please let me know.
-Thanks
Here is an article on Encrypting Viewstate. It's for ASP.Net 2.0. which should be fine for 3.5.
Via P&P on MSDN:
Forms authentication defaults to SHA1
for tamper proofing (if or
,
then forms authentication hashes the
forms authentication ticket by using
either MD5 or HMACSHA1 (HMACSHA1 is
used even if validation is set to AES
or 3DES). Forms authentication then
encrypts the ticket using the
algorithm specified in the decryption
attribute. (The decryption attribute
was introduced in ASP.NET 2.0.)
Therefore, theoretically, only SHA1 and MD5 should differ in the hash that is produced.

Resources