Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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.

* System.Web.UI/LosFormatter.cs: Adapt code for internal API change.
Fix some small behaviro changes wrt NET_4_0

* System.Web.UI/ObjectStateFormatter.cs: Use the new common cryptographic
code.

* System.Web.UI/Page.cs: Remove code that is now unneeded (with the new
common cryptogrraphic code).

* System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs: New.

* Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs:
Add more, mostly 4.0, test cases.

* Test/System.Web.Security/FormsAuthenticationTest.cs: Add test case to
ensure HashPasswordForStoringInConfigFile is not case sensitive.

* Test/System.Web.UI/LosFormatterTest.cs: Add some rountrip test cases
with the different ctors
  • Loading branch information...
commit a22389fde254675e52a9da9c9bcd18afdec29d33 1 parent 96880dc
Sebastien Pouliot authored
Showing with 1,397 additions and 686 deletions.
  1. +40 −0 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
  2. +2 −55 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyRegistryStorage.cs
  3. +201 −9 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs
  4. +219 −92 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
  5. +8 −4 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidation.cs
  6. +53 −17 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
  7. +8 −56 mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
  8. +19 −148 mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs
  9. +11 −35 mcs/class/System.Web/System.Web.Security/MembershipHelper.cs
  10. +17 −76 mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
  11. +14 −3 mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
  12. +1 −1  mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
  13. +2 −21 mcs/class/System.Web/System.Web.SessionState_2.0/SessionId.cs
  14. +34 −10 mcs/class/System.Web/System.Web.UI/LosFormatter.cs
  15. +51 −78 mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
  16. +0 −69 mcs/class/System.Web/System.Web.UI/Page.cs
  17. +1 −0  mcs/class/System.Web/System.Web.dll.sources
  18. +2 −0  mcs/class/System.Web/System.Web_test.dll.sources
  19. +157 −0 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
  20. +309 −0 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
  21. +77 −7 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs
  22. +10 −0 mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs
  23. +2 −2 mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs
  24. +143 −2 mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs
  25. +16 −1 mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs
View
40 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
+
View
57 mcs/class/System.Web/System.Web.Configuration_2.0/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 @@ public enum KeyType
Encryption
};
- const int encryptionKeyLength = 64;
- const int validationKeyLength = 64;
-
static string keyEncryption;
static string keyValidation;
@@ -63,30 +58,15 @@ static MachineKeyRegistryStorage ()
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 @@ static byte[] GetKey (KeyType kt)
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 @@ static RegistryKey OpenRegistryKey (string path, bool write)
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 @@ static void Store (byte[] buf, KeyType kt)
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 @@ static void Store (byte[] buf, KeyType kt)
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;
- }
}
}
View
210 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 @@ public sealed class MachineKeySection : ConfigurationSection
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 @@ static MachineKeySection ()
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 @@ static MachineKeySection ()
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 @@ protected override void Reset (ConfigurationElement parentElement)
[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 @@ protected override void Reset (ConfigurationElement parentElement)
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 @@ protected override void Reset (ConfigurationElement parentElement)
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;
+ }
}
}
View
311 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.Configuration.Provider;
using System.Security.Cryptography;
+using System.Text;
#if NET_2_0
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 @@ static byte ToHexValue (char c, bool high)
return v;
}
-
+
internal static byte [] GetBytes (string key, int len)
{
byte [] result = new byte [len / 2];
@@ -101,85 +67,246 @@ static byte ToHexValue (char c, bool high)
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
+ throw new ConfigurationErrorsException ();
+ break;
+ }
+ 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 (MachineKeySection section)
{
- 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);
+ KeyedHashAlgorithm kha = null;
+ switch (section.Validation) {
+ case MachineKeyValidation.MD5:
+ kha = new HMACMD5 ();
+ 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;
}
- internal static void SetValidationKey (string n)
+ // helpers to ease unit testing of the cryptographic code
+#if TEST
+ static byte [] decryption_key;
+ static byte [] validation_key;
+
+ static SymmetricAlgorithm GetDecryptionAlgorithm (MachineKeySection section)
{
- validation_key = MakeKey (n, false); //, out isolate_validation);
+ return GetDecryptionAlgorithm (section.Decryption);
}
- static MachineKeySection Config {
- get { return WebConfigurationManager.GetSection ("system.web/machineKey") as MachineKeySection; }
- }
-
- internal static byte [] ValidationKeyBytes ()
+ static byte [] GetDecryptionKey (MachineKeySection section)
{
- return ValidationKeyBytes (Config);
+ if (decryption_key == null)
+ decryption_key = GetDecryptionAlgorithm (section).Key;
+ return decryption_key;
}
-
- internal static byte [] ValidationKeyBytes (MachineKeySection section)
+
+ static byte [] GetValidationKey (MachineKeySection section)
{
- 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 (MachineKeySection section)
+ {
+ return section.GetDecryptionAlgorithm ();
+ }
+
+ static byte[] GetDecryptionKey (MachineKeySection section)
+ {
+ return section.GetDecryptionKey ();
+ }
- internal static byte [] DecryptionKeyBytes ()
+ static byte [] GetValidationKey (MachineKeySection section)
{
- return DecryptionKeyBytes (Config);
+ return section.GetValidationKey ();
}
-
- internal static byte [] DecryptionKeyBytes (MachineKeySection section)
+#endif
+
+ static public byte [] Decrypt (MachineKeySection section, byte [] encodedData)
{
- if (section == null)
- throw new ArgumentNullException ("section");
-
- if (decryption_key == null)
- SetDecryptionKey (section.DecryptionKey);
- return decryption_key;
+ return Decrypt (section, encodedData, 0, encodedData.Length);
}
- internal static byte [] DecryptionKey192Bits ()
+ static byte [] Decrypt (MachineKeySection section, byte [] encodedData, int offset, int length)
{
- return DecryptionKey192Bits (Config);
+ using (SymmetricAlgorithm sa = GetDecryptionAlgorithm (section)) {
+ sa.Key = GetDecryptionKey (section);
+ return Decrypt (sa, encodedData, offset, length);
+ }
}
-
- internal static byte [] DecryptionKey192Bits (MachineKeySection section)
+
+ static public byte [] Decrypt (SymmetricAlgorithm alg, byte [] encodedData, int offset, int length)
{
- if (section == null)
- throw new ArgumentNullException ("section");
-
- if (decryption_key_192bits == null)
- SetDecryptionKey (section.DecryptionKey);
- return decryption_key_192bits;
+ // 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 (MachineKeySection section, 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 (MachineKeySection section, byte [] data)
+ {
+ return Sign (section, data, 0, data.Length);
+ }
+
+ static byte [] Sign (MachineKeySection section, 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 (MachineKeySection section, 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 (MachineKeySection section, 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 (MachineKeySection section, 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;
+ }
}
}
}
View
12 mcs/class/System.Web/System.Web.Configuration_2.0/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 @@ enum MachineKeyValidation
MD5 = 0,
SHA1 = 1,
TripleDES = 2,
- AES = 3
+ AES = 3,
+#if NET_4_0
+ HMACSHA256 = 4,
+ HMACSHA384 = 5,
+ HMACSHA512 = 6,
+ Custom = 7
+#endif
}
}
View
70 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
+ }
}
}
}
View
64 mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
@@ -34,7 +34,6 @@
using System.IO;
using System.Resources;
using System.Collections;
-using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Configuration;
@@ -58,11 +57,6 @@ class AssemblyResourceLoader : IHttpHandler {
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)
{
@@ -93,67 +87,25 @@ internal static string GetResourceUrl (Type type, string resourceName)
}
#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)
- {
-#if NET_2_0
- return MachineKeySectionUtils.GetBytes (val, val.Length);
-#else
- return MachineKeyConfig.GetBytes (val, val.Length);
-#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.ToLowerInvariant ());
+ bytes = MachineKeySectionUtils.Encrypt (MachineKeySection.Config, 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 (MachineKeySection.Config, 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;
@@ -201,7 +153,7 @@ static string CreateResourceUrl (Assembly assembly, string resourceName, bool no
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) {
View
167 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 @@ public sealed class FormsAuthentication
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 @@ static FormsProtectionEnum protection
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 @@ static FormsProtectionEnum protection
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
@@ -237,18 +227,6 @@ public static bool Authenticate (string name, string password)
return String.Compare (password, stored, caseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0;
}
-#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)
@@ -259,59 +237,14 @@ static FormsAuthenticationTicket Decrypt2 (byte [] bytes)
#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);
@@ -325,11 +258,8 @@ public static FormsAuthenticationTicket Decrypt (string encryptedTicket)
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) {
@@ -347,57 +277,23 @@ public static string Encrypt (FormsAuthenticationTicket ticket)
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)
@@ -478,21 +374,6 @@ public static string GetRedirectUrl (string userName, bool createPersistentCooki
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)
@@ -512,7 +393,7 @@ static string HashPasswordForStoringInConfigFile (string password, FormsAuthPass
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)
@@ -580,16 +461,6 @@ public static void Initialize ()
}
#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;
}
}
View
46 mcs/class/System.Web/System.Web.Security/MembershipHelper.cs
@@ -49,56 +49,32 @@ sealed class MembershipHelper
get { return Membership.Providers; }
}
- static SymmetricAlgorithm GetAlg ()
+ static 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;
}
public 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);
}
}
public 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);
}
}
}
View
93 mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
@@ -29,7 +29,6 @@
//
using System.Collections.Specialized;
-using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Principal;
using System.Web.Configuration;
@@ -146,42 +145,16 @@ public string ToEncryptedTicket ()
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)
@@ -193,45 +166,18 @@ void DecryptTicket (string encryptedTicket)
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);
@@ -276,11 +222,6 @@ void InitializeRoles (string decryptedRoles)
_cachedRoles.Add (r, r);
}
- byte [] InitVector
- {
- get { return new byte [] { 1, 2, 3, 4, 5, 6, 7, 8 }; }
- }
-
public bool CachedListChanged {
get { return _listChanged; }
}
View
17 mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
@@ -1048,11 +1048,22 @@ string EncodePassword (string password, MembershipPasswordFormat passwordFormat,
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);
}
View
2  mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
@@ -1432,7 +1432,7 @@ string EncodePassword(string password)
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)));
View
23 mcs/class/System.Web/System.Web.SessionState_2.0/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 @@ internal static string Create ()
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)
{
View
44 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 {
@@ -46,42 +47,62 @@ public LosFormatter ()
osf = new ObjectStateFormatter ();
}
- public LosFormatter (bool enableMac, string macKeyModifier) : this (enableMac, Convert.FromBase64String (macKeyModifier))
+ public LosFormatter (bool enableMac, string macKeyModifier)
{
+ osf = new ObjectStateFormatter ();
+ if (enableMac && !String.IsNullOrEmpty (macKeyModifier)) {
+ SetMacKey (Convert.FromBase64String (macKeyModifier));
+ }
}
- [MonoTODO]
public LosFormatter (bool enableMac, byte[] macKeyModifier)
{
- if (enableMac)
- osf = new ObjectStateFormatter (macKeyModifier);
- else
- osf = new ObjectStateFormatter ();
+ osf = new ObjectStateFormatter ();
+ if (enableMac && (macKeyModifier != null)) {
+ SetMacKey (macKeyModifier);
+ }
+ }
+
+ private void SetMacKey (byte[] macKeyModifier)
+ {
+ try {
+ osf.Section.ValidationKey = MachineKeySectionUtils.GetHexString (macKeyModifier);
+ }
+ catch (ArgumentException) {
+ }
+ catch (ConfigurationErrorsException) {
+ // bad key (e.g. size), default key will be used
+ }
}
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)
ms.Write (bytes, 0, n);
streamLength = ms.Length;
}
-
string b64 = Encoding.ASCII.GetString (ms.GetBuffer (),
0, (int) streamLength);
return Deserialize (b64);
+#endif
}
public object Deserialize (TextReader input)
@@ -109,7 +130,10 @@ public void Serialize (Stream stream, object value)
{
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);
View
129 mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
@@ -44,7 +44,6 @@
using System.Web.UI.WebControls;
using System.Web.Util;
using System.Diagnostics;
-using System.Security.Cryptography;
using System.Web.Configuration;
namespace System.Web.UI
@@ -52,8 +51,7 @@ namespace System.Web.UI
public sealed class ObjectStateFormatter : IFormatter, IStateFormatter
{
Page page;
- HashAlgorithm algo;
- byte [] vkey;
+ MachineKeySection section;
public ObjectStateFormatter ()
{
@@ -64,59 +62,29 @@ internal ObjectStateFormatter (Page page)
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;
- } else
- return page.EnableViewStateMac;
+ return (page == null) ? (section != null) : page.EnableViewStateMac;
}
}
- internal HashAlgorithm GetAlgo ()
- {
- if (algo != null)
- return algo;
- if (!EnableMac)
- return null;
-
- byte [] algoKey;
- if (page != null) {
- MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
- algoKey = MachineKeySectionUtils.ValidationKeyBytes (mconfig);
- } else
- algoKey = vkey;
-
- algo = new HMACSHA1 (algoKey);
- return algo;
+ bool NeedViewStateEncryption {
+ get {
+ return (page == null) ? false : page.NeedViewStateEncryption;
+ }
}
- 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;
+ internal MachineKeySection Section {
+ get {
+ if (section == null)
+ section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
+ return section;
+ }
+ set {
+ section = value;
+ }
}
-
+
public object Deserialize (Stream inputStream)
{
if (inputStream == null)
@@ -132,45 +100,50 @@ public object Deserialize (string inputString)
if (inputString.Length == 0)
throw new ArgumentNullException ("inputString");
- 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);
- bool isEncrypted = ((int)buffer [--length] == 1)? true : false;
- Stream ms = new MemoryStream (buffer, 0, length, false, false);
- if (isEncrypted)
- ms = new CryptoStream (ms, page.GetCryptoTransform (CryptoStreamMode.Read), CryptoStreamMode.Read);
- 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)
{
if (stateGraph == null)
return String.Empty;
-
- MemoryStream ms = new MemoryStream ();
- Stream output = ms;
- bool needEncryption = page == null ? false : page.NeedViewStateEncryption;
- if (needEncryption){
- output = new CryptoStream (output, page.GetCryptoTransform (CryptoStreamMode.Write), CryptoStreamMode.Write);
- }
- Serialize (output, stateGraph);
- ms.WriteByte((byte)(needEncryption? 1 : 0));
-#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);
+
+ byte[] data = null;
+ using (MemoryStream ms = new MemoryStream ()) {
+ Serialize (ms, stateGraph);
+ data = ms.GetBuffer ();
+ }
+
+ 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)
View
69 mcs/class/System.Web/System.Web.UI/Page.cs
@@ -39,7 +39,6 @@
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;
@@ -2375,74 +2374,6 @@ public void RegisterRequiresViewStateEncryption ()
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 ||
View
1  mcs/class/System.Web/System.Web.dll.sources
@@ -180,6 +180,7 @@ System.Web.Configuration_2.0/IConfigMapPath.cs
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/MachineKeyCompatibilityMode.cs
System.Web.Configuration_2.0/MachineKeyRegistryStorage.cs
System.Web.Configuration_2.0/MachineKeySection.cs
System.Web.Configuration_2.0/MachineKeySectionUtils.cs
View
2  mcs/class/System.Web/System.Web_test.dll.sources
@@ -88,6 +88,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
View
157 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
@@ -0,0 +1,157 @@
+//
+// 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.
+//
+
+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
+ }
+}
+
View
309 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
@@ -0,0 +1,309 @@
+//
+// 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.
+//
+
+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 ()
+ {