From 8f45490043351941fcee96305d11a07b5d8ab5bc Mon Sep 17 00:00:00 2001
From: Marek Habersack <grendel@twistedcode.net>
Date: Wed, 1 Dec 2010 01:55:56 +0100
Subject: [PATCH 2/5] [asp.net] A few moves/changes following previous patch review
     Backport of commit 21d2c6aedb993eb201e88e6c0a4cce9be8d76825

    * Makefile: Compile tests with TEST defined (to include System.Web.Util.
    MachineKeySectionUtils unit tests)
    * System.Web.dll.sources: Move MachineKeySectionUtils.cs from System.
    Web.Configuration_2.0 to System.Web.Util
    * System.Web_test.dll.sources: Move MachineKeySectionUtilsTest.cs from
    System.Web.Configuration_2.0 to System.Web.Util

    * System.Web.Configuration_2.0/MachineKeySection.cs: Adjust using
    clauses. Uncomment some code. Fix TripleDES versus 3DES for Validation
    under NET_4_0. Remove 'private' on fields/methods.
    * System.Web.Handlers/AssemblyResourceLoader.cs: Adjust using clauses
    * System.Web.Security/MembershipHelper.cs: Adjust using clauses
    * System.Web.Security/RolePrincipal.cs: Adjust using clauses
    * System.Web.SessionState_2.0/SessionId.cs: Adjust using clauses
    * System.Web.UI/LosFormatter.cs: Adjust using clauses.
    * System.Web.Util/MachineKeySectionUtils.cs: Moved from System.Web.
    Configuration_2.0. Rename namespace and remove 'internal' on type
    declaration

    * Test/System.Web.Util/MachineKeySectionUtilsTest.cs: Moved from Test/
    System.Web.Configuration/MachineKeySectionTest.cs. Add test case for
    TripleDES versus 3DES
---
 mcs/class/System.Web/Makefile                      |    3 +
 .../System.Web.Configuration/MachineKeyConfig.cs   |    1 +
 .../MachineKeySection.cs                           |   22 +-
 .../MachineKeySectionUtils.cs                      |  439 -------------------
 .../System.Web.Security/MembershipProvider.cs      |    1 +
 .../System.Web.Security/RolePrincipal.cs           |    1 +
 .../System.Web.SessionState/SessionId.cs           |    1 +
 mcs/class/System.Web/System.Web.UI/LosFormatter.cs |    2 +-
 .../System.Web.Util/MachineKeySectionUtils.cs      |  440 ++++++++++++++++++++
 mcs/class/System.Web/System.Web.dll.sources        |    2 +-
 mcs/class/System.Web/System.Web_test.dll.sources   |    2 +-
 .../MachineKeySectionTest.cs                       |   21 +
 .../MachineKeySectionUtilsTest.cs                  |  310 --------------
 .../System.Web.Util/MachineKeySectionUtilsTest.cs  |  311 ++++++++++++++
 14 files changed, 795 insertions(+), 761 deletions(-)
 delete mode 100644 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
 create mode 100644 mcs/class/System.Web/System.Web.Util/MachineKeySectionUtils.cs
 delete mode 100644 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
 create mode 100644 mcs/class/System.Web/Test/System.Web.Util/MachineKeySectionUtilsTest.cs

diff --git a/mcs/class/System.Web/Makefile b/mcs/class/System.Web/Makefile
index f1e505f..0fe2585 100644
--- a/mcs/class/System.Web/Makefile
+++ b/mcs/class/System.Web/Makefile
@@ -181,6 +181,9 @@ endif
 endif
 
 TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -doc:$(test_lib:.dll=.xml)  -nowarn:219 -nowarn:169 $(NUNIT_RESOURCE_FILES:%=/resource:%)
+ifeq (net_2_0, $(PROFILE))
+TEST_MCS_FLAGS += -d:TEST
+endif
 
 EXTRA_DISTFILES = $(RESOURCE_FILES_2) $(RESOURCE_FILES_1) $(TEST_RESOURCE_FILES) UplevelHelperDefinitions.xml $(RESX_DIST) \
 		  SQLiteProviders_DatabaseSchema.sql
diff --git a/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs b/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
index 4806ac6..ad44cc4 100644
--- a/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
+++ b/mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
@@ -34,6 +34,7 @@ using System.Collections;
 using System.Configuration;
 using System.Xml;
 using System.Security.Cryptography;
+using System.Web.Util;
 
 namespace System.Web.Configuration
 {
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 c193e74..70ce7fd 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
@@ -35,6 +35,7 @@ using System;
 using System.ComponentModel;
 using System.Configuration;
 using System.Security.Cryptography;
+using System.Web.Util;
 
 namespace System.Web.Configuration {
 
@@ -127,7 +128,7 @@ namespace System.Web.Configuration {
 			get { return (string) base [decryptionKeyProp];}
 			set {
 				base[decryptionKeyProp] = value;
-//				SetDecryptionKey (value);
+				SetDecryptionKey (value);
 			}
 		}
 
@@ -138,7 +139,10 @@ namespace System.Web.Configuration {
 			set {
 				if (value == MachineKeyValidation.Custom)
 					throw new ArgumentException ();
-//				ValidationAlgorithm = value.ToString ();
+
+				string algo = value.ToString ();
+				// enum and accept values differs for TripleDES
+				ValidationAlgorithm = (algo == "TripleDES") ? "3DES" : algo;
 			}
 		}
 
@@ -175,7 +179,7 @@ namespace System.Web.Configuration {
 			get { return (string) base [validationKeyProp];}
 			set {
 				base[validationKeyProp] = value;
-//				SetValidationKey (value);
+				SetValidationKey (value);
 			}
 		}
 
@@ -188,10 +192,10 @@ namespace System.Web.Configuration {
 			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;
+		byte[] decryption_key;
+		byte[] validation_key;
+		SymmetricAlgorithm decryption_template;
+		KeyedHashAlgorithm validation_template;
 
 		internal SymmetricAlgorithm GetDecryptionAlgorithm ()
 		{
@@ -200,7 +204,7 @@ namespace System.Web.Configuration {
 		}
 
 		// not to be reused outside algorithm and key validation purpose
-		private SymmetricAlgorithm DecryptionTemplate {
+		SymmetricAlgorithm DecryptionTemplate {
 			get {
 				if (decryption_template == null)
 					decryption_template = GetDecryptionAlgorithm ();
@@ -238,7 +242,7 @@ namespace System.Web.Configuration {
 		}
 
 		// not to be reused outside algorithm and key validation purpose
-		private KeyedHashAlgorithm ValidationTemplate {
+		KeyedHashAlgorithm ValidationTemplate {
 			get {
 				if (validation_template == null)
 					validation_template = GetValidationAlgorithm ();
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
deleted file mode 100644
index dc4de7e..0000000
--- a/mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
+++ /dev/null
@@ -1,439 +0,0 @@
-//
-// System.Web.Configuration.MachineKeySection
-//
-// Authors:
-//	Chris Toshok (toshok@ximian.com)
-//	Sebastien Pouliot  <sebastien@ximian.com>
-//
-// (c) Copyright 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
-// "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.
-//
-
-using System.ComponentModel;
-using System.Configuration;
-#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 ToHexValue (char c, bool high)
-		{
-			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;
-		}
-
-		static public string GetHexString (byte [] bytes)
-		{
-			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 ();
-		}
-
-
-		// 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;
-		}
-
-		// 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
-		)
-		{
-
-			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)
-		{
-			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;
-		}
-
-		// helpers to ease unit testing of the cryptographic code
-#if TEST
-		static byte [] decryption_key;
-		static byte [] validation_key;
-
-		static SymmetricAlgorithm GetDecryptionAlgorithm (
-#if NET_2_0
-			MachineKeySection section
-#else
-			MachineKeyConfig section
-#endif
-		)
-		{
-			return GetDecryptionAlgorithm (section.Decryption);
-		}
-
-		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 (validation_key == null)
-				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 ();
-		}
-
-		static byte[] GetDecryptionKey (
-#if NET_2_0
-			MachineKeySection section
-#else
-			MachineKeyConfig section
-#endif
-		)
-		{
-			return section.GetDecryptionKey ();
-		}
-
-		static byte [] GetValidationKey (
-#if NET_2_0
-			MachineKeySection section
-#else
-			MachineKeyConfig section
-#endif
-		)
-		{
-			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);
-		}
-
-		static byte [] Sign (
-#if NET_2_0
-			MachineKeySection section,
-#else
-			MachineKeyConfig section,
-#endif
-			byte [] data, int offset, int length)
-		{
-			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;
-			}
-		}
-
-		public static byte [] Verify (
-#if NET_2_0
-			MachineKeySection section,
-#else
-			MachineKeyConfig section,
-#endif
-			byte [] data)
-		{
-			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;
-			}
-		}
-	}
-}
-
diff --git a/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs b/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
index 71b5e16..79d325f 100644
--- a/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
+++ b/mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
@@ -34,6 +34,7 @@ using System.Configuration.Provider;
 using System.Web.Configuration;
 using System.Security.Cryptography;
 using System.Text;
+using System.Web.Util;
 
 namespace System.Web.Security
 {
diff --git a/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs b/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
index 9dc9eca..ba9e0b9 100644
--- a/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
+++ b/mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
@@ -34,6 +34,7 @@ using System.Collections.Specialized;
 using System.Security.Permissions;
 using System.Security.Principal;
 using System.Web.Configuration;
+using System.Web.Util;
 using System.IO;
 using System.Text;
 
diff --git a/mcs/class/System.Web/System.Web.SessionState/SessionId.cs b/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
index 7a4245e..3ed8a6d 100644
--- a/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
+++ b/mcs/class/System.Web/System.Web.SessionState/SessionId.cs
@@ -28,6 +28,7 @@
 
 using System.Text;
 using System.Security.Cryptography;
+using System.Web.Util;
 
 namespace System.Web.SessionState {
 
diff --git a/mcs/class/System.Web/System.Web.UI/LosFormatter.cs b/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
index 4cb250d..4fdb00b 100644
--- a/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
+++ b/mcs/class/System.Web/System.Web.UI/LosFormatter.cs
@@ -32,7 +32,7 @@ using System.Configuration;
 using System.IO;
 using System.Security.Permissions;
 using System.Text;
-using System.Web.Configuration;
+using System.Web.Util;
 
 namespace System.Web.UI {
 
diff --git a/mcs/class/System.Web/System.Web.Util/MachineKeySectionUtils.cs b/mcs/class/System.Web/System.Web.Util/MachineKeySectionUtils.cs
new file mode 100644
index 0000000..4c95076
--- /dev/null
+++ b/mcs/class/System.Web/System.Web.Util/MachineKeySectionUtils.cs
@@ -0,0 +1,440 @@
+//
+// System.Web.Configuration.MachineKeySection
+//
+// Authors:
+//	Chris Toshok (toshok@ximian.com)
+//	Sebastien Pouliot  <sebastien@ximian.com>
+//
+// (c) Copyright 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
+// "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.
+//
+
+using System.ComponentModel;
+using System.Configuration;
+#if NET_2_0
+using System.Configuration.Provider;
+#endif
+using System.Security.Cryptography;
+using System.Text;
+using System.Web.Configuration;
+
+namespace System.Web.Util {
+
+	internal static class MachineKeySectionUtils {
+		static byte ToHexValue (char c, bool high)
+		{
+			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;
+		}
+
+		static public string GetHexString (byte [] bytes)
+		{
+			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 ();
+		}
+
+
+		// 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;
+		}
+
+		// 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
+		)
+		{
+
+			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)
+		{
+			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;
+		}
+
+		// helpers to ease unit testing of the cryptographic code
+#if TEST
+		static byte [] decryption_key;
+		static byte [] validation_key;
+
+		static SymmetricAlgorithm GetDecryptionAlgorithm (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
+		{
+			return GetDecryptionAlgorithm (section.Decryption);
+		}
+
+		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 (validation_key == null)
+				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 ();
+		}
+
+		static byte[] GetDecryptionKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
+		{
+			return section.GetDecryptionKey ();
+		}
+
+		static byte [] GetValidationKey (
+#if NET_2_0
+			MachineKeySection section
+#else
+			MachineKeyConfig section
+#endif
+		)
+		{
+			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);
+		}
+
+		static byte [] Sign (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data, int offset, int length)
+		{
+			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;
+			}
+		}
+
+		public static byte [] Verify (
+#if NET_2_0
+			MachineKeySection section,
+#else
+			MachineKeyConfig section,
+#endif
+			byte [] data)
+		{
+			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;
+			}
+		}
+	}
+}
+
diff --git a/mcs/class/System.Web/System.Web.dll.sources b/mcs/class/System.Web/System.Web.dll.sources
index 19dc4bb..9b0ef3e 100644
--- a/mcs/class/System.Web/System.Web.dll.sources
+++ b/mcs/class/System.Web/System.Web.dll.sources
@@ -191,7 +191,6 @@ System.Web.Configuration_2.0/IConfigMapPathFactory.cs
 System.Web.Configuration_2.0/IRemoteWebConfigurationHostServer.cs
 System.Web.Configuration_2.0/LowerCaseStringConverter.cs
 System.Web.Configuration_2.0/MachineKeySection.cs
-System.Web.Configuration_2.0/MachineKeySectionUtils.cs
 System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
 System.Web.Configuration_2.0/MembershipSection.cs
 System.Web.Configuration_2.0/NamespaceCollection.cs
@@ -1157,6 +1156,7 @@ System.Web.Util/FileUtils.cs
 System.Web.Util/ICalls.cs
 System.Web.Util/IWebObjectFactory.cs
 System.Web.Util/IWebPropertyAccessor.cs
+System.Web.Util/MachineKeySectionUtils.cs
 System.Web.Util/SerializationHelper.cs
 System.Web.Util/StrUtils.cs
 System.Web.Util/TimeUtil.cs
diff --git a/mcs/class/System.Web/System.Web_test.dll.sources b/mcs/class/System.Web/System.Web_test.dll.sources
index 777958e..5760a5c 100644
--- a/mcs/class/System.Web/System.Web_test.dll.sources
+++ b/mcs/class/System.Web/System.Web_test.dll.sources
@@ -72,7 +72,6 @@ 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
@@ -509,6 +508,7 @@ System.Web.UI.WebControls/WebColorConverterCas.cs
 System.Web.UI.WebControls/WebControlCas.cs
 System.Web.UI.WebControls/XmlCas.cs
 System.Web.UI.WebControls/XmlDataSourceCas.cs
+System.Web.Util/MachineKeySectionUtilsTest.cs
 System.Web.Util/TransactionsCas.cs
 System.Web.Util/UrlUtilsTest.cs
 System.Web.Util/WorkItemCas.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
index ac5fce8..4f9fbd5 100644
--- a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
+++ b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
@@ -121,6 +121,27 @@ namespace MonoTests.System.Web.Configuration {
 		}
 
 		[Test]
+		public void Validation ()
+		{
+			MachineKeySection section = new MachineKeySection ();
+			section.Validation = MachineKeyValidation.AES;
+			Assert.AreEqual ("AES", section.ValidationAlgorithm, "AES");
+			section.Validation = MachineKeyValidation.HMACSHA256;
+			Assert.AreEqual ("HMACSHA256", section.ValidationAlgorithm, "HMACSHA256");
+			section.Validation = MachineKeyValidation.HMACSHA384;
+			Assert.AreEqual ("HMACSHA384", section.ValidationAlgorithm, "HMACSHA384");
+			section.Validation = MachineKeyValidation.HMACSHA512;
+			Assert.AreEqual ("HMACSHA512", section.ValidationAlgorithm, "HMACSHA512");
+			section.Validation = MachineKeyValidation.MD5;
+			Assert.AreEqual ("MD5", section.ValidationAlgorithm, "MD5");
+			section.Validation = MachineKeyValidation.SHA1;
+			Assert.AreEqual ("SHA1", section.ValidationAlgorithm, "SHA1");
+			// special case, enum value and algorithm names differs
+			section.Validation = MachineKeyValidation.TripleDES;
+			Assert.AreEqual ("3DES", section.ValidationAlgorithm, "3DES");
+		}
+
+		[Test]
 		[ExpectedException (typeof (ArgumentException))]
 		public void ValidationAlgorithm ()
 		{
diff --git a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs b/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
deleted file mode 100644
index 3564cc0..0000000
--- a/mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
+++ /dev/null
@@ -1,310 +0,0 @@
-//
-// 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.Util/MachineKeySectionUtilsTest.cs b/mcs/class/System.Web/Test/System.Web.Util/MachineKeySectionUtilsTest.cs
new file mode 100644
index 0000000..75d187f
--- /dev/null
+++ b/mcs/class/System.Web/Test/System.Web.Util/MachineKeySectionUtilsTest.cs
@@ -0,0 +1,311 @@
+//
+// 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 System.Web.Util;
+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
-- 
1.7.3.2

