Tuesday, August 11, 2009

Sitecore 6 - CryptographicException: Padding is invalid and cannot be removed.

I've been getting the following exception from sitecore fairly frequently from my local IIS.

[CryptographicException: Padding is invalid and cannot be removed.]
   System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) +2910
   System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) +286
   System.Security.Cryptography.CryptoStream.FlushFinalBlock() +51
   System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo) +318
   System.Web.Security.FormsAuthentication.Decrypt(String encryptedTicket) +290
   Sitecore.Security.Authentication.AuthenticationHelper.GetCurrentUser() +473
   Sitecore.Security.Authentication.AuthenticationHelper.GetActiveUser() +17
   Sitecore.Security.Authentication.AuthenticationProvider.GetActiveUser() +21
   Sitecore.Security.Authentication.AuthenticationManager.GetActiveUser() +39
   Sitecore.Context.get_User() +17
   Sitecore.DateUtil.ParseTimeSpan(String time) +51
   Sitecore.Configuration.Settings.GetTimeSpanSetting(String name, TimeSpan defaultValue) +106
   Sitecore.Caching.CacheManager.InitializeScavenging() +70
   Sitecore.Caching.CacheManager..cctor() +92

I've tracked it back to the following sitecore code in Sitecore.Security.Authentication.AuthenticationHelper.GetCurrentUser():

protected User GetCurrentUser()
{
    HttpContext current = HttpContext.Current;
    if (current != null)
    {
        IPrincipal user = HttpContext.Current.User;
        if (user == null)
        {
            HttpCookie cookie = current.Request.Cookies[FormsAuthentication.FormsCookieName];
            if ((cookie != null) && !string.IsNullOrEmpty(cookie.Value))
            {
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
                if (!string.IsNullOrEmpty(ticket.Name))
                {
                    return this.GetUser(ticket.Name, true);
                }
            }
            return null;
        }
        // omitted code
        return null;
    }
    // omitted code
    return null;
}

The issue around line 473 (12 in the sample above) is in decrypting the value of the Forms Authentication cookie.

Possible Solution 0

Install Sitecore CMS 6.3.0 rev.100716 or higher. From the release notes:

When receiving an invalid authentication cookie (which may occur when switching between Sitecore instances in the IIS or when running a load balanced setup where each web application uses different machine keys), Sitecore would sometimes throw a "CryptographicException: Padding is invalid and cannot be removed" error and return a "500 Server Error" response to all requests hitting the web server. The CryptographicException will still be written to the log file to inform about improper configuration, while all requests passing invalid cookies are processed under the context of Anonymous user. (320777)

Possible Solution 1

If you are hosting with IIS7 try making adding the following to the global.asax (found at Running Sitecore 6 on Windows 7’s IIS but equally applies to Windows Server 2008):

public void Application_Start() {
      System.Security.Cryptography.RSACryptoServiceProvider.UseMachineKeyStore = true;
      System.Security.Cryptography.DSACryptoServiceProvider.UseMachineKeyStore = true;
  }

Possible Solution 2

Try clearing out the browsers cookies - in particular the Forms Authentication Cookie that ASP.NET creates.

Possible Solution 3

Try restarting/recycling the application pool in IIS.

Possible Solution 4

This may be applicable if you are running multiple versions of the site locally on different ports. Change these settings so that they are unique for each of your local sites.

Change your web.config Authentication Form name, which is used for the cookie name. Below the ".XXXXXXXX" is usually defaults to ".ASPXAUTH".

<authentication mode="None">
   <forms name=".XXXXXXXX" cookieless="UseCookies"/>
</authentication>

Add a unique machineKey in the web.config system.web node.

<system.web>
  <!-- Machine key attributes -->
  <machineKey validationKey="3SAMPLE122EA7A3F74BBEAD8450366243D982677F5243660BBAE3281839E013C2CEE7CF18BB85DC00C207E861B309FB075C51F74DFEB5FC4B72E01277610SAMPLE" 
       decryptionKey="060B29B5E05ESAMPLE42884148138D39B2ED861755A5E64AE370F6473E8SAMPLE" 
       validation="SHA1" decryption="AES" />

</system.web>

Possible Solution 5

Day to day I may have multiple separate instances of Sitecore running on my local IIS for developing for different clients. I'll typically be accessing them as http://localhost:8080 or http://127.0.0.1:8080 with different ports depending on the instance.

I often seem to come across the padding exception when switching between the multiple sites (by just changing the port).

My new theory is to setup a mock domain in my hosts file and change the site binding in IIS to use this new binding on port 80. I then use the new mock domain to access Sitecore from the browser.

See Also