Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[asp.net] Normalization of cryptographic uses in asp.net.

Backport of commit a22389f
    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.
  • Loading branch information...
commit f5501ef47531aa48531532160dbdc133ce93551e 1 parent 3c24090
@grendello grendello authored
Showing with 1,703 additions and 769 deletions.
  1. +2 −0  mcs/class/System.Web/Assembly/AssemblyInfo.cs
  2. +126 −72 mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
  3. +2 −55 mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs
  4. +8 −4 mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs
  5. +40 −0 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyCompatibilityMode.cs
  6. +201 −9 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySection.cs
  7. +347 −95 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
  8. +53 −17 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeyValidationConverter.cs
  9. +21 −57 mcs/class/System.Web/System.Web.Handlers/AssemblyResourceLoader.cs
  10. +19 −148 mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs
  11. +11 −35 mcs/class/System.Web/System.Web.Security/MembershipProvider.cs
  12. +17 −76 mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
  13. +14 −3 mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs
  14. +1 −1  mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
  15. +2 −21 mcs/class/System.Web/System.Web.SessionState/SessionId.cs
  16. +45 −9 mcs/class/System.Web/System.Web.UI/LosFormatter.cs
  17. +72 −86 mcs/class/System.Web/System.Web.UI/ObjectStateFormatter.cs
  18. +0 −69 mcs/class/System.Web/System.Web.UI/Page.cs
  19. +1 −0  mcs/class/System.Web/System.Web.dll.sources
  20. +2 −0  mcs/class/System.Web/System.Web_test.dll.sources
  21. +158 −0 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionTest.cs
  22. +310 −0 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeySectionUtilsTest.cs
  23. +77 −7 mcs/class/System.Web/Test/System.Web.Configuration/MachineKeyValidationConverterTest.cs
  24. +10 −0 mcs/class/System.Web/Test/System.Web.Security/FormsAuthenticationTest.cs
  25. +2 −2 mcs/class/System.Web/Test/System.Web.Security/RolePrincipalTest.cs
  26. +146 −2 mcs/class/System.Web/Test/System.Web.UI/LosFormatterTest.cs
  27. +15 −1 mcs/class/System.Web/Test/System.Web.UI/ObjectStateFormatterTest.cs
  28. +1 −0  mcs/class/System.Web/net_4_0_System.Web.dll.sources
View
2  mcs/class/System.Web/Assembly/AssemblyInfo.cs
@@ -69,6 +69,8 @@
[assembly: InternalsVisibleTo ("System.Web.DynamicData, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo ("SystemWebTestShim, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
+[assembly: InternalsVisibleTo ("System.Web_test_net_2_0, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
+[assembly: InternalsVisibleTo ("System.Web_test_net_4_0, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
#endif
#endif
View
198 mcs/class/System.Web/System.Web.Configuration/MachineKeyConfig.cs
@@ -39,23 +39,40 @@ namespace System.Web.Configuration
{
class MachineKeyConfig
{
- byte [] validation_key;
- //bool isolate_validation;
- byte [] decryption_key;
- byte [] decryption_key_192bits;
- //bool isolate_decryption; // For us, this is always true by now.
+ byte[] decryption_key;
+ byte[] validation_key;
+ string decryption_key_name;
+ string validation_key_name;
+ SymmetricAlgorithm decryption_template;
+ KeyedHashAlgorithm validation_template;
MachineKeyValidation validation_type;
- static byte [] autogenerated;
- static byte [] autogenerated_decrypt;
+ internal static MachineKeyConfig Config {
+ get {
+ HttpContext context = HttpContext.Current;
+ if (context == null)
+ return null;
+
+ return context.GetConfig ("system.web/machineKey") as MachineKeyConfig;
+ }
+ }
- static MachineKeyConfig ()
- {
- autogenerated = new byte [64];
- RandomNumberGenerator rng = RandomNumberGenerator.Create ();
- rng.GetBytes (autogenerated);
- autogenerated_decrypt = new byte [64];
- rng.GetBytes (autogenerated_decrypt);
+ // not to be reused outside algorithm and key validation purpose
+ SymmetricAlgorithm DecryptionTemplate {
+ get {
+ if (decryption_template == null)
+ decryption_template = GetDecryptionAlgorithm ();
+ return decryption_template;
+ }
+ }
+
+ // not to be reused outside algorithm and key validation purpose
+ KeyedHashAlgorithm ValidationTemplate {
+ get {
+ if (validation_template == null)
+ validation_template = GetValidationAlgorithm ();
+ return validation_template;
+ }
}
internal MachineKeyConfig (object parent)
@@ -68,75 +85,45 @@ internal MachineKeyConfig (object parent)
}
}
- static byte ToHexValue (char c, bool high)
+ internal byte [] GetDecryptionKey ()
{
- byte v;
- if (c >= '0' && c <= '9')
- v = (byte) (c - '0');
- else if (c >= 'a' && c <= 'f')
- v = (byte) (c - 'a' + 10);
- else if (c >= 'A' && c <= 'F')
- v = (byte) (c - 'A' + 10);
- else
- throw new ArgumentException ("Invalid hex character");
-
- if (high)
- v <<= 4;
-
- return v;
- }
-
- internal static byte [] GetBytes (string key, int len)
- {
- byte [] result = new byte [len / 2];
- for (int i = 0; i < len; i += 2)
- result [i / 2] = (byte) (ToHexValue (key [i], true) + ToHexValue (key [i + 1], false));
-
- return result;
+ if (decryption_key == null)
+ SetDecryptionKey (decryption_key_name);
+ return decryption_key;
}
- static byte [] MakeKey (string key, bool decryption) //, out bool isolate)
+ internal void SetDecryptionKey (string key)
{
- if (key == null || key.StartsWith ("AutoGenerate")){
- //isolate = key.IndexOf ("IsolateApps") != 1;
-
- return (decryption) ? autogenerated_decrypt : autogenerated;
+ if ((key == null) || key.StartsWith ("AutoGenerate")) {
+ decryption_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Encryption);
+ } else {
+ try {
+ decryption_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+ DecryptionTemplate.Key = decryption_key;
+ }
+ catch {
+ decryption_key = null;
+ throw new ArgumentException ("Invalid key length");
+ }
}
-
- //isolate = false;
-
- int len = key.Length;
- if (len < 40 || len > 128 || (len % 2) == 1)
- throw new ArgumentException ("Invalid key length");
-
- return GetBytes (key, len);
}
-
- internal void SetValidationKey (string n)
+
+ internal KeyedHashAlgorithm GetValidationAlgorithm ()
{
- validation_key = MakeKey (n, false); //, out isolate_validation);
- }
-
- internal byte [] ValidationKey {
- get { return validation_key; }
+ // code location to help with unit testing the code
+ return MachineKeySectionUtils.GetValidationAlgorithm (this.ValidationType);
}
- internal void SetDecryptionKey (string n)
+ internal SymmetricAlgorithm GetDecryptionAlgorithm ()
{
- decryption_key = MakeKey (n, true); //, out isolate_decryption);
- decryption_key_192bits = new byte [24];
- int count = 24;
- if (decryption_key.Length < 24)
- count = decryption_key.Length;
- Buffer.BlockCopy (decryption_key, 0, decryption_key_192bits, 0, count);
- }
-
- internal byte [] DecryptionKey {
- get { return decryption_key; }
- }
+ string name;
- internal byte [] DecryptionKey192Bits {
- get { return decryption_key_192bits; }
+ if (decryption_key_name == null || decryption_key_name.StartsWith ("AutoGenerate"))
+ name = "Auto";
+ else
+ name = decryption_key_name;
+
+ return MachineKeySectionUtils.GetDecryptionAlgorithm (name);
}
internal MachineKeyValidation ValidationType {
@@ -147,6 +134,73 @@ internal void SetDecryptionKey (string n)
validation_type = value;
}
}
+
+ internal byte [] GetValidationKey ()
+ {
+ if (validation_key == null)
+ SetValidationKey (validation_key_name);
+ return validation_key;
+ }
+
+ // key can be expended for HMAC - i.e. a small key, e.g. 32 bytes, is still accepted as valid
+ // the HMAC class already deals with keys larger than what it can use (digested to right size)
+ internal void SetValidationKey (string key)
+ {
+ validation_key_name = key;
+ if ((key == null) || key.StartsWith ("AutoGenerate")) {
+ validation_key = AutoGenerate (MachineKeyRegistryStorage.KeyType.Validation);
+ } else {
+ try {
+ validation_key = MachineKeySectionUtils.GetBytes (key, key.Length);
+ ValidationTemplate.Key = validation_key;
+ }
+ catch (CryptographicException) {
+ // second chance, use the key length that the HMAC really wants
+ try {
+ byte[] expanded_key = new byte [ValidationTemplate.Key.Length];
+ Array.Copy (validation_key, 0, expanded_key, 0, validation_key.Length);
+ ValidationTemplate.Key = expanded_key;
+ validation_key = expanded_key;
+ }
+ catch {
+ validation_key = null;
+ throw new ArgumentException ("Invalid key length");
+ }
+ }
+ }
+ }
+
+ byte[] AutoGenerate (MachineKeyRegistryStorage.KeyType type)
+ {
+ byte[] key = null;
+#if TARGET_J2EE
+ {
+#else
+ try {
+ key = MachineKeyRegistryStorage.Retrieve (type);
+
+ // ensure the stored key is usable with the selection algorithm
+ if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+ DecryptionTemplate.Key = key;
+ else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+ ValidationTemplate.Key = key;
+ } catch (Exception) {
+ key = null;
+ }
+#endif
+ // some algorithms have special needs for key (e.g. length, parity, weak keys...)
+ // so we better ask them to provide a default key (than to generate/use bad ones)
+ if (key == null) {
+ if (type == MachineKeyRegistryStorage.KeyType.Encryption)
+ key = DecryptionTemplate.Key;
+ else if (type == MachineKeyRegistryStorage.KeyType.Validation)
+ key = ValidationTemplate.Key;
+#if !TARGET_J2EE
+ MachineKeyRegistryStorage.Store (key, type);
+#endif
+ }
+ return key;
+ }
}
}
View
57 mcs/class/System.Web/System.Web.Configuration/MachineKeyRegistryStorage.cs
@@ -28,8 +28,6 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
-using System.Security.Cryptography;
using Microsoft.Win32;
namespace System.Web.Configuration
@@ -42,9 +40,6 @@ 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
12 mcs/class/System.Web/System.Web.Configuration/MachineKeyValidation.cs
@@ -23,11 +23,9 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2010 Novell, Inc (http://www.novell.com)
//
-using System.Resources;
-
namespace System.Web.Configuration
{
#if NET_2_0
@@ -40,7 +38,13 @@ 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
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
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
442 mcs/class/System.Web/System.Web.Configuration_2.0/MachineKeySectionUtils.cs
@@ -3,8 +3,9 @@
//
// Authors:
// Chris Toshok (toshok@ximian.com)
+// Sebastien Pouliot <sebastien@ximian.com>
//
-// (c) Copyright 2005 Novell, Inc (http://www.novell.com)
+// (c) Copyright 2005, 2010 Novell, Inc (http://www.novell.com)
//
//
@@ -28,52 +29,17 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
using System.ComponentModel;
using System.Configuration;
-using System.Security.Cryptography;
-
#if NET_2_0
+using System.Configuration.Provider;
+#endif
+using System.Security.Cryptography;
+using System.Text;
namespace System.Web.Configuration {
- internal static class MachineKeySectionUtils
- {
- static byte [] autogenerated;
- static byte [] autogenerated_decrypt;
- static byte[] decryption_key;
- static byte[] decryption_key_192bits;
- static byte[] validation_key;
-
- internal static void AutoGenKeys ()
- {
-#if TARGET_J2EE
- {
-#else
- try {
- if (autogenerated == null)
- autogenerated = MachineKeyRegistryStorage.Retrieve (
- MachineKeyRegistryStorage.KeyType.Validation);
- if (autogenerated_decrypt == null)
- autogenerated_decrypt = MachineKeyRegistryStorage.Retrieve (
- MachineKeyRegistryStorage.KeyType.Encryption);
- } catch (Exception) {
-#endif
- // Fall back to old method
- RandomNumberGenerator rng = RandomNumberGenerator.Create ();
-
- if (autogenerated == null) {
- autogenerated = new byte [64];
- rng.GetBytes (autogenerated);
- }
-
- if (autogenerated_decrypt == null) {
- autogenerated_decrypt = new byte [64];
- rng.GetBytes (autogenerated_decrypt);
- }
- }
- }
-
+ internal static class MachineKeySectionUtils {
static byte ToHexValue (char c, bool high)
{
byte v;
@@ -91,7 +57,7 @@ static byte ToHexValue (char c, bool high)
return v;
}
-
+
internal static byte [] GetBytes (string key, int len)
{
byte [] result = new byte [len / 2];
@@ -101,87 +67,373 @@ 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
+ {
+#if NET_2_0
+ throw new ConfigurationErrorsException ();
+#else
+ throw new HttpException ("Unknown encryption algorithm name.");
+#endif
+ }
+#if NET_4_0
+ break;
+#endif
+ }
+ return sa;
}
- internal static void SetDecryptionKey (string n)
+ // validation="HMACSHA256" [SHA1 | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]
+ // [1] http://msdn.microsoft.com/en-us/library/system.web.configuration.machinekeyvalidation.aspx
+ // [2] http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx
+ public static KeyedHashAlgorithm GetValidationAlgorithm (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
{
- decryption_key = MakeKey (n, true); //, out isolate_decryption);
- decryption_key_192bits = new byte [24];
- int count = 24;
- if (decryption_key.Length < 24)
- count = decryption_key.Length;
- Buffer.BlockCopy (decryption_key, 0, decryption_key_192bits, 0, count);
- }
- internal static void SetValidationKey (string n)
+ return GetValidationAlgorithm (
+#if NET_2_0
+ section.Validation
+#else
+ section.ValidationType
+#endif
+#if NET_4_0
+ , section
+#endif
+ );
+ }
+#if NET_4_0
+ public static KeyedHashAlgorithm GetValidationAlgorithm (MachineKeyValidation validation)
{
- validation_key = MakeKey (n, false); //, out isolate_validation);
+ return GetValidationAlgorithm (validation, null);
+ }
+#endif
+ public static KeyedHashAlgorithm GetValidationAlgorithm (MachineKeyValidation validation
+#if NET_4_0
+ , MachineKeySection section
+#endif
+ )
+ {
+ KeyedHashAlgorithm kha = null;
+ switch (validation) {
+ case MachineKeyValidation.MD5:
+#if NET_2_0
+ kha = new HMACMD5 ();
+#else
+ kha = new Mono.Security.Cryptography.HMAC ();
+#endif
+ break;
+ case MachineKeyValidation.AES: // see link [1] or [2]
+ case MachineKeyValidation.TripleDES: // see link [2]
+ case MachineKeyValidation.SHA1:
+ kha = new HMACSHA1 ();
+ break;
+#if NET_4_0
+ case MachineKeyValidation.HMACSHA256:
+ kha = new HMACSHA256 ();
+ break;
+ case MachineKeyValidation.HMACSHA384:
+ kha = new HMACSHA384 ();
+ break;
+ case MachineKeyValidation.HMACSHA512:
+ kha = new HMACSHA512 ();
+ break;
+ case MachineKeyValidation.Custom:
+ // remove the "alg:" from the start of the string
+ string algo = section.ValidationAlgorithm;
+ if (algo.StartsWith ("alg:"))
+ kha = KeyedHashAlgorithm.Create (algo.Substring (4));
+ break;
+#endif
+ }
+ return kha;
}
- static MachineKeySection Config {
- get { return WebConfigurationManager.GetSection ("system.web/machineKey") as MachineKeySection; }
- }
+ // helpers to ease unit testing of the cryptographic code
+#if TEST
+ static byte [] decryption_key;
+ static byte [] validation_key;
- internal static byte [] ValidationKeyBytes ()
+ static SymmetricAlgorithm GetDecryptionAlgorithm (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
{
- return ValidationKeyBytes (Config);
+ return GetDecryptionAlgorithm (section.Decryption);
}
-
- internal static byte [] ValidationKeyBytes (MachineKeySection section)
+
+ static byte [] GetDecryptionKey (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
+ {
+ if (decryption_key == null)
+ decryption_key = GetDecryptionAlgorithm (section).Key;
+ return decryption_key;
+ }
+
+ static byte [] GetValidationKey (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
{
- if (section == null)
- throw new ArgumentNullException ("section");
-
if (validation_key == null)
- SetValidationKey (section.ValidationKey);
+ validation_key = GetValidationAlgorithm (section).Key;
return validation_key;
}
+#else
+ static SymmetricAlgorithm GetDecryptionAlgorithm (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
+ {
+ return section.GetDecryptionAlgorithm ();
+ }
- internal static byte [] DecryptionKeyBytes ()
+ static byte[] GetDecryptionKey (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
{
- return DecryptionKeyBytes (Config);
+ return section.GetDecryptionKey ();
}
-
- internal static byte [] DecryptionKeyBytes (MachineKeySection section)
+
+ static byte [] GetValidationKey (
+#if NET_2_0
+ MachineKeySection section
+#else
+ MachineKeyConfig section
+#endif
+ )
{
- if (section == null)
- throw new ArgumentNullException ("section");
-
- if (decryption_key == null)
- SetDecryptionKey (section.DecryptionKey);
- return decryption_key;
+ return section.GetValidationKey ();
+ }
+#endif
+
+ static public byte [] Decrypt (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] encodedData)
+ {
+ return Decrypt (section, encodedData, 0, encodedData.Length);
+ }
+
+ static byte [] Decrypt (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] encodedData, int offset, int length)
+ {
+ using (SymmetricAlgorithm sa = GetDecryptionAlgorithm (section)) {
+ sa.Key = GetDecryptionKey (section);
+ return Decrypt (sa, encodedData, offset, length);
+ }
+ }
+
+ static public byte [] Decrypt (SymmetricAlgorithm alg, byte [] encodedData, int offset, int length)
+ {
+ // alg.IV is randomly set (default behavior) and perfect for our needs
+ // iv is the first part of the encodedPassword
+ byte [] iv = new byte [alg.IV.Length];
+ Array.Copy (encodedData, 0, iv, 0, iv.Length);
+ using (ICryptoTransform decryptor = alg.CreateDecryptor (alg.Key, iv)) {
+ try {
+ return decryptor.TransformFinalBlock (encodedData, iv.Length + offset, length - iv.Length);
+ }
+ catch (CryptographicException) {
+ return null;
+ }
+ }
+ }
+
+ static public byte [] Encrypt (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] data)
+ {
+ using (SymmetricAlgorithm sa = GetDecryptionAlgorithm (section)) {
+ sa.Key = GetDecryptionKey (section);
+ return Encrypt (sa, data);
+ }
+ }
+
+ static public byte [] Encrypt (SymmetricAlgorithm alg, byte [] data)
+ {
+ // alg.IV is randomly set (default behavior) and perfect for our needs
+ byte [] iv = alg.IV;
+ using (ICryptoTransform encryptor = alg.CreateEncryptor (alg.Key, iv)) {
+ byte [] encrypted = encryptor.TransformFinalBlock (data, 0, data.Length);
+ byte [] output = new byte [iv.Length + encrypted.Length];
+ // note: the IV can be public, however it should not be based on the password
+ Array.Copy (iv, 0, output, 0, iv.Length);
+ Array.Copy (encrypted, 0, output, iv.Length, encrypted.Length);
+ return output;
+ }
+ }
+
+ // in [data]
+ // return [data][signature]
+ public static byte [] Sign (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] data)
+ {
+ return Sign (section, data, 0, data.Length);
}
- internal static byte [] DecryptionKey192Bits ()
+ static byte [] Sign (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] data, int offset, int length)
{
- return DecryptionKey192Bits (Config);
+ using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+ kha.Key = GetValidationKey (section);
+ byte [] signature = kha.ComputeHash (data, offset, length);
+ byte [] block = new byte [length + signature.Length];
+ Array.Copy (data, block, length);
+ Array.Copy (signature, 0, block, length, signature.Length);
+ return block;
+ }
}
-
- internal static byte [] DecryptionKey192Bits (MachineKeySection section)
+
+ public static byte [] Verify (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] data)
{
- if (section == null)
- throw new ArgumentNullException ("section");
-
- if (decryption_key_192bits == null)
- SetDecryptionKey (section.DecryptionKey);
- return decryption_key_192bits;
+ byte [] unsigned_data = null;
+ bool valid = true;
+ using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+ kha.Key = GetValidationKey (section);
+ int signlen = kha.HashSize >> 3; // bits to bytes
+ byte [] signature = Sign (section, data, 0, data.Length - signlen);
+ for (int i = 0; i < signature.Length; i++) {
+ if (signature [i] != data [data.Length - signature.Length + i])
+ valid = false; // do not return (timing attack)
+ }
+ unsigned_data = new byte [data.Length - signlen];
+ Array.Copy (data, 0, unsigned_data, 0, unsigned_data.Length);
+ }
+ return valid ? unsigned_data : null;
+ }
+
+ // do NOT sign then encrypt
+
+ public static byte [] EncryptSign (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] data)
+ {
+ byte [] encdata = Encrypt (section, data);
+ return Sign (section, encdata);
+ }
+
+ // note: take no shortcut (timing attack) while verifying or decrypting
+ public static byte [] VerifyDecrypt (
+#if NET_2_0
+ MachineKeySection section,
+#else
+ MachineKeyConfig section,
+#endif
+ byte [] block)
+ {
+ bool valid = true;
+ int signlen;
+
+ using (KeyedHashAlgorithm kha = GetValidationAlgorithm (section)) {
+ kha.Key = GetValidationKey (section);
+ signlen = kha.HashSize >> 3; // bits to bytes
+ byte [] signature = Sign (section, block, 0, block.Length - signlen);
+ for (int i = 0; i < signature.Length; i++) {
+ if (signature [i] != block [block.Length - signature.Length + i])
+ valid = false; // do not return (timing attack)
+ }
+ }
+
+ // whatever the signature continue with decryption
+ try {
+ byte [] decdata = Decrypt (section, block, 0, block.Length - signlen);
+ return valid ? decdata : null;
+ }
+ catch {
+ return null;
+ }
}
}
}
-#endif
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
78 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;
@@ -59,11 +58,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)
{
@@ -92,70 +86,40 @@ internal static string GetResourceUrl (Type type, string resourceName)
{
return GetResourceUrl (type.Assembly, resourceName, false);
}
-#endif
-
- static string GetHexString (byte [] bytes)
- {
- const int letterPart = 55;
- const int numberPart = 48;
- char [] result = new char [bytes.Length * 2];
- for (int i = 0; i < bytes.Length; i++) {
- int tmp = (int) bytes [i];
- int second = tmp & 15;
- int first = (tmp >> 4) & 15;
- result [(i * 2)] = (char) (first > 9 ? letterPart + first : numberPart + first);
- result [(i * 2) + 1] = (char) (second > 9 ? letterPart + second : numberPart + second);
- }
- return new string (result);
- }
-
- static byte[] GetEncryptionKey ()
- {
-#if NET_2_0
- return MachineKeySectionUtils.DecryptionKey192Bits ();
-#else
- MachineKeyConfig config = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
- return config.DecryptionKey192Bits;
-#endif
- }
-
- static byte[] GetBytes (string val)
+#endif
+ static string EncryptAssemblyResource (string asmName, string resName)
{
+ byte[] bytes = Encoding.UTF8.GetBytes (String.Concat (asmName, ";", resName));
+ bytes = MachineKeySectionUtils.Encrypt (
#if NET_2_0
- return MachineKeySectionUtils.GetBytes (val, val.Length);
+ MachineKeySection.Config,
#else
- return MachineKeyConfig.GetBytes (val, val.Length);
+ MachineKeyConfig.Config,
#endif
- }
-
- static byte [] init_vector = { 0xD, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF };
-
- static string EncryptAssemblyResource (string asmName, string resName)
- {
- byte[] key = GetEncryptionKey ();
- byte[] bytes = Encoding.UTF8.GetBytes (String.Concat (asmName, ";", resName));
- string result;
-
- ICryptoTransform encryptor = TripleDES.Create ().CreateEncryptor (key, init_vector);
- result = GetHexString (encryptor.TransformFinalBlock (bytes, 0, bytes.Length));
- bytes = null;
-
- return String.Concat ("d=", result.ToLower (Helpers.InvariantCulture));
+ bytes);
+ return Convert.ToBase64String (bytes);
}
static void DecryptAssemblyResource (string val, out string asmName, out string resName)
{
- byte[] key = GetEncryptionKey ();
- byte[] bytes = GetBytes (val);
- byte[] result;
+ byte[] bytes = Convert.FromBase64String (val);
asmName = null;
resName = null;
- ICryptoTransform decryptor = TripleDES.Create ().CreateDecryptor (key, init_vector);
- result = decryptor.TransformFinalBlock (bytes, 0, bytes.Length);
+ byte[] result = MachineKeySectionUtils.Decrypt (
+#if NET_2_0
+ MachineKeySection.Config,
+#else
+ MachineKeyConfig.Config,
+#endif
+ bytes);
bytes = null;
+ // null will be returned if, for any reason, decryption fails
+ if (result == null)
+ return;
+
string data = Encoding.UTF8.GetString (result);
result = null;
@@ -202,7 +166,7 @@ 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
@@ -240,18 +230,6 @@ public static bool Authenticate (string name, string password)
#endif
}
-#if NET_2_0
- static byte [] GetDecryptionKey (MachineKeySection config)
- {
- return MachineKeySectionUtils.DecryptionKey192Bits (config);
- }
-#else
- static byte [] GetDecryptionKey (MachineKeyConfig config)
- {
- return config.DecryptionKey192Bits;
- }
-#endif
-
static FormsAuthenticationTicket Decrypt2 (byte [] bytes)
{
if (protection == FormsProtectionEnum.None)
@@ -262,59 +240,14 @@ 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);
@@ -328,11 +261,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) {
@@ -350,57 +280,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)
@@ -481,21 +377,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)
@@ -515,7 +396,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)
@@ -583,16 +464,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/MembershipProvider.cs
@@ -87,57 +87,33 @@ protected virtual void OnValidatingPassword (ValidatePasswordEventArgs args)
eh (this, args);
}
- SymmetricAlgorithm GetAlg ()
+ SymmetricAlgorithm GetAlgorithm ()
{
- MachineKeySection section = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
+ MachineKeySection section = MachineKeySection.Config;
if (section.DecryptionKey.StartsWith ("AutoGenerate"))
throw new ProviderException ("You must explicitly specify a decryption key in the <machineKey> section when using encrypted passwords.");
- string alg_type = section.Decryption;
- if (alg_type == "Auto")
- alg_type = "AES";
+ SymmetricAlgorithm sa = section.GetDecryptionAlgorithm ();
+ if (sa == null)
+ throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", section.Decryption));
- SymmetricAlgorithm alg = null;
- if (alg_type == "AES")
- alg = Rijndael.Create ();
- else if (alg_type == "3DES")
- alg = TripleDES.Create ();
- else
- throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", alg_type));
-
- alg.Key = MachineKeySectionUtils.DecryptionKey192Bits (section);
- return alg;
+ sa.Key = section.GetDecryptionKey ();
+ return sa;
}
internal const int SALT_BYTES = 16;
protected virtual byte [] DecryptPassword (byte [] encodedPassword)
{
- using (SymmetricAlgorithm alg = GetAlg ()) {
- // alg.Key is set in GetAlg based on web.config
- // iv is the first part of the encodedPassword
- byte [] iv = new byte [alg.IV.Length];
- Array.Copy (encodedPassword, 0, iv, 0, iv.Length);
- using (ICryptoTransform decryptor = alg.CreateDecryptor (alg.Key, iv)) {
- return decryptor.TransformFinalBlock (encodedPassword, iv.Length, encodedPassword.Length - iv.Length);
- }
+ using (SymmetricAlgorithm sa = GetAlgorithm ()) {
+ return MachineKeySectionUtils.Decrypt (sa, encodedPassword, 0, encodedPassword.Length);
}
}
protected virtual byte[] EncryptPassword (byte[] password)
{
- using (SymmetricAlgorithm alg = GetAlg ()) {
- // alg.Key is set in GetAlg based on web.config
- // alg.IV is randomly set (default behavior) and perfect for our needs
- byte [] iv = alg.IV;
- using (ICryptoTransform encryptor = alg.CreateEncryptor (alg.Key, iv)) {
- byte [] encrypted = encryptor.TransformFinalBlock (password, 0, password.Length);
- byte [] output = new byte [iv.Length + encrypted.Length];
- // note: the IV can be public, however it should not be based on the password
- Array.Copy (iv, 0, output, 0, iv.Length);
- Array.Copy (encrypted, 0, output, iv.Length, encrypted.Length);
- return output;
- }
+ using (SymmetricAlgorithm sa = GetAlgorithm ()) {
+ return MachineKeySectionUtils.Encrypt (sa, password);
}
}
}
View
93 mcs/class/System.Web/System.Web.Security/RolePrincipal.cs
@@ -31,7 +31,6 @@
#if NET_2_0
using System.Collections.Specialized;
-using System.Security.Cryptography;
using System.Security.Permissions;
using System.Security.Principal;
using System.Web.Configuration;
@@ -143,42 +142,16 @@ 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)
@@ -190,45 +163,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);
@@ -273,11 +219,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/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
54 mcs/class/System.Web/System.Web.UI/LosFormatter.cs
@@ -28,10 +28,11 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+using System.Configuration;
using System.IO;
-using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
+using System.Web.Configuration;
namespace System.Web.UI {
@@ -48,11 +49,14 @@ public LosFormatter ()
#if NET_1_1
public LosFormatter (bool enableMac, string macKeyModifier)
- : this (enableMac, Convert.FromBase64String (macKeyModifier))
{
+ osf = new ObjectStateFormatter ();
+ if (enableMac && macKeyModifier != null && macKeyModifier.Length > 0) {
+ SetMacKey (Convert.FromBase64String (macKeyModifier));
+ }
}
#endif
- [MonoTODO]
+
#if NET_2_0
public
#else
@@ -60,25 +64,53 @@ public LosFormatter (bool enableMac, string macKeyModifier)
#endif
LosFormatter (bool enableMac, byte[] macKeyModifier)
{
- if (enableMac)
- osf = new ObjectStateFormatter (macKeyModifier);
- else
- osf = new ObjectStateFormatter ();
+ osf = new ObjectStateFormatter ();
+ if (enableMac && (macKeyModifier != null)) {
+ SetMacKey (macKeyModifier);
+ }
}
+ void SetMacKey (byte[] macKeyModifier)
+ {
+ try {
+#if NET_2_0
+ osf.Section.ValidationKey = MachineKeySectionUtils.GetHexString (macKeyModifier);
+#else
+ osf.Section.SetValidationKey (MachineKeySectionUtils.GetHexString (macKeyModifier));
+#endif
+ }
+ catch (ArgumentException) {
+ }
+#if NET_2_0
+ catch (ConfigurationErrorsException) {
+ // bad key (e.g. size), default key will be used
+ }
+#else
+ catch (HttpException) {
+ // bad key (e.g. size), default key will be used
+ }
+#endif
+ }
+
public object Deserialize (Stream stream)
{
if (stream == null)
throw new ArgumentNullException ("stream");
+#if NET_4_0
+ using (StreamReader sr = new StreamReader (stream)) {
+ return Deserialize (sr.ReadToEnd ());
+ }
+#else
long streamLength = -1;
if (stream.CanSeek)
streamLength = stream.Length;
- byte [] bytes = new byte [streamLength >= 0 ? streamLength : 2048];
+
MemoryStream ms = null;
if (streamLength != -1 && (stream is MemoryStream) && stream.Position == 0) {
// We save allocating a new stream and reading in this case.
ms = (MemoryStream) stream;
} else {
+ byte [] bytes = new byte [streamLength >= 0 ? streamLength : 2048];
ms = new MemoryStream ();
int n;
while ((n = stream.Read (bytes, 0, bytes.Length)) > 0)
@@ -89,6 +121,7 @@ public object Deserialize (Stream stream)
string b64 = Encoding.ASCII.GetString (ms.GetBuffer (),
0, (int) streamLength);
return Deserialize (b64);
+#endif
}
public object Deserialize (TextReader input)
@@ -116,7 +149,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
158 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 {
@@ -56,9 +55,11 @@ namespace System.Web.UI {
sealed class ObjectStateFormatter : IFormatter, IStateFormatter
{
Page page;
- HashAlgorithm algo;
- byte [] vkey;
-
+#if NET_2_0
+ MachineKeySection section;
+#else
+ MachineKeyConfig section;
+#endif
public ObjectStateFormatter ()
{
}
@@ -67,18 +68,11 @@ 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;
+ return section != null;
} else {
#if NET_2_0
@@ -92,48 +86,44 @@ internal ObjectStateFormatter (byte [] vkey)
}
}
- internal HashAlgorithm GetAlgo ()
- {
- if (algo != null)
- return algo;
- if (!EnableMac)
- return null;
-
- byte [] algoKey;
- if (page != null) {
+ bool NeedViewStateEncryption {
+ get {
#if NET_2_0
- MachineKeySection mconfig = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
- algoKey = MachineKeySectionUtils.ValidationKeyBytes (mconfig);
+ return (page == null) ? false : page.NeedViewStateEncryption;
#else
- MachineKeyConfig mconfig = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig;
- algoKey = mconfig.ValidationKey;
+ return false;
#endif
- } else
- algoKey = vkey;
-
- algo = new HMACSHA1 (algoKey);
- return algo;
+ }
}
-
- static int ValidateInput (HashAlgorithm algo, byte [] data, int offset, int size)
- {
- if (algo == null)
- throw new HttpException ("Unable to validate data.");
-
- int hash_size = algo.HashSize / 8;
- if (size != 0 && size < hash_size)
- throw new HttpException ("Unable to validate data.");
-
- int data_length = size - hash_size;
- MemoryStream data_stream = new MemoryStream (data, offset, data_length, false, false);
- byte [] hash = algo.ComputeHash (data_stream);
- for (int i = 0; i < hash_size; i++) {
- if (hash [i] != data [data_length + i])
- throw new HttpException ("Unable to validate data.");
- }
- return data_length;
+#if NET_2_0
+ internal MachineKeySection Section {
+ get {
+ if (section == null)
+ section = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection ("system.web/machineKey");
+ return section;
+ }
+ set {
+ section = value;
+ }
}
-
+#else
+ internal MachineKeyConfig Section {
+ get {
+ if (section == null) {
+ HttpContext context = HttpContext.Current;
+ if (context == null)
+ section = new MachineKeyConfig (null);
+ else
+ section = (MachineKeyConfig) context.GetConfig ("system.web/machineKey");
+ }
+
+ return section;
+ }
+ set {
+ section = value;
+ }
+ }
+#endif
public object Deserialize (Stream inputStream)
{
if (inputStream == null)
@@ -153,21 +143,25 @@ public object Deserialize (string inputString)
if (inputString == "")
return "";
#endif
- byte [] buffer = Convert.FromBase64String (inputString);
- int length;
- if (buffer == null || (length = buffer.Length) == 0)
+ byte [] data = Convert.FromBase64String (inputString);
+ if (data == null || (data.Length) == 0)
throw new ArgumentNullException ("inputString");
- if (page != null && EnableMac)
- length = ValidateInput (GetAlgo (), buffer, 0, length);
-#if NET_2_0
- bool isEncrypted = ((int)buffer [--length] == 1)? true : false;
-#endif
- Stream ms = new MemoryStream (buffer, 0, length, false, false);
-#if NET_2_0
- if (isEncrypted)
- ms = new CryptoStream (ms, page.GetCryptoTransform (CryptoStreamMode.Read), CryptoStreamMode.Read);
-#endif
- return Deserialize (ms);
+ if (NeedViewStateEncryption) {
+ if (EnableMac) {
+ data = MachineKeySectionUtils.VerifyDecrypt (Section, data);
+ } else {
+ data = MachineKeySectionUtils.Decrypt (Section, data);
+ }
+ } else if (EnableMac) {
+ data = MachineKeySectionUtils.Verify (Section, data);
+ }
+
+ if (data == null)
+ throw new HttpException ("Unable to validate data.");
+
+ using (MemoryStream ms = new MemoryStream (data)) {
+ return Deserialize (ms);
+ }
}
public string Serialize (object stateGraph)
@@ -175,31 +169,23 @@ public string Serialize (object stateGraph)
if (stateGraph == null)
return "";
- MemoryStream ms = new MemoryStream ();
- Stream output = ms;
-#if NET_2_0
- bool needEncryption = page == null ? false : page.NeedViewStateEncryption;
- if (needEncryption){
- output = new CryptoStream (output, page.GetCryptoTransform (CryptoStreamMode.Write), CryptoStreamMode.Write);
+ byte[] data = null;
+ using (MemoryStream ms = new MemoryStream ()) {
+ Serialize (ms, stateGraph);
+ data = ms.GetBuffer ();
}
-#endif
- Serialize (output, stateGraph);
-#if NET_2_0
- ms.WriteByte((byte)(needEncryption? 1 : 0));
-#endif
-
-#if TRACE
- ms.WriteTo (File.OpenWrite (Path.GetTempFileName ()));
-#endif
- if (EnableMac && ms.Length > 0) {
- HashAlgorithm algo = GetAlgo ();
- if (algo != null) {
- byte [] hash = algo.ComputeHash (ms.GetBuffer (), 0, (int) ms.Length);
- ms.Write (hash, 0, hash.Length);
+
+ if (NeedViewStateEncryption) {
+ if (EnableMac) {
+ data = MachineKeySectionUtils.EncryptSign (Section, data);
+ } else {
+ data = MachineKeySectionUtils.Encrypt (Section, data);
}
-
+ } else if (EnableMac) {
+ data = MachineKeySectionUtils.Sign (Section, data);
+
}
- return Convert.ToBase64String (ms.GetBuffer (), 0, (int) ms.Length);
+ return Convert.ToBase64String (data, 0, data.Length);
}
public void Serialize (Stream outputStream, object stateGraph)
View
69 mcs/class/System.Web/System.Web.UI/Page.cs
@@ -38,7 +38,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;
@@ -2535,74 +2534,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
@@ -7,6 +7,7 @@ Assembly/AssemblyInfo.cs
../Managed.Windows.Forms/System.Resources/ResXFileRef.cs
../Managed.Windows.Forms/System.Resources/ResXDataNode.cs
../Managed.Windows.Forms/System.Resources/ResXNullRef.cs
+../Mono.Security/Mono.Security.Cryptography/TlsHMAC.cs
System.Web.Configuration_2.0/CapabilitiesBuild.cs
System.Web.Configuration_2.0/CapabilitiesResult.cs
System.Web.Configuration_2.0/ICapabilitiesProcess.cs
View
2  mcs/class/System.Web/System.Web_test.dll.sources
@@ -85,6 +85,8 @@ System.Web.Configuration/CustomErrorCollectionTest.cs
System.Web.Configuration/DeploymentSectionTest.cs
System.Web.Configuration/GlobalizationSectionTest.cs
System.Web.Configuration/HostingEnvironmentSectionTest.cs
+System.Web.Configuration/MachineKeySectionTest.cs
+System.Web.Configuration/MachineKeySectionUtilsTest.cs
System.Web.Configuration/MachineKeyValidationConverterTest.cs
System.Web.Configuration/NullableStringValidatorTest.cs
System.Web.Configuration/ProfilePropertySettingsTest.cs