From e7419ca8bf79df22b3d6e70379e31e785d654cbe Mon Sep 17 00:00:00 2001
From: Marek Habersack <grendel@twistedcode.net>
Date: Wed, 24 Nov 2010 20:33:09 +0100
Subject: [PATCH] [asp.net] Normalization of cryptographic uses in asp.net.
 Backport of commit a22389fde254675e52a9da9c9bcd18afdec29d33
     Normalization of cryptographic uses in asp.net

    * System.Web.Configuration_2.0/MachineKeyRegistryStorage.cs:
    Remove key length check and generic key generation.

    * System.Web.Configuration_2.0/MachineKeySection.cs: Add support for 4.0
    ValidationAlgorithm and the use of custom algorithms (validation and
    decryption). Allow the use of any, valid, key length (based on the
    algorithm). Let each algorithm creates its own key (e.g. special needs,
    default length...)

    * System.Web.Configuration_2.0/MachineKeySectionUtils.cs: Remove key
    generation (from random) code and 192bits key length hack (won't work
    with custom algorithms). Add support for new (4.0) algorithms, including
    custom ones. Provide uniform/shared code to Encrypt/Decrypt, Sign/Verify
    and EncryptSign/VerifyDecrypt using MachineKeySection data.

    * System.Web.Configuration_2.0/MachineKeyValidation.cs: Add new (4.0)
    values.

    * System.Web.Configuration_2.0/MachineKeyValidationConverter.cs: Add
    support for new (4.0) algorithms.

    * System.Web.Handlers/AssemblyResourceLoader.cs: Use the new common
    cryptographic code and base64 the encrypted data.

    * System.Web.Security/FormsAuthentication.cs: Use the new common
    cryptographic code and base64 the signed and/or encrypted data.

    * System.Web.Security/MembershipHelper.cs: Use the new common
    cryptographic code - this should be 100% compatible with existing data.

    * System.Web.Security/RolePrincipal.cs: Use the new common cryptographic
    code.

    * System.Web.Security/SqliteMembershipProvider.cs: Adapt code for
    internal API change.
---
 mcs/class/System.Web/Assembly/AssemblyInfo.cs      |    2 +
 .../System.Web.Configuration/MachineKeyConfig.cs   |  198 ++++++----
 .../MachineKeyRegistryStorage.cs                   |   57 +---
 .../MachineKeyValidation.cs                        |   12 +-
 .../MachineKeyCompatibilityMode.cs                 |   40 ++
 .../MachineKeySection.cs                           |  210 +++++++++-
 .../MachineKeySectionUtils.cs                      |  442 +++++++++++++++-----
 .../MachineKeyValidationConverter.cs               |   70 +++-
 .../System.Web.Handlers/AssemblyResourceLoader.cs  |   78 +---
 .../System.Web.Security/FormsAuthentication.cs     |  167 +-------
 .../System.Web.Security/MembershipProvider.cs      |   46 +--
 .../System.Web.Security/RolePrincipal.cs           |   93 +----
 .../System.Web.Security/SqlMembershipProvider.cs   |   17 +-
 .../SqliteMembershipProvider.cs                    |    2 +-
 .../System.Web.SessionState/SessionId.cs           |   23 +-
 mcs/class/System.Web/System.Web.UI/LosFormatter.cs |   54 ++-
 .../System.Web.UI/ObjectStateFormatter.cs          |  156 ++++----
 mcs/class/System.Web/System.Web.UI/Page.cs         |   69 ---
 mcs/class/System.Web/System.Web.dll.sources        |    1 +
 mcs/class/System.Web/System.Web_test.dll.sources   |    2 +
 .../MachineKeySectionTest.cs                       |  158 +++++++
 .../MachineKeySectionUtilsTest.cs                  |  310 ++++++++++++++
 .../MachineKeyValidationConverterTest.cs           |   84 ++++-
 .../System.Web.Security/FormsAuthenticationTest.cs |   10 +
 .../Test/System.Web.Security/RolePrincipalTest.cs  |    4 +-
 .../Test/System.Web.UI/LosFormatterTest.cs         |  148 +++++++-
 .../Test/System.Web.UI/ObjectStateFormatterTest.cs |   16 +-
 .../System.Web/net_4_0_System.Web.dll.sources      |    1 +
 28 files changed, 1702 insertions(+), 768 deletions(-)
 create mode 100644 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
 create mode 100644 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
 create mode 100644 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs

diff --git a/mcs/class/System.Web/Assembly/AssemblyInfo.cs b/mcs/class/System.Web/Assembly/AssemblyInfo.cs
index b1e6f1e..7c174a2 100644
--- a/mcs/class/System.Web/Assembly/AssemblyInfo.cs
+++ b/mcs/class/System.Web/Assembly/AssemblyInfo.cs
@@ -69,6 +69,8 @@ using System.Web.UI;
 [assembly: InternalsVisibleTo ("System.Web.DynamicData, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
 
 [assembly: InternalsVisibleTo ("SystemWebTestShim, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
+[assembly: InternalsVisibleTo ("System.Web_test_net_2_0, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
+[assembly: InternalsVisibleTo ("System.Web_test_net_4_0, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
 #endif
 #endif
 
diff --git a/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs b/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
index b60fca5..4806ac6 100644
--- a/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
+++ b/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
@@ -39,23 +39,40 @@ namespace System.Web.Configuration
 {
 	class MachineKeyConfig
 	{
-		byte [] validation_key;
-		//bool    isolate_validation;
-		byte [] decryption_key;
-		byte [] decryption_key_192bits;
-		//bool    isolate_decryption; // For us, this is always true by now.
+		byte[] decryption_key;
+		byte[] validation_key;
+		string decryption_key_name;
+		string validation_key_name;
+		SymmetricAlgorithm decryption_template;
+		KeyedHashAlgorithm validation_template;
 		MachineKeyValidation validation_type;
 
-		static byte [] autogenerated;
-		static byte [] autogenerated_decrypt;
+		internal static MachineKeyConfig Config {
+			get {
+				HttpContext context = HttpContext.Current;
+				if (context == null)
+					return null;
+				
+				return context.GetConfig ("system.web/machineKey") as MachineKeyConfig;
+			}
+		}
 		
-		static MachineKeyConfig ()
-		{
-			autogenerated = new byte [64];
-			RandomNumberGenerator rng = RandomNumberGenerator.Create ();
-			rng.GetBytes (autogenerated);
-			autogenerated_decrypt = new byte [64];
-			rng.GetBytes (autogenerated_decrypt);
+		// not to be reused outside algorithm and key validation purpose
+		SymmetricAlgorithm DecryptionTemplate {
+			get {
+				if (decryption_template == null)
+					decryption_template = GetDecryptionAlgorithm ();
+				return decryption_template;
+			}
+		}
+
+		// not to be reused outside algorithm and key validation purpose
+		KeyedHashAlgorithm ValidationTemplate {
+			get {
+				if (validation_template == null)
+					validation_template = GetValidationAlgorithm ();
+				return validation_template;
+			}
 		}
 		
 		internal MachineKeyConfig (object parent)
@@ -68,75 +85,45 @@ namespace System.Web.Configuration
 			}
 		}
 
-		static byte ToHexValue (char c, bool high)
+		internal byte [] GetDecryptionKey ()
 		{
-			byte v;
-			if (c >= '0' && c <= '9')
-				v = (byte) (c - '0');
-			else if (c >= 'a' && c <= 'f')
-				v = (byte) (c - 'a' + 10);
-			else if (c >= 'A' && c <= 'F')
-				v = (byte) (c - 'A' + 10);
-			else
-				throw new ArgumentException ("Invalid hex character");
-
-			if (high)
-				v <<= 4;
-
-			return v;
-		}
-		
-		internal static byte [] GetBytes (string key, int len)
-		{
-			byte [] result = new byte [len / 2];
-			for (int i = 0; i < len; i += 2)
-				result [i / 2] = (byte) (ToHexValue (key [i], true) + ToHexValue (key [i + 1], false));
-
-			return result;
+			if (decryption_key == null)
+				SetDecryptionKey (decryption_key_name);
+			return decryption_key;
 		}
 
-		static byte [] MakeKey (string key, bool decryption) //, out bool isolate)
+		internal void SetDecryptionKey (string key)
 		{
-			if (key == null || key.StartsWith ("AutoGenerate")){
-				//isolate = key.IndexOf ("IsolateApps") != 1;
-
-				return (decryption) ? autogenerated_decrypt : autogenerated;
+			if ((key == null) || key.StartsWith ("AutoGenerate")) {
+				decryption_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
+			} else {
+				try {
+					decryption_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+					DecryptionTemplate.Key = decryption_key;
+				}
+				catch {
+					decryption_key = null;
+					throw new ArgumentException ("Invalid key length");
+				}
 			}
-
-			//isolate = false;
-
-			int len = key.Length;
-			if (len < 40 || len > 128 || (len % 2) == 1)
-				throw new ArgumentException ("Invalid key length");
-
-			return GetBytes (key, len);
 		}
-		
-		internal void SetValidationKey (string n)
+
+		internal KeyedHashAlgorithm GetValidationAlgorithm ()
 		{
-			validation_key = MakeKey (n, false); //, out isolate_validation);
-		}
-		
-		internal byte [] ValidationKey {
-			get { return validation_key; }
+			// code location to help with unit testing the code
+			return MachineKeySectionUtils.GetValidationAlgorithm (this.ValidationType);
 		}
 
-		internal void SetDecryptionKey (string n)
+		internal SymmetricAlgorithm GetDecryptionAlgorithm ()
 		{
-			decryption_key = MakeKey (n, true); //, out isolate_decryption);
-			decryption_key_192bits = new byte [24];
-			int count = 24;
-			if (decryption_key.Length < 24)
-				count = decryption_key.Length;
-			Buffer.BlockCopy (decryption_key, 0, decryption_key_192bits, 0, count);
-		}
-		
-		internal byte [] DecryptionKey {
-			get { return decryption_key; }
-		}
+			string name;
 
-		internal byte [] DecryptionKey192Bits {
-			get { return decryption_key_192bits; }
+			if (decryption_key_name == null || decryption_key_name.StartsWith ("AutoGenerate"))
+				name = "Auto";
+			else
+				name = decryption_key_name;
+			
+			return MachineKeySectionUtils.GetDecryptionAlgorithm (name);
 		}
 
 		internal MachineKeyValidation ValidationType {
@@ -147,6 +134,73 @@ namespace System.Web.Configuration
 				validation_type = value;
 			}
 		}
+
+		internal byte [] GetValidationKey ()
+		{
+			if (validation_key == null)
+				SetValidationKey (validation_key_name);
+			return validation_key;
+		}		
+
+		// key can be expended for HMAC - i.e. a small key, e.g. 32 bytes, is still accepted as valid
+		// the HMAC class already deals with keys larger than what it can use (digested to right size)
+		internal void SetValidationKey (string key)
+		{
+			validation_key_name = key;
+			if ((key == null) || key.StartsWith ("AutoGenerate")) {
+				validation_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
+			} else {
+				try {
+					validation_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+					ValidationTemplate.Key = validation_key;
+				}
+				catch (CryptographicException) {
+					// second chance, use the key length that the HMAC really wants
+					try {
+						byte[] expanded_key = new byte [ValidationTemplate.Key.Length];
+						Array.Copy (validation_key, 0, expanded_key, 0, validation_key.Length);
+						ValidationTemplate.Key = expanded_key;
+						validation_key = expanded_key;
+					}
+					catch {
+						validation_key = null;
+						throw new ArgumentException ("Invalid key length");
+					}
+				}
+			}
+		}
+
+		byte[] AutoGenerate (MachineKeyRegistryStorage.KeyType type)
+		{
+			byte[] key = null;
+#if TARGET_J2EE
+			{
+#else
+			try {
+				key = MachineKeyRegistryStorage.Retrieve (type);
+
+				// ensure the stored key is usable with the selection algorithm
+				if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+					DecryptionTemplate.Key = key;
+				else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+					ValidationTemplate.Key = key;
+			} catch (Exception) {
+				key = null;
+			}
+#endif
+			// some algorithms have special needs for key (e.g. length, parity, weak keys...) 
+			// so we better ask them to provide a default key (than to generate/use bad ones)
+			if (key == null) {
+				if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+					key = DecryptionTemplate.Key;
+				else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+					key = ValidationTemplate.Key;
+#if !TARGET_J2EE
+				MachineKeyRegistryStorage.Store (key, type);
+#endif
+			}
+			return key;
+		}
 	}
 }
 
diff --git a/mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs b/mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs
index c6f1d52..52bc5b3 100644
--- a/mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs
+++ b/mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs
@@ -28,8 +28,6 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
-using System.Security.Cryptography;
 using Microsoft.Win32;
 
 namespace System.Web.Configuration
@@ -42,9 +40,6 @@ namespace System.Web.Configuration
 			Encryption
 		};
 
-		const int encryptionKeyLength = 64;
-		const int validationKeyLength = 64;
-		
 		static string keyEncryption;
 		static string keyValidation;
 		
@@ -63,30 +58,15 @@ namespace System.Web.Configuration
 		
 		public static byte[] Retrieve (KeyType kt)
 		{
-			byte[] ret = GetKey (kt);
-			if (ret == null) {
-				ret = Generate (kt);
-				if (ret != null)
-					Store (ret, kt);
-			}
-			
-			return ret;
-		}
-
-		static byte[] GetKey (KeyType kt)
-		{
 			string key = null;
-			int len;
 			
 			switch (kt) {
 				case KeyType.Validation:
 					key = keyValidation;
-					len = validationKeyLength;
 					break;
 
 				case KeyType.Encryption:
 					key = keyEncryption;
-					len = validationKeyLength;
 					break;
 
 				default:
@@ -107,11 +87,7 @@ namespace System.Web.Configuration
 
 			if (o == null || o.GetType () != typeof (byte[]))
 				return null;
-			byte[] ret = (byte[])o;
-			if (ret.Length != len)
-				return null;
-
-			return ret;
+			return (byte[]) o;
 		}
 
 		static RegistryKey OpenRegistryKey (string path, bool write)
@@ -134,23 +110,19 @@ namespace System.Web.Configuration
 			return ret;
 		}
 		
-		static void Store (byte[] buf, KeyType kt)
+		public static void Store (byte[] buf, KeyType kt)
 		{
 			if (buf == null)
 				return;
 			
 			string key = null;
-			int len;
-			
 			switch (kt) {
 				case KeyType.Validation:
 					key = keyValidation;
-					len = validationKeyLength;
 					break;
 
 				case KeyType.Encryption:
 					key = keyEncryption;
-					len = validationKeyLength;
 					break;
 
 				default:
@@ -160,9 +132,6 @@ namespace System.Web.Configuration
 			if (key == null)
 				return;
 
-			if (buf.Length != len)
-				throw new ArgumentException ("Key has invalid length");
-
 			try {
 				using (RegistryKey rk = OpenRegistryKey (key, true)) {
 #if NET_2_0
@@ -180,27 +149,5 @@ namespace System.Web.Configuration
 				throw new ApplicationException ("Failed to store encryption key in the registry.", ex);
 			}
 		}
-
-		static byte[] Generate (KeyType kt)
-		{
-			RandomNumberGenerator rng = RandomNumberGenerator.Create ();
-			byte[] ret = null;
-			
-			switch (kt) {
-				case KeyType.Validation:
-					ret = new byte [validationKeyLength];
-					break;
-
-				case KeyType.Encryption:
-					ret = new byte [encryptionKeyLength];
-					break;
-
-				default:
-					throw new ArgumentException ("Unknown key type.");
-			}
-			
-			rng.GetBytes (ret);
-			return ret;
-		}
 	}
 }
diff --git a/mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs b/mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs
index a7b7515..eb7dfe1 100644
--- a/mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs
+++ b/mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs
@@ -23,11 +23,9 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2010 Novell, Inc (http://www.novell.com)
 //
 
-using System.Resources;
-
 namespace System.Web.Configuration
 {
 #if NET_2_0
@@ -40,7 +38,13 @@ namespace System.Web.Configuration
 		MD5 = 0,
 		SHA1 = 1,
 		TripleDES = 2,
-		AES = 3
+		AES = 3,
+#if NET_4_0
+		HMACSHA256 = 4,
+		HMACSHA384 = 5,
+		HMACSHA512 = 6,
+		Custom = 7
+#endif
 	}
 }
 
diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
new file mode 100644
index 0000000..5581143
--- /dev/null
+++ b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
@@ -0,0 +1,40 @@
+//
+// System.Web.Configuration.MachineKeyCompatibilityMode
+//
+// Authors:
+//	Sebastien Pouliot  <sebastien@ximian.com>
+//
+// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if NET_4_0
+
+namespace System.Web.Configuration {
+
+	public enum MachineKeyCompatibilityMode {
+		Framework20SP1 = 0,
+		Framework20SP2 = 1
+	}
+}
+
+#endif
+
diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs
index 193b9c2..c193e74 100644
--- a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs
+++ b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs
@@ -3,8 +3,9 @@
 //
 // Authors:
 //	Chris Toshok (toshok@ximian.com)
+//	Sebastien Pouliot  <sebastien@ximian.com>
 //
-// (c) Copyright 2005 Novell, Inc (http://www.novell.com)
+// (c) Copyright 2005, 2010 Novell, Inc (http://www.novell.com)
 //
 
 //
@@ -28,13 +29,13 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if NET_2_0
+
 using System;
 using System.ComponentModel;
 using System.Configuration;
 using System.Security.Cryptography;
 
-#if NET_2_0
-
 namespace System.Web.Configuration {
 
 	public sealed class MachineKeySection : ConfigurationSection
@@ -44,6 +45,10 @@ namespace System.Web.Configuration {
 		static ConfigurationProperty validationProp;
 		static ConfigurationProperty validationKeyProp;
 		static ConfigurationPropertyCollection properties;
+		static MachineKeyValidationConverter converter = new MachineKeyValidationConverter ();
+#if NET_4_0
+		MachineKeyValidation validation;
+#endif
 
 		static MachineKeySection ()
 		{
@@ -55,10 +60,17 @@ namespace System.Web.Configuration {
 								       PropertyHelper.WhiteSpaceTrimStringConverter,
 								       PropertyHelper.NonEmptyStringValidator,
 								       ConfigurationPropertyOptions.None);
-			validationProp = new ConfigurationProperty ("validation", typeof (MachineKeyValidation), MachineKeyValidation.SHA1,
-								    new MachineKeyValidationConverter (),
+#if NET_4_0
+			validationProp = new ConfigurationProperty ("validation", typeof (string), "HMACSHA256",
+								    PropertyHelper.WhiteSpaceTrimStringConverter,
+								    PropertyHelper.NonEmptyStringValidator,
+								    ConfigurationPropertyOptions.None);
+#else
+			validationProp = new ConfigurationProperty ("validation", typeof (MachineKeyValidation), 
+								    MachineKeyValidation.SHA1, converter,
 								    PropertyHelper.DefaultValidator,
 								    ConfigurationPropertyOptions.None);
+#endif
 			validationKeyProp = new ConfigurationProperty ("validationKey", typeof (string), "AutoGenerate,IsolateApps",
 								       PropertyHelper.WhiteSpaceTrimStringConverter,
 								       PropertyHelper.NonEmptyStringValidator,
@@ -71,12 +83,30 @@ namespace System.Web.Configuration {
 			properties.Add (validationProp);
 			properties.Add (validationKeyProp);
 
-			MachineKeySectionUtils.AutoGenKeys ();
+			Config.AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
+			Config.AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
 		}
 
+#if NET_4_0
+		public MachineKeySection ()
+		{
+			// get DefaultValue from ValidationAlgorithm
+			validation = (MachineKeyValidation) converter.ConvertFrom (null, null, ValidationAlgorithm);
+		}
+
+		[MonoTODO]
+		public MachineKeyCompatibilityMode CompatibilityMode {
+			get; set;
+		}
+#endif
+
 		protected override void Reset (ConfigurationElement parentElement)
 		{
 			base.Reset (parentElement);
+			decryption_key = null;
+			validation_key = null;
+			decryption_template = null;
+			validation_template = null;
 		}
 
 		[TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
@@ -84,7 +114,10 @@ namespace System.Web.Configuration {
 		[ConfigurationProperty ("decryption", DefaultValue = "Auto")]
 		public string Decryption {
 			get { return (string) base [decryptionProp];}
-			set { base[decryptionProp] = value; }
+			set {
+				decryption_template = MachineKeySectionUtils.GetDecryptionAlgorithm (value);
+				base[decryptionProp] = value;
+			}
 		}
 
 		[TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
@@ -94,16 +127,46 @@ namespace System.Web.Configuration {
 			get { return (string) base [decryptionKeyProp];}
 			set {
 				base[decryptionKeyProp] = value;
-				MachineKeySectionUtils.SetDecryptionKey (value);
+//				SetDecryptionKey (value);
 			}
 		}
 
+#if NET_4_0
+		// property exists for backward compatibility
+		public MachineKeyValidation Validation {
+			get { return validation; }
+			set {
+				if (value == MachineKeyValidation.Custom)
+					throw new ArgumentException ();
+//				ValidationAlgorithm = value.ToString ();
+			}
+		}
+
+		[StringValidator (MinLength = 1)]
+		[TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
+		[ConfigurationProperty ("validation", DefaultValue = "HMACSHA256")]
+		public string ValidationAlgorithm {
+			get { return (string) base [validationProp];}
+			set {
+				if (value == null)
+					return;
+
+				if (value.StartsWith ("alg:"))
+					validation = MachineKeyValidation.Custom;
+				else
+					validation = (MachineKeyValidation) converter.ConvertFrom (null, null, value);
+
+				base[validationProp] = value;
+			}
+		}
+#else
 		[TypeConverter (typeof (MachineKeyValidationConverter))]
 		[ConfigurationProperty ("validation", DefaultValue = "SHA1")]
 		public MachineKeyValidation Validation {
 			get { return (MachineKeyValidation) base [validationProp];}
 			set { base[validationProp] = value; }
 		}
+#endif
 
 		[TypeConverter (typeof (WhiteSpaceTrimStringConverter))]
 		[StringValidator (MinLength = 1)]
@@ -112,13 +175,142 @@ namespace System.Web.Configuration {
 			get { return (string) base [validationKeyProp];}
 			set {
 				base[validationKeyProp] = value;
-				MachineKeySectionUtils.SetValidationKey (value);
+//				SetValidationKey (value);
 			}
 		}
 
 		protected override ConfigurationPropertyCollection Properties {
 			get { return properties; }
 		}
+
+
+		internal static MachineKeySection Config {
+			get { return WebConfigurationManager.GetSection ("system.web/machineKey") as MachineKeySection; }
+		}
+
+		private byte[] decryption_key;
+		private byte[] validation_key;
+		private SymmetricAlgorithm decryption_template;
+		private KeyedHashAlgorithm validation_template;
+
+		internal SymmetricAlgorithm GetDecryptionAlgorithm ()
+		{
+			// code location to help with unit testing the code
+			return MachineKeySectionUtils.GetDecryptionAlgorithm (Decryption);
+		}
+
+		// not to be reused outside algorithm and key validation purpose
+		private SymmetricAlgorithm DecryptionTemplate {
+			get {
+				if (decryption_template == null)
+					decryption_template = GetDecryptionAlgorithm ();
+				return decryption_template;
+			}
+		}
+
+		internal byte [] GetDecryptionKey ()
+		{
+			if (decryption_key == null)
+				SetDecryptionKey (DecryptionKey);
+			return decryption_key;
+		}
+
+		void SetDecryptionKey (string key)
+		{
+			if ((key == null) || key.StartsWith ("AutoGenerate")) {
+				decryption_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
+			} else {
+				try {
+					decryption_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+					DecryptionTemplate.Key = decryption_key;
+				}
+				catch {
+					decryption_key = null;
+					throw new ArgumentException ("Invalid key length");
+				}
+			}
+		}
+
+		internal KeyedHashAlgorithm GetValidationAlgorithm ()
+		{
+			// code location to help with unit testing the code
+			return MachineKeySectionUtils.GetValidationAlgorithm (this);
+		}
+
+		// not to be reused outside algorithm and key validation purpose
+		private KeyedHashAlgorithm ValidationTemplate {
+			get {
+				if (validation_template == null)
+					validation_template = GetValidationAlgorithm ();
+				return validation_template;
+			}
+		}
+
+		internal byte [] GetValidationKey ()
+		{
+			if (validation_key == null)
+				SetValidationKey (ValidationKey);
+			return validation_key;
+		}
+
+		// key can be expended for HMAC - i.e. a small key, e.g. 32 bytes, is still accepted as valid
+		// the HMAC class already deals with keys larger than what it can use (digested to right size)
+		void SetValidationKey (string key)
+		{
+			if ((key == null) || key.StartsWith ("AutoGenerate")) {
+				validation_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
+			} else {
+				try {
+					validation_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+					ValidationTemplate.Key = validation_key;
+				}
+				catch (CryptographicException) {
+					// second chance, use the key length that the HMAC really wants
+					try {
+						byte[] expanded_key = new byte [ValidationTemplate.Key.Length];
+						Array.Copy (validation_key, 0, expanded_key, 0, validation_key.Length);
+						ValidationTemplate.Key = expanded_key;
+						validation_key = expanded_key;
+					}
+					catch {
+						validation_key = null;
+						throw new ArgumentException ("Invalid key length");
+					}
+				}
+			}
+		}
+
+		byte[] AutoGenerate (MachineKeyRegistryStorage.KeyType type)
+		{
+			byte[] key = null;
+#if TARGET_J2EE
+			{
+#else
+			try {
+				key = MachineKeyRegistryStorage.Retrieve (type);
+
+				// ensure the stored key is usable with the selection algorithm
+				if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+					DecryptionTemplate.Key = key;
+				else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+					ValidationTemplate.Key = key;
+			} catch (Exception) {
+				key = null;
+			}
+#endif
+			// some algorithms have special needs for key (e.g. length, parity, weak keys...) 
+			// so we better ask them to provide a default key (than to generate/use bad ones)
+			if (key == null) {
+				if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+					key = DecryptionTemplate.Key;
+				else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+					key = ValidationTemplate.Key;
+#if !TARGET_J2EE
+				MachineKeyRegistryStorage.Store (key, type);
+#endif
+			}
+			return key;
+		}
 	}
 }
 
diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
index 1f73379..dc4de7e 100644
--- a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
+++ b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
@@ -3,8 +3,9 @@
 //
 // Authors:
 //	Chris Toshok (toshok@ximian.com)
+//	Sebastien Pouliot  <sebastien@ximian.com>
 //
-// (c) Copyright 2005 Novell, Inc (http://www.novell.com)
+// (c) Copyright 2005, 2010 Novell, Inc (http://www.novell.com)
 //
 
 //
@@ -28,52 +29,17 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.ComponentModel;
 using System.Configuration;
-using System.Security.Cryptography;
-
 #if NET_2_0
+using System.Configuration.Provider;
+#endif
+using System.Security.Cryptography;
+using System.Text;
 
 namespace System.Web.Configuration {
 
-	internal static class MachineKeySectionUtils
-	{
-		static byte [] autogenerated;
-		static byte [] autogenerated_decrypt;
-		static byte[] decryption_key;
-		static byte[] decryption_key_192bits;
-		static byte[] validation_key;
-
-		internal static void AutoGenKeys ()
-		{
-#if TARGET_J2EE
-			{
-#else
-			try {
-				if (autogenerated == null)
-					autogenerated = MachineKeyRegistryStorage.Retrieve (
-						MachineKeyRegistryStorage.KeyType.Validation);
-				if (autogenerated_decrypt == null)
-					autogenerated_decrypt = MachineKeyRegistryStorage.Retrieve (
-						MachineKeyRegistryStorage.KeyType.Encryption);
-			} catch (Exception) {
-#endif
-				// Fall back to old method
-				RandomNumberGenerator rng = RandomNumberGenerator.Create ();
-				
-				if (autogenerated == null) {
-					autogenerated = new byte [64];
-					rng.GetBytes (autogenerated);
-				}
-
-				if (autogenerated_decrypt == null) {
-					autogenerated_decrypt = new byte [64];
-					rng.GetBytes (autogenerated_decrypt);
-				}
-			}
-		}
-
+	internal static class MachineKeySectionUtils {
 		static byte ToHexValue (char c, bool high)
 		{
 			byte v;
@@ -91,7 +57,7 @@ namespace System.Web.Configuration {
 
 			return v;
 		}
-		
+
 		internal static byte [] GetBytes (string key, int len)
 		{
 			byte [] result = new byte [len / 2];
@@ -101,87 +67,373 @@ namespace System.Web.Configuration {
 			return result;
 		}
 
-		static byte [] MakeKey (string key, bool decryption) //, out bool isolate)
+		static public string GetHexString (byte [] bytes)
 		{
-			if (key == null || key.StartsWith ("AutoGenerate")){
-				//isolate = key.IndexOf ("IsolateApps") != 1;
-				AutoGenKeys ();
-				return (decryption) ? autogenerated_decrypt : autogenerated;
+			StringBuilder sb = new StringBuilder (bytes.Length * 2);
+			int letterPart = 55;
+			const int numberPart = 48;
+			for (int i = 0; i < bytes.Length; i++) {
+				int tmp = (int) bytes [i];
+				int second = tmp & 15;
+				int first = (tmp >> 4) & 15;
+				sb.Append ((char) (first > 9 ? letterPart + first : numberPart + first));
+				sb.Append ((char) (second > 9 ? letterPart + second : numberPart + second));
 			}
+			return sb.ToString ();
+		}
 
-			//isolate = false;
-
-			int len = key.Length;
-			if (len < 40 || len > 128 || (len % 2) == 1)
-				throw new ArgumentException ("Invalid key length");
 
-			return GetBytes (key, len);
+		// decryption="Auto" [Auto | DES | 3DES | AES | alg:algorithm_name]
+		// http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx
+		public static SymmetricAlgorithm GetDecryptionAlgorithm (string name)
+		{
+			SymmetricAlgorithm sa = null;
+			switch (name) {
+			case "AES":
+			case "Auto":
+				sa = Rijndael.Create ();
+				break;
+			case "DES":
+				sa = DES.Create ();
+				break;
+			case "3DES":
+				sa = TripleDES.Create ();
+				break;
+			default:
+#if NET_4_0
+				if (name.StartsWith ("alg:"))
+					sa = SymmetricAlgorithm.Create (name.Substring (4));
+				else
+#endif
+				{
+#if NET_2_0
+					throw new ConfigurationErrorsException ();
+#else
+					throw new HttpException ("Unknown encryption algorithm name.");
+#endif
+				}
+#if NET_4_0
+				break;
+#endif
+			}
+			return sa;
 		}
 
-		internal static void SetDecryptionKey (string n)
+		// validation="HMACSHA256" [SHA1 | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]
+		// [1] http://msdn.microsoft.com/en-us/library/system.web.configuration.machinekeyvalidation.aspx
+		// [2] http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx
+		public static KeyedHashAlgorithm GetValidationAlgorithm (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
 		{
-			decryption_key = MakeKey (n, true); //, out isolate_decryption);
-			decryption_key_192bits = new byte [24];
-			int count = 24;
-			if (decryption_key.Length < 24)
-				count = decryption_key.Length;
-			Buffer.BlockCopy (decryption_key, 0, decryption_key_192bits, 0, count);
-		}
 
-		internal static void SetValidationKey (string n)
+			return GetValidationAlgorithm (
+#if NET_2_0
+				section.Validation
+#else
+				section.ValidationType
+#endif
+#if NET_4_0
+				, section
+#endif
+			);
+		}
+#if NET_4_0
+		public static KeyedHashAlgorithm GetValidationAlgorithm (MachineKeyValidation validation)
 		{
-			validation_key = MakeKey (n, false); //, out isolate_validation);
+			return GetValidationAlgorithm (validation, null);
+		}
+#endif
+		public static KeyedHashAlgorithm GetValidationAlgorithm (MachineKeyValidation validation
+#if NET_4_0
+									 , MachineKeySection section
+#endif
+		)
+		{
+			KeyedHashAlgorithm kha = null;
+			switch (validation) {
+			case MachineKeyValidation.MD5:
+#if NET_2_0
+				kha = new HMACMD5 ();
+#else
+				kha = new Mono.Security.Cryptography.HMAC ();
+#endif
+				break;
+			case MachineKeyValidation.AES:		// see link [1] or [2]
+			case MachineKeyValidation.TripleDES:	// see link [2]
+			case MachineKeyValidation.SHA1:
+				kha = new HMACSHA1 ();
+				break;
+#if NET_4_0
+			case MachineKeyValidation.HMACSHA256:
+				kha = new HMACSHA256 ();
+				break;
+			case MachineKeyValidation.HMACSHA384:
+				kha = new HMACSHA384 ();
+				break;
+			case MachineKeyValidation.HMACSHA512:
+				kha = new HMACSHA512 ();
+				break;
+			case MachineKeyValidation.Custom:
+				// remove the "alg:" from the start of the string
+				string algo = section.ValidationAlgorithm;
+				if (algo.StartsWith ("alg:"))
+					kha = KeyedHashAlgorithm.Create (algo.Substring (4));
+				break;
+#endif
+			}
+			return kha;
 		}
 
-		static MachineKeySection Config {
-			get { return WebConfigurationManager.GetSection ("system.web/machineKey") as MachineKeySection; }
-		}		
+		// helpers to ease unit testing of the cryptographic code
+#if TEST
+		static byte [] decryption_key;
+		static byte [] validation_key;
 
-		internal static byte [] ValidationKeyBytes ()
+		static SymmetricAlgorithm GetDecryptionAlgorithm (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
 		{
-			return ValidationKeyBytes (Config);
+			return GetDecryptionAlgorithm (section.Decryption);
 		}
-		
-		internal static byte [] ValidationKeyBytes (MachineKeySection section)
+
+		static byte [] GetDecryptionKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
+		{
+			if (decryption_key == null)
+				decryption_key = GetDecryptionAlgorithm (section).Key;
+			return decryption_key;
+		}
+
+		static byte [] GetValidationKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
 		{
-			if (section == null)
-				throw new ArgumentNullException ("section");
-			
 			if (validation_key == null)
-				SetValidationKey (section.ValidationKey);
+				validation_key = GetValidationAlgorithm (section).Key;
 			return validation_key;
 		}
+#else
+		static SymmetricAlgorithm GetDecryptionAlgorithm (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
+		{
+			return section.GetDecryptionAlgorithm ();
+		}
 
-		internal static byte [] DecryptionKeyBytes ()
+		static byte[] GetDecryptionKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
 		{
-			return DecryptionKeyBytes (Config);
+			return section.GetDecryptionKey ();
 		}
-		
-		internal static byte [] DecryptionKeyBytes (MachineKeySection section)
+
+		static byte [] GetValidationKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
 		{
-			if (section == null)
-				throw new ArgumentNullException ("section");
-			
-			if (decryption_key == null)
-				SetDecryptionKey (section.DecryptionKey);
-			return decryption_key;
+			return section.GetValidationKey ();
+		}
+#endif
+
+		static public byte [] Decrypt (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] encodedData)
+		{
+			return Decrypt (section, encodedData, 0, encodedData.Length);
+		}
+
+		static byte [] Decrypt (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] encodedData, int offset, int length)
+		{
+			using (SymmetricAlgorithm sa = GetDecryptionAlgorithm (section)) {
+				sa.Key = GetDecryptionKey (section);
+				return Decrypt (sa, encodedData, offset, length);
+			}
+		}
+
+		static public byte [] Decrypt (SymmetricAlgorithm alg, byte [] encodedData, int offset, int length)
+		{
+			// alg.IV is randomly set (default behavior) and perfect for our needs
+			// iv is the first part of the encodedPassword
+			byte [] iv = new byte [alg.IV.Length];
+			Array.Copy (encodedData, 0, iv, 0, iv.Length);
+			using (ICryptoTransform decryptor = alg.CreateDecryptor (alg.Key, iv)) {
+				try {
+					return decryptor.TransformFinalBlock (encodedData, iv.Length + offset, length - iv.Length);
+				}
+				catch (CryptographicException) {
+					return null;
+				}
+			}
+		}
+
+		static public byte [] Encrypt (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data)
+		{
+			using (SymmetricAlgorithm sa = GetDecryptionAlgorithm (section)) {
+				sa.Key = GetDecryptionKey (section);
+				return Encrypt (sa, data);
+			}
+		}
+
+		static public byte [] Encrypt (SymmetricAlgorithm alg, byte [] data)
+		{
+			// alg.IV is randomly set (default behavior) and perfect for our needs
+			byte [] iv = alg.IV;
+			using (ICryptoTransform encryptor = alg.CreateEncryptor (alg.Key, iv)) {
+				byte [] encrypted = encryptor.TransformFinalBlock (data, 0, data.Length);
+				byte [] output = new byte [iv.Length + encrypted.Length];
+				// note: the IV can be public, however it should not be based on the password
+				Array.Copy (iv, 0, output, 0, iv.Length);
+				Array.Copy (encrypted, 0, output, iv.Length, encrypted.Length);
+				return output;
+			}
+		}
+
+		// in		[data]
+		// return	[data][signature]
+		public static byte [] Sign (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data)
+		{
+			return Sign (section, data, 0, data.Length);
 		}
 
-		internal static byte [] DecryptionKey192Bits ()
+		static byte [] Sign (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data, int offset, int length)
 		{
-			return DecryptionKey192Bits (Config);
+			using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+				kha.Key = GetValidationKey (section);
+				byte [] signature = kha.ComputeHash (data, offset, length);
+				byte [] block = new byte [length + signature.Length];
+				Array.Copy (data, block, length);
+				Array.Copy (signature, 0, block, length, signature.Length);
+				return block;
+			}
 		}
-		
-		internal static byte [] DecryptionKey192Bits (MachineKeySection section)
+
+		public static byte [] Verify (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data)
 		{
-			if (section == null)
-				throw new ArgumentNullException ("section");
-			
-			if (decryption_key_192bits == null)
-				SetDecryptionKey (section.DecryptionKey);
-			return decryption_key_192bits;
+			byte [] unsigned_data = null;
+			bool valid = true;
+			using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+				kha.Key = GetValidationKey (section);
+				int signlen = kha.HashSize >> 3; // bits to bytes
+				byte [] signature = Sign (section, data, 0, data.Length - signlen);
+				for (int i = 0; i < signature.Length; i++) {
+					if (signature [i] != data [data.Length - signature.Length + i])
+						valid = false; // do not return (timing attack)
+				}
+				unsigned_data = new byte [data.Length - signlen];
+				Array.Copy (data, 0, unsigned_data, 0, unsigned_data.Length);
+			}
+			return valid ? unsigned_data : null;
+		}
+
+		// do NOT sign then encrypt
+
+		public static byte [] EncryptSign (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data)
+		{
+			byte [] encdata = Encrypt (section, data);
+			return Sign (section, encdata);
+		}
+
+		// note: take no shortcut (timing attack) while verifying or decrypting
+		public static byte [] VerifyDecrypt (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] block)
+		{
+			bool valid = true;
+			int signlen;
+
+			using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+				kha.Key = GetValidationKey (section);
+				signlen = kha.HashSize >> 3; // bits to bytes
+				byte [] signature = Sign (section, block, 0, block.Length - signlen);
+				for (int i = 0; i < signature.Length; i++) {
+					if (signature [i] != block [block.Length - signature.Length + i])
+						valid = false; // do not return (timing attack)
+				}
+			}
+
+			// whatever the signature continue with decryption
+			try {
+				byte [] decdata = Decrypt (section, block, 0, block.Length - signlen);
+				return valid ? decdata : null;
+			}
+			catch {
+				return null;
+			}
 		}
 	}
 }
 
-#endif
diff --git a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
index 014ca28..698509c 100644
--- a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
+++ b/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
@@ -3,8 +3,9 @@
 //
 // Authors:
 //	Chris Toshok (toshok@ximian.com)
+//	Sebastien Pouliot  <sebastien@ximian.com>
 //
-// (c) Copyright 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005, 2010 Novell, Inc (http://www.novell.com)
 //
 
 //
@@ -28,7 +29,6 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.ComponentModel;
 using System.Configuration;
 using System.Globalization;
@@ -39,40 +39,76 @@ namespace System.Web.Configuration {
 
 	public sealed class MachineKeyValidationConverter : ConfigurationConverterBase
 	{
+#if NET_4_0
+		const string InvalidValue = "The enumeration value must be one of the following: SHA1, MD5, 3DES, AES, HMACSHA256, HMACSHA384, HMACSHA512."; 
+#else
+		const string InvalidValue = "The enumeration value must be one of the following: SHA1, MD5, 3DES, AES."; 
+#endif
 		public MachineKeyValidationConverter ()
 		{
 		}
 
 		public override object ConvertFrom (ITypeDescriptorContext ctx, CultureInfo ci, object data)
 		{
-			if ((string)data == "MD5")
+			switch ((string) data) {
+			case "MD5":
 				return MachineKeyValidation.MD5;
-			else if ((string)data == "SHA1")
+			case "SHA1":
 				return MachineKeyValidation.SHA1;
-			else if ((string)data == "3DES")
+			case "3DES":
 				return MachineKeyValidation.TripleDES;
-			else if ((string)data == "AES")
+			case "AES":
 				return MachineKeyValidation.AES;
-			else
-				throw new ArgumentException ("The enumeration value must be one of the following: SHA1, MD5, 3DES, AES.");
+#if NET_4_0
+			case "HMACSHA256":
+				return MachineKeyValidation.HMACSHA256;
+			case "HMACSHA384":
+				return MachineKeyValidation.HMACSHA384;
+			case "HMACSHA512":
+				return MachineKeyValidation.HMACSHA512;
+#endif
+			default:
+				throw new ArgumentException (InvalidValue);
+			}
 		}
 
 		public override object ConvertTo (ITypeDescriptorContext ctx, CultureInfo ci, object value, Type type)
 		{
+#if NET_4_0
+			if ((value == null) || (value.GetType () != typeof (MachineKeyValidation)))
+				throw new ArgumentException (InvalidValue);
+#else
 			if (value.GetType () != typeof (MachineKeyValidation)) {
 				/* MS throws this exception on an invalid */
-				throw new FormatException ("invalid validation value");
+				throw new FormatException (InvalidValue);
 			}				
+#endif
 
-			MachineKeyValidation v = (MachineKeyValidation)value;
-
-			if (v == MachineKeyValidation.MD5) return "MD5";
-			else if (v == MachineKeyValidation.SHA1) return "SHA1";
-			else if (v == MachineKeyValidation.TripleDES) return "3DES";
-			else if (v ==  MachineKeyValidation.AES) return "AES";
-			else
+			switch ((MachineKeyValidation) value) {
+			case MachineKeyValidation.MD5:
+				return "MD5";
+			case MachineKeyValidation.SHA1:
+				return "SHA1";
+			case MachineKeyValidation.TripleDES:
+				return "3DES";
+			case MachineKeyValidation.AES:
+				return "AES";
+#if NET_4_0
+			case MachineKeyValidation.HMACSHA256:
+				return "HMACSHA256";
+			case MachineKeyValidation.HMACSHA384:
+				return "HMACSHA384";
+			case MachineKeyValidation.HMACSHA512:
+				return "HMACSHA512";
+			default:
+				// includes MachineKeyValidation.Custom
+				throw new ArgumentException (InvalidValue);
+#else
+			default:
 				/* MS throws this exception on an invalid */
-				throw new FormatException ("invalid validation value");
+				throw new FormatException (InvalidValue);
+#endif
+			}
 		}
 	}
 }
diff --git a/mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs b/mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
index c8acba1..8953b71 100644
--- a/mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
+++ b/mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
@@ -34,7 +34,6 @@ using System.Reflection;
 using System.IO;
 using System.Resources;
 using System.Collections;
-using System.Security.Cryptography;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Web.Configuration;
@@ -59,11 +58,6 @@ namespace System.Web.Handlers {
 		const char QueryParamSeparator = '&';
 
 		static readonly Hashtable _embeddedResources = Hashtable.Synchronized (new Hashtable ());
-#if SYSTEM_WEB_EXTENSIONS
-		static ScriptResourceHandler () {
-			MachineKeySectionUtils.AutoGenKeys ();
-		}
-#endif
 
 		static void InitEmbeddedResourcesUrls (Assembly assembly, Hashtable hashtable)
 		{
@@ -92,70 +86,40 @@ namespace System.Web.Handlers {
 		{
 			return GetResourceUrl (type.Assembly, resourceName, false);
 		}
-#endif
-
-		static string GetHexString (byte [] bytes)
-		{
-			const int letterPart = 55;
-			const int numberPart = 48;
-			char [] result = new char [bytes.Length * 2];
-			for (int i = 0; i < bytes.Length; i++) {
-				int tmp = (int) bytes [i];
-				int second = tmp & 15;
-				int first = (tmp >> 4) & 15;
-				result [(i * 2)] = (char) (first > 9 ? letterPart + first : numberPart + first);
-				result [(i * 2) + 1] = (char) (second > 9 ? letterPart + second : numberPart + second);
-			}
-			return new string (result);
-		}
-		
-		static byte[] GetEncryptionKey ()
-		{
-#if NET_2_0
-			return MachineKeySectionUtils.DecryptionKey192Bits ();
-#else
-			MachineKeyConfig config = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
-			return config.DecryptionKey192Bits;
-#endif
-		}
-
-		static byte[] GetBytes (string val)
+#endif		
+		static string EncryptAssemblyResource (string asmName, string resName)
 		{
+			byte[] bytes = Encoding.UTF8.GetBytes (String.Concat (asmName, ";", resName));
+			bytes = MachineKeySectionUtils.Encrypt (
 #if NET_2_0
-			return MachineKeySectionUtils.GetBytes (val, val.Length);
+				MachineKeySection.Config,
 #else
-			return MachineKeyConfig.GetBytes (val, val.Length);
+				MachineKeyConfig.Config,
 #endif
-		}		
-		
-		static byte [] init_vector = { 0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF };
-		
-		static string EncryptAssemblyResource (string asmName, string resName)
-		{
-			byte[] key = GetEncryptionKey ();
-			byte[] bytes = Encoding.UTF8.GetBytes (String.Concat (asmName, ";", resName));
-			string result;
-			
-			ICryptoTransform encryptor = TripleDES.Create ().CreateEncryptor (key, init_vector);
-			result = GetHexString (encryptor.TransformFinalBlock (bytes, 0, bytes.Length));
-			bytes = null;
-
-			return String.Concat ("d=", result.ToLower (Helpers.InvariantCulture));
+				bytes);
+			return Convert.ToBase64String (bytes);
 		}
 
 		static void DecryptAssemblyResource (string val, out string asmName, out string resName)
 		{
-			byte[] key = GetEncryptionKey ();
-			byte[] bytes = GetBytes (val);
-			byte[] result;
+			byte[] bytes = Convert.FromBase64String (val);
 
 			asmName = null;
 			resName = null;			
 
-			ICryptoTransform decryptor = TripleDES.Create ().CreateDecryptor (key, init_vector);
-			result = decryptor.TransformFinalBlock (bytes, 0, bytes.Length);
+			byte[] result = MachineKeySectionUtils.Decrypt (
+#if NET_2_0
+				MachineKeySection.Config,
+#else
+				MachineKeyConfig.Config,
+#endif
+				bytes);
 			bytes = null;
 
+			// null will be returned if, for any reason, decryption fails
+			if (result == null)
+				return;
+
 			string data = Encoding.UTF8.GetString (result);
 			result = null;
 
@@ -202,7 +166,7 @@ namespace System.Web.Handlers {
 			if (apath != String.Empty)
 				atime = String.Concat (QueryParamSeparator, "t=", File.GetLastWriteTimeUtc (apath).Ticks);
 #endif
-			string href = HandlerFileName + "?" + EncryptAssemblyResource (aname, resourceName) + atime + extra;
+			string href = HandlerFileName + "?d=" + EncryptAssemblyResource (aname, resourceName) + atime + extra;
 
 			HttpContext ctx = HttpContext.Current;
 			if (ctx != null && ctx.Request != null) {
diff --git a/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs b/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs
index 2ece407..899237e 100644
--- a/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs
+++ b/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs
@@ -45,9 +45,6 @@ namespace System.Web.Security
 	[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
 	public sealed class FormsAuthentication
 	{
-		const int MD5_hash_size = 16;
-		const int SHA1_hash_size = 20;
-
 		static string authConfigPath = "system.web/authentication";
 		static string machineKeyConfigPath = "system.web/machineKey";
 #if TARGET_J2EE
@@ -56,7 +53,6 @@ namespace System.Web.Security
 		const string Forms_cookiePath = "Forms.cookiePath";
 		const string Forms_timeout = "Forms.timeout";
 		const string Forms_protection = "Forms.protection";
-		const string Forms_init_vector = "Forms.init_vector";
 		static bool initialized
 		{
 			get {
@@ -88,11 +84,6 @@ namespace System.Web.Security
 			get { return (FormsProtectionEnum) AppDomain.CurrentDomain.GetData (Forms_protection); }
 			set { AppDomain.CurrentDomain.SetData (Forms_protection, value); }
 		}
-		static byte [] init_vector
-		{
-			get { return (byte []) AppDomain.CurrentDomain.GetData (Forms_init_vector); }
-			set { AppDomain.CurrentDomain.SetData (Forms_init_vector, value); }
-		}
 		static object locker = new object ();
 #else
 		static bool initialized;
@@ -101,7 +92,6 @@ namespace System.Web.Security
 		static int timeout;
 		static FormsProtectionEnum protection;
 		static object locker = new object ();
-		static byte [] init_vector; // initialization vector used for 3DES
 #endif
 #if NET_1_1
 #if TARGET_J2EE
@@ -240,18 +230,6 @@ namespace System.Web.Security
 #endif
 		}
 
-#if NET_2_0
-		static byte [] GetDecryptionKey (MachineKeySection config)
-		{
-			return MachineKeySectionUtils.DecryptionKey192Bits (config);
-		}
-#else
-		static byte [] GetDecryptionKey (MachineKeyConfig config)
-		{
-			return config.DecryptionKey192Bits;
-		}
-#endif
-		
 		static FormsAuthenticationTicket Decrypt2 (byte [] bytes)
 		{
 			if (protection == FormsProtectionEnum.None)
@@ -262,59 +240,14 @@ namespace System.Web.Security
 #else
 			MachineKeyConfig config = HttpContext.GetAppConfig (machineKeyConfigPath) as MachineKeyConfig;
 #endif
-			bool all = (protection == FormsProtectionEnum.All);
-
-			byte [] result = bytes;
-			if (all || protection == FormsProtectionEnum.Encryption) {
-				ICryptoTransform decryptor;
-				decryptor = TripleDES.Create ().CreateDecryptor (GetDecryptionKey (config), init_vector);
-				result = decryptor.TransformFinalBlock (bytes, 0, bytes.Length);
-				bytes = null;
-			}
-
-			if (all || protection == FormsProtectionEnum.Validation) {
-				int count;
-				MachineKeyValidation validationType;
-
-#if NET_2_0
-				validationType = config.Validation;
-#else
-				validationType = config.ValidationType;
-#endif
-				if (validationType == MachineKeyValidation.MD5)
-					count = MD5_hash_size;
-				else
-					count = SHA1_hash_size; // 3DES and SHA1
-
-#if NET_2_0
-				byte [] vk = MachineKeySectionUtils.ValidationKeyBytes (config);
-#else
-				byte [] vk = config.ValidationKey;
-#endif
-				byte [] mix = new byte [result.Length - count + vk.Length];
-				Buffer.BlockCopy (result, 0, mix, 0, result.Length - count);
-				Buffer.BlockCopy (vk, 0, mix, result.Length - count, vk.Length);
-
-				byte [] hash = null;
-				switch (validationType) {
-				case MachineKeyValidation.MD5:
-					hash = MD5.Create ().ComputeHash (mix);
-					break;
-				// From MS docs: "When 3DES is specified, forms authentication defaults to SHA1"
-				case MachineKeyValidation.TripleDES:
-				case MachineKeyValidation.SHA1:
-					hash = SHA1.Create ().ComputeHash (mix);
-					break;
-				}
-
-				if (result.Length < count)
-					throw new ArgumentException ("Error validating ticket (length).", "encryptedTicket");
 
-				int i, k;
-				for (i = result.Length - count, k = 0; k < count; i++, k++) {
-					if (result [i] != hash [k])
-						throw new ArgumentException ("Error validating ticket.", "encryptedTicket");
-				}
+			byte [] result = null;
+			if (protection == FormsProtectionEnum.All) {
+				result = MachineKeySectionUtils.VerifyDecrypt (config, bytes);
+			} else if (protection == FormsProtectionEnum.Encryption) {
+				result = MachineKeySectionUtils.Decrypt (config, bytes);
+			} else if (protection == FormsProtectionEnum.Validation) {
+				result = MachineKeySectionUtils.Verify (config, bytes);
 			}
 
 			return FormsAuthenticationTicket.FromByteArray (result);
@@ -328,11 +261,8 @@ namespace System.Web.Security
 			Initialize ();
 
 			FormsAuthenticationTicket ticket;
-#if NET_2_0
-			byte [] bytes = MachineKeySectionUtils.GetBytes (encryptedTicket, encryptedTicket.Length);
-#else
-			byte [] bytes = MachineKeyConfig.GetBytes (encryptedTicket, encryptedTicket.Length);
-#endif
+			byte [] bytes = Convert.FromBase64String (encryptedTicket);
+
 			try {
 				ticket = Decrypt2 (bytes);
 			} catch (Exception) {
@@ -350,57 +280,23 @@ namespace System.Web.Security
 			Initialize ();
 			byte [] ticket_bytes = ticket.ToByteArray ();
 			if (protection == FormsProtectionEnum.None)
-				return GetHexString (ticket_bytes);
+				return Convert.ToBase64String (ticket_bytes);
 
-			byte [] result = ticket_bytes;
+			byte [] result = null;
 #if NET_2_0
 			MachineKeySection config = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection (machineKeyConfigPath);
 #else
 			MachineKeyConfig config = HttpContext.GetAppConfig (machineKeyConfigPath) as MachineKeyConfig;
 #endif
-			bool all = (protection == FormsProtectionEnum.All);
-			if (all || protection == FormsProtectionEnum.Validation) {
-				byte [] valid_bytes = null;
-#if NET_2_0
-				byte [] vk = MachineKeySectionUtils.ValidationKeyBytes (config);
-#else
-				byte [] vk = config.ValidationKey;
-#endif
-				byte [] mix = new byte [ticket_bytes.Length + vk.Length];
-				Buffer.BlockCopy (ticket_bytes, 0, mix, 0, ticket_bytes.Length);
-				Buffer.BlockCopy (vk, 0, mix, result.Length, vk.Length);
-
-				switch (
-#if NET_2_0
-					config.Validation
-#else
-					config.ValidationType
-#endif
-					) {
-				case MachineKeyValidation.MD5:
-					valid_bytes = MD5.Create ().ComputeHash (mix);
-					break;
-				// From MS docs: "When 3DES is specified, forms authentication defaults to SHA1"
-				case MachineKeyValidation.TripleDES:
-				case MachineKeyValidation.SHA1:
-					valid_bytes = SHA1.Create ().ComputeHash (mix);
-					break;
-				}
-
-				int tlen = ticket_bytes.Length;
-				int vlen = valid_bytes.Length;
-				result = new byte [tlen + vlen];
-				Buffer.BlockCopy (ticket_bytes, 0, result, 0, tlen);
-				Buffer.BlockCopy (valid_bytes, 0, result, tlen, vlen);
+			if (protection == FormsProtectionEnum.All) {
+				result = MachineKeySectionUtils.EncryptSign (config, ticket_bytes);
+			} else if (protection == FormsProtectionEnum.Encryption) {
+				result = MachineKeySectionUtils.Encrypt (config, ticket_bytes);
+			} else if (protection == FormsProtectionEnum.Validation) {
+				result = MachineKeySectionUtils.Sign (config, ticket_bytes);
 			}
 
-			if (all || protection == FormsProtectionEnum.Encryption) {
-				ICryptoTransform encryptor;
-				encryptor = TripleDES.Create ().CreateEncryptor (GetDecryptionKey (config), init_vector);
-				result = encryptor.TransformFinalBlock (result, 0, result.Length);
-			}
-
-			return GetHexString (result);
+			return Convert.ToBase64String (result);
 		}
 
 		public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie)
@@ -481,21 +377,6 @@ namespace System.Web.Security
 			return returnUrl;
 		}
 
-		static string GetHexString (byte [] bytes)
-		{
-			const int letterPart = 55;
-			const int numberPart = 48;
-			char [] result = new char [bytes.Length * 2];
-			for (int i = 0; i < bytes.Length; i++) {
-				int tmp = (int) bytes [i];
-				int second = tmp & 15;
-				int first = (tmp >> 4) & 15;
-				result [(i * 2)] = (char) (first > 9 ? letterPart + first : numberPart + first);
-				result [(i * 2) + 1] = (char) (second > 9 ? letterPart + second : numberPart + second);
-			}
-			return new string (result);
-		}
-
 		static string HashPasswordForStoringInConfigFile (string password, FormsAuthPasswordFormat passwordFormat)
 		{
 			if (password == null)
@@ -515,7 +396,7 @@ namespace System.Web.Security
 					throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat");
 			}
 
-			return GetHexString (bytes);
+			return MachineKeySectionUtils.GetHexString (bytes);
 		}
 		
 		public static string HashPasswordForStoringInConfigFile (string password, string passwordFormat)
@@ -583,16 +464,6 @@ namespace System.Web.Security
 				}
 #endif
 
-				// IV is 8 bytes long for 3DES
-				init_vector = new byte [8];
-				int len = cookieName.Length;
-				for (int i = 0; i < 8; i++) {
-					if (i >= len)
-						break;
-
-					init_vector [i] = (byte) cookieName [i];
-				}
-
 				initialized = true;
 			}
 		}
diff --git a/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs b/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
index 4a9556b..71b5e16 100644
--- a/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
+++ b/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
@@ -87,57 +87,33 @@ namespace System.Web.Security
 				eh (this, args);
 		}
 
-		SymmetricAlgorithm GetAlg ()
+		SymmetricAlgorithm GetAlgorithm ()
 		{
-			MachineKeySection section = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
+			MachineKeySection section = MachineKeySection.Config;
 
 			if (section.DecryptionKey.StartsWith ("AutoGenerate"))
 				throw new ProviderException ("You must explicitly specify a decryption key in the <machineKey> section when using encrypted passwords.");
 
-			string alg_type = section.Decryption;
-			if (alg_type == "Auto")
-				alg_type = "AES";
+			SymmetricAlgorithm sa = section.GetDecryptionAlgorithm ();
+			if (sa == null)
+				throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", section.Decryption));
 
-			SymmetricAlgorithm alg = null;
-			if (alg_type == "AES")
-				alg = Rijndael.Create ();
-			else if (alg_type == "3DES")
-				alg = TripleDES.Create ();
-			else
-				throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", alg_type));
-
-			alg.Key = MachineKeySectionUtils.DecryptionKey192Bits (section);
-			return alg;
+			sa.Key = section.GetDecryptionKey ();
+			return sa;
 		}
 
 		internal const int SALT_BYTES = 16;
 		protected virtual byte [] DecryptPassword (byte [] encodedPassword)
 		{
-			using (SymmetricAlgorithm alg = GetAlg ()) {
-				// alg.Key is set in GetAlg based on web.config
-				// iv is the first part of the encodedPassword
-				byte [] iv = new byte [alg.IV.Length];
-				Array.Copy (encodedPassword, 0, iv, 0, iv.Length);
-				using (ICryptoTransform decryptor = alg.CreateDecryptor (alg.Key, iv)) {
-					return decryptor.TransformFinalBlock (encodedPassword, iv.Length, encodedPassword.Length - iv.Length);
-				}
+			using (SymmetricAlgorithm sa = GetAlgorithm ()) {
+				return MachineKeySectionUtils.Decrypt (sa, encodedPassword, 0, encodedPassword.Length);
 			}
 		}
 
 		protected virtual byte[] EncryptPassword (byte[] password)
 		{
-			using (SymmetricAlgorithm alg = GetAlg ()) {
-				// alg.Key is set in GetAlg based on web.config
-				// alg.IV is randomly set (default behavior) and perfect for our needs
-				byte [] iv = alg.IV;
-				using (ICryptoTransform encryptor = alg.CreateEncryptor (alg.Key, iv)) {
-					byte [] encrypted = encryptor.TransformFinalBlock (password, 0, password.Length);
-					byte [] output = new byte [iv.Length + encrypted.Length];
-					// note: the IV can be public, however it should not be based on the password
-					Array.Copy (iv, 0, output, 0, iv.Length);
-					Array.Copy (encrypted, 0, output, iv.Length, encrypted.Length);
-					return output;
-				}
+			using (SymmetricAlgorithm sa = GetAlgorithm ()) {
+				return MachineKeySectionUtils.Encrypt (sa, password);
 			}
 		}
 	}
diff --git a/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs b/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
index 36d0211..ece4894 100644
--- a/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
+++ b/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
@@ -31,7 +31,6 @@
 #if NET_2_0
 
 using System.Collections.Specialized;
-using System.Security.Cryptography;
 using System.Security.Permissions;
 using System.Security.Principal;
 using System.Web.Configuration;
@@ -143,42 +142,16 @@ namespace System.Web.Security {
 
 			CookieProtection cookieProtection = RoleManagerConfig.CookieProtection;
 
-			if (cookieProtection == CookieProtection.None)
-				return GetBase64FromBytes (ticket.GetBuffer (), 0, (int) ticket.Position);
-			
-			if (cookieProtection == CookieProtection.All || cookieProtection == CookieProtection.Validation) {
-
-				byte [] hashBytes = null;
-				byte [] validationBytes = MachineKeySectionUtils.ValidationKeyBytes (MachineConfig);
-				writer.Write (validationBytes);
-
-				switch (MachineConfig.Validation) {
-					case MachineKeyValidation.MD5:
-						hashBytes = MD5.Create ().ComputeHash (ticket.GetBuffer (), 0, (int) ticket.Position);
-						break;
-
-					case MachineKeyValidation.TripleDES:
-					case MachineKeyValidation.SHA1:
-						hashBytes = SHA1.Create ().ComputeHash (ticket.GetBuffer (), 0, (int) ticket.Position);
-						break;
-				}
-
-				writer.Seek (-validationBytes.Length, SeekOrigin.Current);
-				writer.Write (hashBytes);
-			}
-
-			byte [] ticketBytes = null;
-			if (cookieProtection == CookieProtection.All || cookieProtection == CookieProtection.Encryption) {
-				ICryptoTransform enc;
-				enc = TripleDES.Create ().CreateEncryptor (MachineKeySectionUtils.DecryptionKey192Bits (MachineConfig),
-									   InitVector);
-				ticketBytes = enc.TransformFinalBlock (ticket.GetBuffer (), 0, (int) ticket.Position);
+			byte[] ticket_data = ticket.GetBuffer ();
+			if (cookieProtection == CookieProtection.All) {
+				ticket_data = MachineKeySectionUtils.EncryptSign (MachineConfig, ticket_data);
+			} else if (cookieProtection == CookieProtection.Encryption) {
+				ticket_data = MachineKeySectionUtils.Encrypt (MachineConfig, ticket_data);
+			} else if (cookieProtection == CookieProtection.Validation) {
+				ticket_data = MachineKeySectionUtils.Sign (MachineConfig, ticket_data);
 			}
 
-			if (ticketBytes == null)
-				return GetBase64FromBytes (ticket.GetBuffer (), 0, (int) ticket.Position);
-			else
-				return GetBase64FromBytes (ticketBytes, 0, ticketBytes.Length);
+			return GetBase64FromBytes (ticket_data, 0, ticket_data.Length);
 		}
 
 		void DecryptTicket (string encryptedTicket)
@@ -190,45 +163,18 @@ namespace System.Web.Security {
 			byte [] decryptedTicketBytes = null;
 
 			CookieProtection cookieProtection = RoleManagerConfig.CookieProtection;
-			if (cookieProtection == CookieProtection.All || cookieProtection == CookieProtection.Encryption) {
-				ICryptoTransform decryptor;
-				decryptor = TripleDES.Create ().CreateDecryptor (
-					MachineKeySectionUtils.DecryptionKey192Bits (MachineConfig),
-					InitVector);
-				decryptedTicketBytes = decryptor.TransformFinalBlock (ticketBytes, 0, ticketBytes.Length);
-			}
-			else
-				decryptedTicketBytes = ticketBytes;
-
-			if (cookieProtection == CookieProtection.All || cookieProtection == CookieProtection.Validation) {
-				byte [] validationBytes = MachineKeySectionUtils.ValidationKeyBytes (MachineConfig);
-				byte [] rolesWithValidationBytes = null;
-				byte [] tmpValidation = null;
 
-				int hashSize = (MachineConfig.Validation == MachineKeyValidation.MD5) ? 16 : 20; //md5 is 16 bytes, sha1 is 20 bytes
-
-				rolesWithValidationBytes = new byte [decryptedTicketBytes.Length - hashSize + validationBytes.Length];
-
-				Buffer.BlockCopy (decryptedTicketBytes, 0, rolesWithValidationBytes, 0, decryptedTicketBytes.Length - hashSize);
-				Buffer.BlockCopy (validationBytes, 0, rolesWithValidationBytes, decryptedTicketBytes.Length - hashSize, validationBytes.Length);
-
-				switch (MachineConfig.Validation) {
-					case MachineKeyValidation.MD5:
-						tmpValidation = MD5.Create ().ComputeHash (rolesWithValidationBytes);
-						break;
-
-					case MachineKeyValidation.TripleDES:
-					case MachineKeyValidation.SHA1:
-						tmpValidation = SHA1.Create ().ComputeHash (rolesWithValidationBytes);
-						break;
-				}
-				for (int i = 0; i < tmpValidation.Length; i++) {
-					if (i >= decryptedTicketBytes.Length ||
-						tmpValidation [i] != decryptedTicketBytes [i + decryptedTicketBytes.Length - hashSize])
-						throw new HttpException ("ticket validation failed");
-				}
+			if (cookieProtection == CookieProtection.All) {
+				decryptedTicketBytes = MachineKeySectionUtils.VerifyDecrypt (MachineConfig, ticketBytes);
+			} else if (cookieProtection == CookieProtection.Encryption) {
+				decryptedTicketBytes = MachineKeySectionUtils.Decrypt (MachineConfig, ticketBytes);
+			} else if (cookieProtection == CookieProtection.Validation) {
+				decryptedTicketBytes = MachineKeySectionUtils.Verify (MachineConfig, ticketBytes);
 			}
 
+			if (decryptedTicketBytes == null)
+				throw new HttpException ("ticket validation failed");
+
 			MemoryStream ticket = new MemoryStream (decryptedTicketBytes);
 			BinaryReader reader = new BinaryReader (ticket);
 
@@ -273,11 +219,6 @@ namespace System.Web.Security {
 				_cachedRoles.Add (r, r);
 		}
 
-		byte [] InitVector
-		{
-			get { return new byte [] { 1, 2, 3, 4, 5, 6, 7, 8 }; }
-		}
-		
 		public bool CachedListChanged {
 			get { return _listChanged; }
 		}
diff --git a/mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs b/mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
index e8778a4..a042f4c 100644
--- a/mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
+++ b/mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
@@ -1048,11 +1048,22 @@ namespace System.Web.Security {
 
 					MembershipSection section = (MembershipSection) WebConfigurationManager.GetSection ("system.web/membership");
 					string alg_type = section.HashAlgorithmType;
-					if (alg_type == "") {
-						MachineKeySection keysection = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
-						alg_type = keysection.Validation.ToString ();
+					if (alg_type.Length == 0) {
+						alg_type = MachineKeySection.Config.Validation.ToString ();
+#if NET_4_0
+						// support new (4.0) custom algorithms
+						if (alg_type.StartsWith ("alg:"))
+							alg_type = alg_type.Substring (4);
+#endif
 					}
 					using (HashAlgorithm hash = HashAlgorithm.Create (alg_type)) {
+#if NET_4_0
+						// for compatibility (with 2.0) we'll allow MD5 and SHA1 not to map to HMACMD5 and HMACSHA1
+						// but that won't work with new (4.0) algorithms, like HMACSHA256|384|512 or custom, won't work without using the key
+						KeyedHashAlgorithm kha = (hash as KeyedHashAlgorithm);
+						if (kha != null)
+							kha.Key = MachineKeySection.Config.GetValidationKey ();
+#endif
 						hash.TransformFinalBlock (hashBytes, 0, hashBytes.Length);
 						return Convert.ToBase64String (hash.Hash);
 					}
diff --git a/mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs b/mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
index f7be4be..2acff57 100644
--- a/mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
+++ b/mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
@@ -1432,7 +1432,7 @@ namespace System.Web.Security
 				case MembershipPasswordFormat.Hashed:
 					HMACSHA1 hash = new HMACSHA1();
 					if (machineKeyIsAutoGenerated)
-						hash.Key = MachineKeySectionUtils.ValidationKeyBytes ();
+						hash.Key = MachineKeySection.Config.GetValidationKey ();
 					else
 						hash.Key = HexToByte(m_MachineKey.ValidationKey);
 					encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
diff --git a/mcs/class/System.Web/System.Web.SessionState/SessionId.cs b/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
index c1eac4d..2161745 100644
--- a/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
+++ b/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
@@ -28,15 +28,12 @@
 
 using System.Text;
 using System.Security.Cryptography;
+using System.Web.Configuration;
 
 namespace System.Web.SessionState {
 
 	internal class SessionId {
 
-		static char [] allowed = { '0', '1', '2', '3', '4', '5',
-						   '6', '7', '8', '9', 'A', 'B',
-						   'C', 'D', 'E', 'F' };
-
 		internal const int IdLength = 24;
 		const int half_len = IdLength / 2;
 		static RandomNumberGenerator rng = RandomNumberGenerator.Create ();
@@ -48,25 +45,9 @@ namespace System.Web.SessionState {
 			lock (rng) {
 				rng.GetBytes (key);
 			}
-			return Encode (key);
+			return MachineKeySectionUtils.GetHexString (key);
 		}
 
-		internal static string Encode (byte[] key)
-		{
-			if (key == null)
-				throw new ArgumentNullException ("key");
-			if (key.Length != half_len)
-				throw new ArgumentException (String.Concat ("key must be ", half_len.ToString (), " bytes long."));
-
-			// Just a standard hex conversion
-			char[] res = new char [IdLength];
-			for (int i=0; i < half_len; i++) {
-				int b = key [i];
-				res [i * 2] = allowed [b >> 4];
-				res [(i * 2) + 1] = allowed [b & 0xF];
-			}
-			return new String (res);
-		}
 #if !NET_2_0
 		internal static string Lookup (HttpRequest request, bool cookieless)
 		{
diff --git a/mcs/class/System.Web/System.Web.UI/LosFormatter.cs b/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
index d146e18..4cb250d 100644
--- a/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
+++ b/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
@@ -28,10 +28,11 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System.Configuration;
 using System.IO;
-using System.Security.Cryptography;
 using System.Security.Permissions;
 using System.Text;
+using System.Web.Configuration;
 
 namespace System.Web.UI {
 
@@ -48,11 +49,14 @@ namespace System.Web.UI {
 
 #if NET_1_1
 		public LosFormatter (bool enableMac, string macKeyModifier)
-			: this (enableMac, Convert.FromBase64String (macKeyModifier))
 		{
+			osf = new ObjectStateFormatter ();
+			if (enableMac && macKeyModifier != null && macKeyModifier.Length > 0) {
+				SetMacKey (Convert.FromBase64String (macKeyModifier));
+			}
 		}
 #endif
-		[MonoTODO]
+
 #if NET_2_0
 		public
 #else
@@ -60,25 +64,53 @@ namespace System.Web.UI {
 #endif
 		LosFormatter (bool enableMac, byte[] macKeyModifier)
 		{
-			if (enableMac)
-				osf = new ObjectStateFormatter (macKeyModifier);
-			else
-				osf = new ObjectStateFormatter ();
+			osf = new ObjectStateFormatter ();
+			if (enableMac && (macKeyModifier != null)) {
+				SetMacKey (macKeyModifier);
+			}
 		}
 
+		void SetMacKey (byte[] macKeyModifier)
+		{
+			try {
+#if NET_2_0
+				osf.Section.ValidationKey = MachineKeySectionUtils.GetHexString (macKeyModifier);
+#else
+				osf.Section.SetValidationKey (MachineKeySectionUtils.GetHexString (macKeyModifier));
+#endif
+			}
+			catch (ArgumentException) {
+			}
+#if NET_2_0
+			catch (ConfigurationErrorsException) {
+				// bad key (e.g. size), default key will be used
+			}
+#else
+			catch (HttpException) {
+				// bad key (e.g. size), default key will be used
+			}
+#endif
+                }
+		
 		public object Deserialize (Stream stream)
 		{
 			if (stream == null)
 				throw new ArgumentNullException ("stream");
+#if NET_4_0
+			using (StreamReader sr = new StreamReader (stream)) {
+				return Deserialize (sr.ReadToEnd ());
+			}
+#else
 			long streamLength = -1;
 			if (stream.CanSeek)
 				streamLength = stream.Length;
-			byte [] bytes = new byte [streamLength >= 0 ? streamLength : 2048];
+			
 			MemoryStream ms = null;
 			if (streamLength  != -1 && (stream is MemoryStream) && stream.Position == 0) {
 				// We save allocating a new stream and reading in this case.
 				ms = (MemoryStream) stream;
 			} else {
+				byte [] bytes = new byte [streamLength >= 0 ? streamLength : 2048];	
 				ms = new MemoryStream ();
 				int n;
 				while ((n = stream.Read (bytes, 0, bytes.Length)) > 0)
@@ -89,6 +121,7 @@ namespace System.Web.UI {
 			string b64 = Encoding.ASCII.GetString (ms.GetBuffer (),
 				0, (int) streamLength);
 			return Deserialize (b64);
+#endif
 		}
 
 		public object Deserialize (TextReader input)
@@ -116,7 +149,10 @@ namespace System.Web.UI {
 		{
 			if (stream == null)
 				throw new ArgumentNullException ("stream");
-
+#if NET_4_0
+			if (!stream.CanSeek)
+				throw new NotSupportedException ();
+#endif
 			string b64 = SerializeToBase64 (value);
 			byte [] bytes = Encoding.ASCII.GetBytes (b64);
 			stream.Write (bytes, 0, bytes.Length);
diff --git a/mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs b/mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
index a73e4af..20cb068 100644
--- a/mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
+++ b/mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
@@ -44,7 +44,6 @@ using System.Text;
 using System.Web.UI.WebControls;
 using System.Web.Util;
 using System.Diagnostics;
-using System.Security.Cryptography;
 using System.Web.Configuration;
 
 namespace System.Web.UI {
@@ -56,9 +55,11 @@ namespace System.Web.UI {
 	sealed class ObjectStateFormatter : IFormatter, IStateFormatter
 	{
 		Page page;
-		HashAlgorithm algo;
-		byte [] vkey;
-
+#if NET_2_0
+		MachineKeySection section;
+#else
+		MachineKeyConfig section;
+#endif
 		public ObjectStateFormatter ()
 		{
 		}
@@ -67,18 +68,11 @@ namespace System.Web.UI {
 		{
 			this.page = page;
 		}
-
-		internal ObjectStateFormatter (byte [] vkey)
-		{
-			this.vkey = vkey;
-		}
 		
-		internal bool EnableMac {
+		bool EnableMac {
 			get {
 				if (page == null) {
-					if (vkey == null)
-						return false;
-					return true;
+					return section != null;
 				} else {
 				
 #if NET_2_0
@@ -92,48 +86,44 @@ namespace System.Web.UI {
 			}
 		}
 
-		internal HashAlgorithm GetAlgo ()
-		{
-			if (algo != null)
-				return algo;
-			if (!EnableMac)
-				return null;
-			
-			byte [] algoKey;
-			if (page != null) {
+		bool NeedViewStateEncryption {
+			get {
 #if NET_2_0
-				MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
-				algoKey = MachineKeySectionUtils.ValidationKeyBytes (mconfig);
+				return (page == null) ? false : page.NeedViewStateEncryption;
 #else
-				MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
-				algoKey = mconfig.ValidationKey;
+				return false;
 #endif
-			} else
-				algoKey = vkey;
-
-			algo = new HMACSHA1 (algoKey);
-			return algo;
+			}
 		}
-
-		static int ValidateInput (HashAlgorithm algo, byte [] data, int offset, int size)
-		{
-			if (algo == null)
-				throw new HttpException ("Unable to validate data.");
-			
-			int hash_size = algo.HashSize / 8;
-			if (size != 0 && size < hash_size)
-				throw new HttpException ("Unable to validate data.");
-
-			int data_length = size - hash_size;
-			MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false);
-			byte [] hash = algo.ComputeHash (data_stream);
-			for (int i = 0; i < hash_size; i++) {
-				if (hash [i] != data [data_length + i])
-					throw new HttpException ("Unable to validate data.");
-			}
-			return data_length;
+#if NET_2_0
+		internal MachineKeySection Section {
+			get {
+				if (section == null)
+					section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
+				return section;
+			}
+			set {
+				section = value;
+			}
 		}
-		
+#else
+		internal MachineKeyConfig Section {
+			get {
+				if (section == null) {
+					HttpContext context = HttpContext.Current;
+					if (context == null)
+						section = new MachineKeyConfig (null);
+					else
+						section = (MachineKeyConfig) context.GetConfig ("system.web/machineKey");
+				}
+				
+				return section;
+			}
+			set {
+				section = value;
+			}
+		}
+#endif		
 		public object Deserialize (Stream inputStream)
 		{
 			if (inputStream == null)
@@ -153,21 +143,25 @@ namespace System.Web.UI {
 			if (inputString == "")
 				return "";
 #endif
-			byte [] buffer = Convert.FromBase64String (inputString);
-			int length;
-			if (buffer == null || (length = buffer.Length) == 0)
+			byte [] data = Convert.FromBase64String (inputString);
+			if (data == null || (data.Length) == 0)
 				throw new ArgumentNullException ("inputString");
-			if (page != null && EnableMac)
-				length = ValidateInput (GetAlgo (), buffer, 0, length);
-#if NET_2_0
-			bool isEncrypted = ((int)buffer [--length] == 1)? true : false;
-#endif
-			Stream ms = new MemoryStream (buffer, 0, length, false, false);
-#if NET_2_0
-			if (isEncrypted)
-				ms = new CryptoStream (ms, page.GetCryptoTransform (CryptoStreamMode.Read), CryptoStreamMode.Read);
-#endif
-			return Deserialize (ms);
+			if (NeedViewStateEncryption) {
+				if (EnableMac) {
+					data = MachineKeySectionUtils.VerifyDecrypt (Section, data);
+				} else {
+					data = MachineKeySectionUtils.Decrypt (Section, data);
+				}
+			} else if (EnableMac) {
+				data = MachineKeySectionUtils.Verify (Section, data);
+			}
+
+			if (data == null)
+				throw new HttpException ("Unable to validate data.");
+
+			using (MemoryStream ms = new MemoryStream (data)) {
+				return Deserialize (ms);
+			}
 		}
 		
 		public string Serialize (object stateGraph)
@@ -175,31 +169,23 @@ namespace System.Web.UI {
 			if (stateGraph == null)
 				return "";
 			
-			MemoryStream ms = new MemoryStream ();
-			Stream output = ms;
-#if NET_2_0
-			bool needEncryption = page == null ? false : page.NeedViewStateEncryption;
-			if (needEncryption){
-				output = new CryptoStream (output, page.GetCryptoTransform (CryptoStreamMode.Write), CryptoStreamMode.Write);
+			byte[] data = null;
+			using (MemoryStream ms = new MemoryStream ()) {
+				Serialize (ms, stateGraph);
+				data = ms.GetBuffer ();
 			}
-#endif
-			Serialize (output, stateGraph);
-#if NET_2_0
-			ms.WriteByte((byte)(needEncryption? 1 : 0));
-#endif
-			
-#if TRACE
-			ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
-#endif
-			if (EnableMac && ms.Length > 0) {
-				HashAlgorithm algo = GetAlgo ();
-				if (algo != null) {
-					byte [] hash = algo.ComputeHash (ms.GetBuffer (), 0, (int) ms.Length);
-					ms.Write (hash, 0, hash.Length);
+
+			if (NeedViewStateEncryption) {
+				if (EnableMac) {
+					data = MachineKeySectionUtils.EncryptSign (Section, data);
+				} else {
+					data = MachineKeySectionUtils.Encrypt (Section, data);
 				}
-				
+			} else if (EnableMac) {
+				data = MachineKeySectionUtils.Sign (Section, data);
+
 			}
-			return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
+			return Convert.ToBase64String (data, 0, data.Length);
 		}
 		
 		public void Serialize (Stream outputStream, object stateGraph)
diff --git a/mcs/class/System.Web/System.Web.UI/Page.cs b/mcs/class/System.Web/System.Web.UI/Page.cs
index ad13eaf..3522767 100644
--- a/mcs/class/System.Web/System.Web.UI/Page.cs
+++ b/mcs/class/System.Web/System.Web.UI/Page.cs
@@ -38,7 +38,6 @@ using System.ComponentModel.Design;
 using System.ComponentModel.Design.Serialization;
 using System.Globalization;
 using System.IO;
-using System.Security.Cryptography;
 using System.Security.Permissions;
 using System.Security.Principal;
 using System.Text;
@@ -2535,74 +2534,6 @@ public partial class Page : TemplateControl, IHttpHandler
 		controlRegisteredForViewStateEncryption = true;
 	}
 
-	static byte [] AES_IV = null;
-	static byte [] TripleDES_IV = null;
-	static object locker = new object ();
-	static bool isEncryptionInitialized = false;
-
-	static void InitializeEncryption () 
-	{
-		if (isEncryptionInitialized)
-			return;
-
-		lock (locker) {
-			if (isEncryptionInitialized)
-				return;
-
-			string iv_string = "0BA48A9E-736D-40f8-954B-B2F62241F282";
-			AES_IV = new byte [16];
-			TripleDES_IV = new byte [8];
-
-			int i;
-			for (i = 0; i < AES_IV.Length; i++) {
-				AES_IV [i] = (byte) iv_string [i];
-			}
-
-			for (i = 0; i < TripleDES_IV.Length; i++) {
-				TripleDES_IV [i] = (byte) iv_string [i];
-			}
-
-			isEncryptionInitialized = true;
-		}
-	}
-
-	internal ICryptoTransform GetCryptoTransform (CryptoStreamMode cryptoStreamMode) 
-	{
-		ICryptoTransform transform = null;
-		MachineKeySection config = (MachineKeySection) WebConfigurationManager.GetSection (machineKeyConfigPath);
-		byte [] vk = MachineKeySectionUtils.ValidationKeyBytes (config);
-
-		switch (config.Validation) {
-			case MachineKeyValidation.SHA1:
-				transform = SHA1.Create ();
-				break;
-
-			case MachineKeyValidation.MD5:
-				transform = MD5.Create ();
-				break;
-
-			case MachineKeyValidation.AES:
-				InitializeEncryption ();
-				if (cryptoStreamMode == CryptoStreamMode.Read){
-					transform = Rijndael.Create().CreateDecryptor(vk, AES_IV);
-				} else {
-					transform = Rijndael.Create().CreateEncryptor(vk, AES_IV);
-				}
-				break;
-
-			case MachineKeyValidation.TripleDES:
-				InitializeEncryption ();
-				if (cryptoStreamMode == CryptoStreamMode.Read){
-					transform = TripleDES.Create().CreateDecryptor(vk, TripleDES_IV);
-				} else {
-					transform = TripleDES.Create().CreateEncryptor(vk, TripleDES_IV);
-				}
-				break;
-		}
-
-		return transform;
-	}
-
 	internal bool NeedViewStateEncryption {
 		get {
 			return (ViewStateEncryptionMode == ViewStateEncryptionMode.Always ||
diff --git a/mcs/class/System.Web/System.Web.dll.sources b/mcs/class/System.Web/System.Web.dll.sources
index 6e4e12e..16087d1 100644
--- a/mcs/class/System.Web/System.Web.dll.sources
+++ b/mcs/class/System.Web/System.Web.dll.sources
@@ -7,6 +7,7 @@ Assembly/AssemblyInfo.cs
 ../Managed.Windows.Forms/System.Resources/ResXFileRef.cs
 ../Managed.Windows.Forms/System.Resources/ResXDataNode.cs
 ../Managed.Windows.Forms/System.Resources/ResXNullRef.cs
+../Mono.Security/Mono.Security.Cryptography/TlsHMAC.cs
 System.Web.Configuration_2.0/CapabilitiesBuild.cs
 System.Web.Configuration_2.0/CapabilitiesResult.cs
 System.Web.Configuration_2.0/ICapabilitiesProcess.cs
diff --git a/mcs/class/System.Web/System.Web_test.dll.sources b/mcs/class/System.Web/System.Web_test.dll.sources
index b1f8fe4..e40268f 100644
--- a/mcs/class/System.Web/System.Web_test.dll.sources
+++ b/mcs/class/System.Web/System.Web_test.dll.sources
@@ -85,6 +85,8 @@ System.Web.Configuration/CustomErrorCollectionTest.cs
 System.Web.Configuration/DeploymentSectionTest.cs
 System.Web.Configuration/GlobalizationSectionTest.cs
 System.Web.Configuration/HostingEnvironmentSectionTest.cs
+System.Web.Configuration/MachineKeySectionTest.cs
+System.Web.Configuration/MachineKeySectionUtilsTest.cs
 System.Web.Configuration/MachineKeyValidationConverterTest.cs
 System.Web.Configuration/NullableStringValidatorTest.cs
 System.Web.Configuration/ProfilePropertySettingsTest.cs
diff --git a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
new file mode 100644
index 0000000..ac5fce8
--- /dev/null
+++ b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
@@ -0,0 +1,158 @@
+//
+// Unit tests for MachineKeySection
+//
+// Author:
+//	Sebastien Pouliot  <sebastien@ximian.com>
+//
+// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Configuration;
+using System.Web.Configuration;
+using NUnit.Framework;
+
+namespace MonoTests.System.Web.Configuration {
+
+	[TestFixture]
+	public class MachineKeySectionTest {
+
+		[Test]
+		public void DefaultValues ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+#if NET_4_0
+			Assert.AreEqual (MachineKeyCompatibilityMode.Framework20SP1, section.CompatibilityMode, "CompatibilityMode");
+#endif
+			Assert.AreEqual ("Auto", section.Decryption, "Decryption");
+			Assert.AreEqual ("AutoGenerate,IsolateApps", section.DecryptionKey, "DecryptionKey");
+#if NET_4_0
+			Assert.AreEqual (MachineKeyValidation.HMACSHA256, section.Validation, "Validation");
+			Assert.AreEqual ("HMACSHA256", section.ValidationAlgorithm, "ValidationAlgorithm");
+#else
+			Assert.AreEqual (MachineKeyValidation.SHA1, section.Validation, "Validation");
+#endif
+			Assert.AreEqual ("AutoGenerate,IsolateApps", section.ValidationKey, "ValidationKey");
+		}
+
+		[Test]
+#if NET_4_0
+		[ExpectedException (typeof (NullReferenceException))]
+#else
+		[ExpectedException (typeof (ConfigurationErrorsException))]
+#endif
+		public void Decryption_Null ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Decryption = null;
+		}
+
+		[Test]
+		[ExpectedException (typeof (ConfigurationErrorsException))]
+		public void Decryption_Empty ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Decryption = String.Empty;
+		}
+#if NET_4_0
+		[Test]
+		public void Decryption_RC2 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			Assert.AreEqual ("Auto", section.Decryption, "before");
+
+			section.Decryption = "alg:RC2";
+			Assert.AreEqual ("alg:RC2", section.Decryption, "after");
+		}
+
+		[Test]
+		public void Decryption_InvalidName ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			Assert.AreEqual ("Auto", section.Decryption, "before");
+
+			section.Decryption = "alg:UnexistingType";
+			// looks like the problem is found (much) later
+			Assert.AreEqual ("alg:UnexistingType", section.Decryption, "Decryption");
+		}
+
+		[Test]
+		public void ValidationAlgorithm_Null ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = null;
+			Assert.AreEqual ("HMACSHA256", section.ValidationAlgorithm, "ValidationAlgorithm");
+		}
+
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void ValidationAlgorithm_Empty ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = String.Empty;
+		}
+
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void Validation_Custom ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.Custom;
+			// cannot be set directly
+		}
+
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void ValidationAlgorithm ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = "HMACRIPEMD160";
+			// syntax is: alg:something-deriving-from-KeyedHashAlgorithm
+		}
+
+		[Test]
+		public void ValidationAlgorithm_RIPEMD160 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			Assert.AreEqual (MachineKeyValidation.HMACSHA256, section.Validation, "before");
+
+			section.ValidationAlgorithm = "alg:HMACRIPEMD160";
+			Assert.AreEqual (MachineKeyValidation.Custom, section.Validation, "after");
+			Assert.AreEqual ("alg:HMACRIPEMD160", section.ValidationAlgorithm, "ValidationAlgorithm");
+		}
+
+		[Test]
+		public void ValidationAlgorithm_InvalidName ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			Assert.AreEqual (MachineKeyValidation.HMACSHA256, section.Validation, "before");
+
+			section.ValidationAlgorithm = "alg:UnexistingType";
+			// looks like the problem is found (much) later
+			Assert.AreEqual (MachineKeyValidation.Custom, section.Validation, "after");
+			Assert.AreEqual ("alg:UnexistingType", section.ValidationAlgorithm, "ValidationAlgorithm");
+		}
+#endif
+	}
+}
+
+#endif
diff --git a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
new file mode 100644
index 0000000..3564cc0
--- /dev/null
+++ b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
@@ -0,0 +1,310 @@
+//
+// Unit tests for MachineKeySectionUtils (internals)
+//
+// Author:
+//	Sebastien Pouliot  <sebastien@ximian.com>
+//
+// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.IO;
+using System.Web.Configuration;
+using NUnit.Framework;
+
+namespace MonoTests.System.Web.Configuration {
+
+	[TestFixture]
+	public class MachineKeySectionUtilsTest {
+
+		public void Encrypt_RoundTrip (MachineKeySection section)
+		{
+			byte [] data = new byte [14];
+			byte [] encdata = MachineKeySectionUtils.Encrypt (section, data);
+			byte [] decdata = MachineKeySectionUtils.Decrypt (section, encdata);
+			Assert.AreEqual (data, decdata, "roundtrip");
+
+			// changing length (missing first byte)
+			byte [] cut = new byte [encdata.Length - 1];
+			Array.Copy (encdata, 1, cut, 0, cut.Length);
+			Assert.IsNull (MachineKeySectionUtils.Decrypt (section, cut), "bad length");
+
+			// changing last byte (padding)
+			byte be = encdata [encdata.Length - 1];
+			encdata [encdata.Length - 1] ^= (byte) (be + 1);
+			Assert.IsNull (MachineKeySectionUtils.Decrypt (section, encdata), "bad padding");
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_Default ()
+		{
+			Encrypt_RoundTrip (new MachineKeySection ());
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_AES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.AES;
+			Encrypt_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_TripleDES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.TripleDES;
+			Encrypt_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_MD5 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.MD5;
+			Encrypt_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_SHA1 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.SHA1;
+			Encrypt_RoundTrip (section);
+		}
+#if NET_4_0
+		[Test]
+		public void Encrypt_RoundTrip_HMACSHA256 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA256;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_HMACSHA384 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA384;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_HMACSHA512 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA512;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void Encrypt_RoundTrip_Custom_RIPEMD160 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = "alg:HMACRIPEMD160";
+			EncryptSign_RoundTrip (section);
+		}
+#endif
+		public void EncryptSign_RoundTrip (MachineKeySection section)
+		{
+			byte [] data = new byte [14];
+			byte [] block = MachineKeySectionUtils.EncryptSign (section, data);
+			byte [] decdata = MachineKeySectionUtils.VerifyDecrypt (section, block);
+			Assert.AreEqual (data, decdata, "roundtrip");
+
+			// changing a byte of the data
+			byte b0 = block [0];
+			block [0] ^= b0;
+			Assert.IsNull (MachineKeySectionUtils.VerifyDecrypt (section, block), "bad data");
+			block [0] = b0;
+
+			// changing a byte of the signature
+			byte be = block [block.Length - 1];
+			block [block.Length - 1] ^= (byte) (be + 1);
+			Assert.IsNull (MachineKeySectionUtils.VerifyDecrypt (section, block), "bad signature");
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_Default ()
+		{
+			EncryptSign_RoundTrip (new MachineKeySection ());
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_AES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.AES;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_TripleDES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.TripleDES;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_MD5 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.MD5;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_SHA1 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.SHA1;
+			EncryptSign_RoundTrip (section);
+		}
+#if NET_4_0
+		[Test]
+		public void EncryptSign_RoundTrip_HMACSHA256 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA256;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_HMACSHA384 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA384;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_HMACSHA512 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA512;
+			EncryptSign_RoundTrip (section);
+		}
+
+		[Test]
+		public void EncryptSign_RoundTrip_Custom_RIPEMD160 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = "alg:HMACRIPEMD160";
+			EncryptSign_RoundTrip (section);
+		}
+#endif
+		public void Validation_RoundTrip (MachineKeySection section)
+		{
+			byte [] data = new byte [] { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 };
+			byte [] block = MachineKeySectionUtils.Sign (section, data);
+			Assert.AreEqual (data, MachineKeySectionUtils.Verify (section, block), "OK");
+
+			// changing last byte
+			for (int i = 0; i < data.Length; i++) {
+				byte b = block [i];
+				block [i] ^= 0xFF;
+				Assert.IsNull (MachineKeySectionUtils.Verify (section, block), "bad-" + i.ToString ());
+				block [i] = b;
+			}
+		}
+
+		[Test]
+		public void Validation_RoundTrip_Default ()
+		{
+			Validation_RoundTrip (new MachineKeySection ());
+		}
+
+		[Test]
+		public void Validation_RoundTrip_AES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.AES;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_TripleDES ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.TripleDES;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_MD5 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.MD5;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_SHA1 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.SHA1;
+			Validation_RoundTrip (section);
+		}
+
+#if NET_4_0
+		[Test]
+		public void Validation_RoundTrip_HMACSHA256 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA256;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_HMACSHA384 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA384;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_HMACSHA512 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.HMACSHA512;
+			Validation_RoundTrip (section);
+		}
+
+		[Test]
+		public void Validation_RoundTrip_Custom_RIPEMD160 ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.ValidationAlgorithm = "alg:HMACRIPEMD160";
+			Validation_RoundTrip (section);
+		}
+#endif
+		[Test]
+		public void GetHexString ()
+		{
+			Assert.AreEqual ("DEADC0DE", MachineKeySectionUtils.GetHexString (new byte [] { 0xde, 0xad, 0xc0, 0xde }), "deadcode");
+		}
+	}
+}
+
+#endif
diff --git a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs
index 0ed9243..3df6feb 100644
--- a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs
@@ -2,10 +2,11 @@
 // System.Web.Configuration.MachineKeyValidationConverterTest.cs - Unit tests
 // for System.Web.Configuration.MachineKeyValidationConverter.
 //
-// Author:
+// Authors:
 //	Chris Toshok  <toshok@ximian.com>
+//	Sebastien Pouliot  <sebastien@ximian.com>
 //
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005, 2010 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -35,8 +36,7 @@ using NUnit.Framework;
 
 namespace MonoTests.System.Web.Configuration {
 	[TestFixture]
-	public class MachineKeyValidationConverterTest
-	{
+	public class MachineKeyValidationConverterTest {
 		[Test]
 		public void CanConvertFrom ()
 		{
@@ -66,10 +66,46 @@ namespace MonoTests.System.Web.Configuration {
 			object o;
 
 			o = cv.ConvertFrom (null, null, "MD5");
-			Assert.AreEqual (typeof (MachineKeyValidation), o.GetType(), "A1");
-			Assert.AreEqual ("MD5", o.ToString(), "A2");
+			Assert.AreEqual (typeof (MachineKeyValidation), o.GetType (), "typeof");
+			Assert.AreEqual ("MD5", o.ToString (), "MD5");
+
+			o = cv.ConvertFrom (null, null, "SHA1");
+			Assert.AreEqual ("SHA1", o.ToString (), "SHA1");
+
+			// 3DES in, TripleDES out
+			o = cv.ConvertFrom (null, null, "3DES");
+			Assert.AreEqual ("TripleDES", o.ToString (), "3DES");
+
 			o = cv.ConvertFrom (null, null, "AES");
-			Assert.AreEqual ("AES", o.ToString(), "A3");
+			Assert.AreEqual ("AES", o.ToString (), "AES");
+#if NET_4_0
+			o = cv.ConvertFrom (null, null, "HMACSHA256");
+			Assert.AreEqual ("HMACSHA256", o.ToString (), "HMACSHA256");
+
+			o = cv.ConvertFrom (null, null, "HMACSHA384");
+			Assert.AreEqual ("HMACSHA384", o.ToString (), "HMACSHA384");
+
+			o = cv.ConvertFrom (null, null, "HMACSHA512");
+			Assert.AreEqual ("HMACSHA512", o.ToString (), "HMACSHA512");
+#endif
+		}
+
+#if NET_4_0
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void ConvertFrom_Custom ()
+		{
+			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
+			cv.ConvertFrom (null, null, "Custom");
+		}
+#endif
+
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void ConvertFrom_CaseSensitive ()
+		{
+			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
+			cv.ConvertFrom (null, null, "sha1");
 		}
 
 		[Test]
@@ -91,10 +127,29 @@ namespace MonoTests.System.Web.Configuration {
 			Assert.AreEqual ("MD5", cv.ConvertTo (null, null, MachineKeyValidation.MD5, typeof (string)), "A1");
 			Assert.AreEqual ("SHA1", cv.ConvertTo (null, null, MachineKeyValidation.SHA1, typeof (string)), "A2");
 			Assert.AreEqual ("3DES", cv.ConvertTo (null, null, MachineKeyValidation.TripleDES, typeof (string)), "A3");
+#if NET_4_0
+			Assert.AreEqual ("HMACSHA256", cv.ConvertTo (null, null, MachineKeyValidation.HMACSHA256, typeof (string)), "HMACSHA256");
+			Assert.AreEqual ("HMACSHA384", cv.ConvertTo (null, null, MachineKeyValidation.HMACSHA384, typeof (string)), "HMACSHA384");
+			Assert.AreEqual ("HMACSHA512", cv.ConvertTo (null, null, MachineKeyValidation.HMACSHA512, typeof (string)), "HMACSHA512");
+#endif
+		}
+
+#if NET_4_0
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void ConvertTo_Custom ()
+		{
+			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
+			cv.ConvertTo (null, null, MachineKeyValidation.Custom, typeof (string));
 		}
+#endif
 
 		[Test]
+#if NET_4_0
+		[ExpectedException (typeof (ArgumentException))]
+#else
 		[ExpectedException (typeof (NullReferenceException))]
+#endif
 		public void ConvertTo_NullError ()
 		{
 			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
@@ -103,7 +158,11 @@ namespace MonoTests.System.Web.Configuration {
 		}
 
 		[Test]
+#if NET_4_0
+		[ExpectedException (typeof (ArgumentException))]
+#else
 		[ExpectedException (typeof (FormatException))]
+#endif
 		public void ConvertTo_TypeError1 ()
 		{
 			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
@@ -120,6 +179,17 @@ namespace MonoTests.System.Web.Configuration {
 			Assert.AreEqual ("MD5", cv.ConvertTo (null, null, MachineKeyValidation.MD5, null), "A2");
 		}
 
+		[Test]
+#if NET_4_0
+		[ExpectedException (typeof (ArgumentException))]
+#else
+		[ExpectedException (typeof (FormatException))]
+#endif
+		public void ConvertTo_TypeError3 ()
+		{
+			MachineKeyValidationConverter cv = new MachineKeyValidationConverter ();
+			cv.ConvertTo (null, null, (MachineKeyValidation)Int32.MinValue, typeof (string));
+		}
 	}
 }
 
diff --git a/mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs b/mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs
index b31d721..dbad10e 100644
--- a/mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs
@@ -129,6 +129,16 @@ namespace MonoTests.System.Web.Security
 		{
 			FormsAuthentication.RedirectToLoginPage (String.Empty);
 		}
+
+		[Test]
+		[Category ("NotWorking")] // works on .net
+		public void Authenticate ()
+		{
+			Assert.IsFalse (FormsAuthentication.Authenticate (null, "password"), "null,string");
+			Assert.IsFalse (FormsAuthentication.Authenticate ("user", null), "string,null");
+			// not throwing
+			Assert.IsFalse (FormsAuthentication.Authenticate ("user", "password"), "string,string");
+		}
 #endif
 
 		[TestFixtureTearDown]
diff --git a/mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs b/mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs
index 0c6e069..67de9b9 100644
--- a/mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs
@@ -1,6 +1,6 @@
 //
-// MembershipUserCollectionTest.cs
-//	- Unit tests for System.Web.Security.MembershipUserCollection
+// RolePrincipalTest.cs
+//	- Unit tests for System.Web.Security.RolePrincipal
 //
 // Author:
 //	Sebastien Pouliot  <sebastien@ximian.com>
diff --git a/mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs b/mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs
index 2889591..36e1748 100644
--- a/mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs
@@ -1,10 +1,12 @@
 //
 // LosFormatterTest.cs - Unit tests for System.Web.UI.LosFormatter
 //
-// Author:
+// Authors:
 //	Gert Driesen  <drieseng@users.sourceforge.net>
+//	Sebastien Pouliot  <sebastien@ximian.com>
 //
 // Copyright (C) 2007 Gert Driesen
+// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -38,6 +40,148 @@ namespace MonoTests.System.Web.UI
 	[TestFixture]
 	public class LosFormatterTest
 	{
+		static byte [] Empty = new byte [0];
+
+		string Serialize (LosFormatter lf, object value)
+		{
+			StringWriter sw = new StringWriter ();
+			lf.Serialize (sw, value);
+			return sw.ToString ();
+		}
+
+		object Deserialize (LosFormatter lf, string serializedData)
+		{
+			return lf.Deserialize (serializedData);
+		}
+
+		string NoKeyRoundTrip (LosFormatter lf, string assertionMessage)
+		{
+			string serializedData = Serialize (lf, "Mono");
+			Assert.AreEqual ("Mono", (string) Deserialize (lf, serializedData), assertionMessage);
+			return serializedData;
+		}
+
+#if NET_2_0
+		[Test]
+		public void Ctor_BoolByteArray ()
+		{
+			LosFormatter lf1 = new LosFormatter (false, (byte []) null);
+			string expected = NoKeyRoundTrip (lf1, "false, null");
+
+			LosFormatter lf2 = new LosFormatter (true, (byte []) null);
+			Assert.AreEqual (expected, NoKeyRoundTrip (lf2, "true, null"), "2");
+
+			LosFormatter lf3 = new LosFormatter (false, Empty);
+			Assert.AreEqual (expected, NoKeyRoundTrip (lf3, "false, empty"), "3");
+
+			// an empty key is still a key - a signature is appended
+			LosFormatter lf4 = new LosFormatter (true, Empty);
+			string signed = NoKeyRoundTrip (lf4, "true, empty");
+			Assert.AreNotEqual (expected, signed, "4");
+
+			byte [] data = Convert.FromBase64String (expected);
+			byte [] signed_data = Convert.FromBase64String (signed);
+			Assert.IsTrue (BitConverter.ToString (signed_data).StartsWith (BitConverter.ToString (data)), "4 / same data");
+#if NET_4_0
+			// 32 bytes == 256 bits -> match HMACSHA256 as default
+			Assert.AreEqual (32, signed_data.Length - data.Length, "signature length");
+#else
+			// 20 bytes == 160 bits -> match HMACSHA1 as default
+			Assert.AreEqual (20, signed_data.Length - data.Length, "signature length");
+#endif
+		}
+#endif
+		[Test]
+		public void Ctor_BoolString ()
+		{
+			LosFormatter lf1 = new LosFormatter (false, (string) null);
+			string expected = NoKeyRoundTrip (lf1, "false, null");
+
+			LosFormatter lf2 = new LosFormatter (true, (string) null);
+			Assert.AreEqual (expected, NoKeyRoundTrip (lf2, "true, null"), "2");
+
+			LosFormatter lf3 = new LosFormatter (false, String.Empty);
+			Assert.AreEqual (expected, NoKeyRoundTrip (lf3, "false, empty"), "3");
+
+			// an empty string is not an empty key!
+			LosFormatter lf4 = new LosFormatter (true, String.Empty);
+			Assert.AreEqual (expected, NoKeyRoundTrip (lf4, "true, empty"), "4");
+
+			byte [] key = new byte [32];
+			LosFormatter lf5 = new LosFormatter (true, Convert.ToBase64String (key));
+			string signed = NoKeyRoundTrip (lf5, "true, b64");
+			Assert.AreNotEqual (expected, signed, "5");
+
+			byte [] data = Convert.FromBase64String (expected);
+			byte [] signed_data = Convert.FromBase64String (signed);
+			Assert.IsTrue (BitConverter.ToString (signed_data).StartsWith (BitConverter.ToString (data)), "5 / same data");
+#if NET_4_0
+			// 32 bytes == 256 bits -> match HMACSHA256 as default
+			Assert.AreEqual (32, signed_data.Length - data.Length, "signature length");
+#elif NET_2_0
+			// 20 bytes == 160 bits -> match HMACSHA1 as default
+			Assert.AreEqual (20, signed_data.Length - data.Length, "signature length");
+#else
+			Assert.AreEqual (16, signed_data.Length - data.Length, "signature length");
+#endif
+		}
+
+		string SerializeOverloads (LosFormatter lf, string message)
+		{
+			string stream_ser;
+			using (MemoryStream ms = new MemoryStream ()) {
+				lf.Serialize (ms, String.Empty);
+				stream_ser = Convert.ToBase64String (ms.ToArray ());
+			}
+
+			string tw_ser;
+			using (MemoryStream ms = new MemoryStream ()) {
+				using (TextWriter tw = new StreamWriter (ms)) {
+					lf.Serialize (tw, String.Empty);
+				}
+				tw_ser = Convert.ToBase64String (ms.ToArray ());
+			}
+
+			Assert.AreEqual (stream_ser, tw_ser, message);
+			return stream_ser;
+		}
+
+		[Test]
+		public void SerializeOverloads ()
+		{
+			LosFormatter lf1 = new LosFormatter (false, (string) null);
+			string r1 = SerializeOverloads (lf1, "false, null");
+
+			LosFormatter lf2 = new LosFormatter (true, (string) null);
+			string r2 = SerializeOverloads (lf2, "true, null");
+			Assert.AreEqual (r1, r2, "r1-r2");
+
+			LosFormatter lf3 = new LosFormatter (false, String.Empty);
+			string r3 = SerializeOverloads (lf3, "false, empty");
+			Assert.AreEqual (r2, r3, "r2-r3");
+
+			// an empty string is not an empty key!
+			LosFormatter lf4 = new LosFormatter (true, String.Empty);
+			string r4 = SerializeOverloads (lf4, "true, empty");
+			Assert.AreEqual (r3, r4, "r3-r4");
+
+			byte [] key = new byte [32];
+			LosFormatter lf5 = new LosFormatter (true, Convert.ToBase64String (key));
+			string r5 = SerializeOverloads (lf5, "false, b64");
+			Assert.AreNotEqual (r4, r5, "r4-r5");
+		}
+
+#if NET_4_0
+		[Test]
+		[ExpectedException (typeof (NotSupportedException))]
+		public void Deserialize_Stream_NonSeekable ()
+		{
+			string s1 = "Hello world";
+			NonSeekableStream ns = new NonSeekableStream ();
+			LosFormatter lf = new LosFormatter ();
+			lf.Serialize (ns, s1);
+		}
+#else
 		[Test] // bug #411115
 		public void Deserialize_Stream_NonSeekable ()
 		{
@@ -49,7 +193,7 @@ namespace MonoTests.System.Web.UI
 			string s2 = lf.Deserialize (ns) as string;
 			Assert.AreEqual (s1, s2);
 		}
-
+#endif
 		[Test] // bug #324526
 		public void Serialize ()
 		{
diff --git a/mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs b/mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs
index 7417c95..683d543 100644
--- a/mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs
@@ -101,6 +101,20 @@ namespace MonoTests.System.Web.UI
 
 			HtmlDiff.AssertAreEqual (originalHtml, renderedHtml, "#A1");
 		}
+#if false
+		[Test]
+		public void SerializeOverloads ()
+		{
+			ObjectStateFormatter osf = new ObjectStateFormatter ();
+			string s1 = osf.Serialize (String.Empty);
+			string s2;
+			using (MemoryStream ms = new MemoryStream ()) {
+				osf.Serialize (ms, String.Empty);
+				s2 = Convert.ToBase64String (ms.ToArray ());
+			}
+			Assert.AreEqual (s1, s2, "identical");
+		}
+#endif
 	}
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/mcs/class/System.Web/net_4_0_System.Web.dll.sources b/mcs/class/System.Web/net_4_0_System.Web.dll.sources
index 482d69b..6707599 100644
--- a/mcs/class/System.Web/net_4_0_System.Web.dll.sources
+++ b/mcs/class/System.Web/net_4_0_System.Web.dll.sources
@@ -10,6 +10,7 @@ Assembly/AssemblyInfo.cs
 System.Web.Configuration_2.0/CapabilitiesBuild.cs
 System.Web.Configuration_2.0/CapabilitiesResult.cs
 System.Web.Configuration_2.0/ICapabilitiesProcess.cs
+System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
 System.Web.Configuration_2.0/nBrowser/Result.cs
 System.Web.Configuration_2.0/nBrowser/NodeTypes.cs
 System.Web.Configuration_2.0/nBrowser/Identification.cs
-- 
1.6.0.2

