MachineKeySection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Configuration / MachineKeySection.cs / 1586730 / MachineKeySection.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.Configuration 
{ 
    using System;
    using System.Xml; 
    using System.Configuration;
    using System.Collections.Specialized;
    using System.Collections;
    using System.IO; 
    using System.Text;
    using System.Security.Cryptography; 
    using System.Web.Util; 
    using System.Globalization;
    using System.Web.Hosting; 
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.Security.Permissions;
 
    /*
             
         
    */
 
    public sealed class MachineKeySection : ConfigurationSection
    {
        // If the default validation algorithm changes, be sure to update the _HashSize and _AutoGenValidationKeySize fields also.
        internal const string DefaultValidationAlgorithm = "HMACSHA256"; 
        internal const MachineKeyValidation DefaultValidation = MachineKeyValidation.SHA1;
 
        private static ConfigurationPropertyCollection _properties; 
        private static readonly ConfigurationProperty _propValidationKey =
            new ConfigurationProperty("validationKey", typeof(string), "AutoGenerate,IsolateApps", StdValidatorsAndConverters.WhiteSpaceTrimStringConverter, StdValidatorsAndConverters.NonEmptyStringValidator, ConfigurationPropertyOptions.None); 
        private static readonly ConfigurationProperty _propDecryptionKey =
            new ConfigurationProperty("decryptionKey", typeof(string),"AutoGenerate,IsolateApps",StdValidatorsAndConverters.WhiteSpaceTrimStringConverter, StdValidatorsAndConverters.NonEmptyStringValidator, ConfigurationPropertyOptions.None);
        private static readonly ConfigurationProperty _propDecryption =
            new ConfigurationProperty("decryption", typeof(string), "Auto", StdValidatorsAndConverters.WhiteSpaceTrimStringConverter, StdValidatorsAndConverters.NonEmptyStringValidator, ConfigurationPropertyOptions.None); 
        private static readonly ConfigurationProperty _propValidation =
            new ConfigurationProperty("validation", typeof(string), DefaultValidationAlgorithm, StdValidatorsAndConverters.WhiteSpaceTrimStringConverter, StdValidatorsAndConverters.NonEmptyStringValidator, ConfigurationPropertyOptions.None); 
        private static readonly ConfigurationProperty _propCompatibilityMode = 
            new ConfigurationProperty("compatibilityMode", typeof(MachineKeyCompatibilityMode), MachineKeyCompatibilityMode.Framework20SP1, null, null, ConfigurationPropertyOptions.None);
 
        static object s_initLock = new object();
        static MachineKeySection s_config;
        static MachineKeyCompatibilityMode s_compatMode;
        private static RNGCryptoServiceProvider s_randomNumberGenerator; 
        private static SymmetricAlgorithm s_oSymAlgoDecryption;
        private static SymmetricAlgorithm s_oSymAlgoValidation; 
        private static byte[] s_validationKey; 
        private static byte[] s_inner = null;
        private static byte[] s_outer = null; 
        internal static bool IsDecryptionKeyAutogenerated { get { EnsureConfig(); return s_config.AutogenKey; } }
        private bool _AutogenKey;
        internal bool AutogenKey { get { RuntimeDataInitialize(); return _AutogenKey; } }
        private byte[] _ValidationKey; 
        private byte[] _DecryptionKey;
        private bool DataInitialized = false; 
        private static bool _CustomValidationTypeIsKeyed; 
        private static string _CustomValidationName;
        private static int _IVLengthDecryption = 64; 
        private static int _IVLengthValidation = 64;
        private static int _HashSize = HMACSHA256_HASH_SIZE;
        private static int _AutoGenValidationKeySize = HMACSHA256_KEY_SIZE;
        private static int _AutoGenDecryptionKeySize = 24; 
        private static bool _UseHMACSHA = true;
        private static bool _UsingCustomEncryption = false; 
        private static SymmetricAlgorithm s_oSymAlgoLegacy; 

        private const int MD5_KEY_SIZE          = 64; 
        private const int MD5_HASH_SIZE         = 16;
        private const int SHA1_KEY_SIZE         = 64;
        private const int HMACSHA256_KEY_SIZE       = 64;
        private const int HMACSHA384_KEY_SIZE       = 128; 
        private const int HMACSHA512_KEY_SIZE       = 128;
        private const int SHA1_HASH_SIZE        = 20; 
        private const int HMACSHA256_HASH_SIZE      = 32; 
        private const int HMACSHA384_HASH_SIZE      = 48;
        private const int HMACSHA512_HASH_SIZE      = 64; 
        private const string ALGO_PREFIX        = "alg:";

        internal byte[] ValidationKeyInternal { get { RuntimeDataInitialize();  return (byte[])_ValidationKey.Clone(); } }
        internal byte[] DecryptionKeyInternal { get { RuntimeDataInitialize(); return (byte[])_DecryptionKey.Clone(); } } 
        internal static int HashSize { get { s_config.RuntimeDataInitialize(); return _HashSize; } }
        internal static int ValidationKeySize { get { s_config.RuntimeDataInitialize(); return _AutoGenValidationKeySize; } } 
 
        static MachineKeySection()
        { 
            // Property initialization
            _properties = new ConfigurationPropertyCollection();
            _properties.Add(_propValidationKey);
            _properties.Add(_propDecryptionKey); 
            _properties.Add(_propValidation);
            _properties.Add(_propDecryption); 
            _properties.Add(_propCompatibilityMode); 
        }
 
        public MachineKeySection()
        {
        }
 
        internal static MachineKeyCompatibilityMode CompatMode
        { 
            get 
            {
                EnsureConfig(); 
                return s_compatMode;
            }
        }
 

        protected override ConfigurationPropertyCollection Properties 
        { 
            get
            { 
                return _properties;
            }
        }
 
        [ConfigurationProperty("validationKey", DefaultValue = "AutoGenerate,IsolateApps")]
        [TypeConverter(typeof(WhiteSpaceTrimStringConverter))] 
        [StringValidator(MinLength = 1)] 
        public string ValidationKey
        { 
            get
            {
                return (string)base[_propValidationKey];
            } 
            set
            { 
                base[_propValidationKey] = value; 
            }
        } 

        [ConfigurationProperty("decryptionKey", DefaultValue = "AutoGenerate,IsolateApps")]
        [TypeConverter(typeof(WhiteSpaceTrimStringConverter))]
        [StringValidator(MinLength = 1)] 
        public string DecryptionKey
        { 
            get 
            {
                return (string)base[_propDecryptionKey]; 
            }
            set
            {
                base[_propDecryptionKey] = value; 
            }
        } 
 
        [ConfigurationProperty("decryption", DefaultValue = "Auto")]
        [TypeConverter(typeof(WhiteSpaceTrimStringConverter))] 
        [StringValidator(MinLength = 1)]
        public string Decryption {
            get {
                string s = base[_propDecryption] as string; 
                if (s == null)
                    return "Auto"; 
                if (s != "Auto" && s != "AES" && s != "3DES" && s != "DES" && !s.StartsWith(ALGO_PREFIX, StringComparison.Ordinal)) 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_decryption_enum), ElementInformation.Properties["decryption"].Source, ElementInformation.Properties["decryption"].LineNumber);
                return s; 
            }
            set {
                if (value != "AES" && value != "3DES" && value != "Auto" && value != "DES" && !value.StartsWith(ALGO_PREFIX, StringComparison.Ordinal))
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_decryption_enum), ElementInformation.Properties["decryption"].Source, ElementInformation.Properties["decryption"].LineNumber); 
                base[_propDecryption] = value;
            } 
        } 
        private bool _validationIsCached;
        private string _cachedValidation; 
        private MachineKeyValidation _cachedValidationEnum;

        [ConfigurationProperty("validation", DefaultValue = DefaultValidationAlgorithm)]
        [TypeConverter(typeof(WhiteSpaceTrimStringConverter))] 
        [StringValidator(MinLength = 1)]
        public string ValidationAlgorithm 
        { 
            get {
                if (!_validationIsCached) 
                    CacheValidation();
                return _cachedValidation;
            } set {
                if (_validationIsCached && value == _cachedValidation) 
                    return;
                if (value == null) 
                    value = DefaultValidationAlgorithm; 
                _cachedValidationEnum = MachineKeyValidationConverter.ConvertToEnum(value);
                _cachedValidation = value; 
                base[_propValidation] = value;
                _validationIsCached = true;
            }
        } 

        private void CacheValidation() 
        { 
            _cachedValidation = (string)base[_propValidation];
            if (_cachedValidation == null) 
                _cachedValidation = DefaultValidationAlgorithm;
            _cachedValidationEnum = MachineKeyValidationConverter.ConvertToEnum(_cachedValidation);
            _validationIsCached = true;
        } 

        public MachineKeyValidation Validation { 
            get { 
                if (_validationIsCached == false)
                    CacheValidation(); 
                return _cachedValidationEnum;
            } set {
                if (_validationIsCached && value == _cachedValidationEnum)
                    return; 
                _cachedValidation = MachineKeyValidationConverter.ConvertFromEnum(value);
                _cachedValidationEnum = value; 
                base[_propValidation] = _cachedValidation; 
                _validationIsCached = true;
            } 
        }


        [ConfigurationProperty("compatibilityMode", DefaultValue = MachineKeyCompatibilityMode.Framework20SP1)] 
        public MachineKeyCompatibilityMode CompatibilityMode
        { 
            get 
            {
                return (MachineKeyCompatibilityMode)base[_propCompatibilityMode]; 
            }
            set
            {
                base[_propCompatibilityMode] = value; 
            }
        } 
 
        protected override void Reset(ConfigurationElement parentElement)
        { 
            MachineKeySection parent = parentElement as MachineKeySection;
            base.Reset(parentElement);
            // copy the privates from the parent.
            if (parent != null) 
            {
//                _ValidationKey = parent.ValidationKeyInternal; 
//                _DecryptionKey = parent.DecryptionKeyInternal; 
//                _AutogenKey = parent.AutogenKey;
            } 
        }

        private void RuntimeDataInitialize()
        { 
            if (DataInitialized == false)
            { 
                byte [] bKeysRandom = null; 
                bool fNonHttpApp = false;
                string strKey = ValidationKey; 
                string appName = HttpRuntime.AppDomainAppVirtualPath;

                InitValidationAndEncyptionSizes();
 
                if( appName == null )
                { 
#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography 
 			// FEATURE_PAL
 
                    appName = System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName;

                    if( ValidationKey.Contains( "AutoGenerate" ) ||
                        DecryptionKey.Contains( "AutoGenerate" ) ) 
                    {
                        fNonHttpApp = true; 
 
                        bKeysRandom = new byte[ _AutoGenValidationKeySize + _AutoGenDecryptionKeySize ];
                        // Gernerate random keys 
                        RandomNumberGenerator.GetBytes(bKeysRandom);
                    }
#endif // !FEATURE_PAL
                } 

                bool fAppSpecific = StringUtil.StringEndsWith(strKey, ",IsolateApps"); 
                if (fAppSpecific) 
                {
                    strKey = strKey.Substring(0, strKey.Length - ",IsolateApps".Length); 
                }
                if (strKey == "AutoGenerate")
                { // case sensitive
                    _ValidationKey = new byte[_AutoGenValidationKeySize]; 

                    if( fNonHttpApp ) 
                    { 
                        Buffer.BlockCopy( bKeysRandom, 0, _ValidationKey, 0, _AutoGenValidationKeySize);
                    } 
                    else
                    {
                        Buffer.BlockCopy(HttpRuntime.s_autogenKeys, 0, _ValidationKey, 0, _AutoGenValidationKeySize);
                    } 
                }
                else 
                { 
                    if (strKey.Length < 40 || (strKey.Length & 0x1) == 1)
                        throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_cookie_authentication_validation_key, strKey.Length.ToString(CultureInfo.InvariantCulture)), ElementInformation.Properties["validationKey"].Source, ElementInformation.Properties["validationKey"].LineNumber); 

                    _ValidationKey = HexStringToByteArray(strKey);
                    if (_ValidationKey == null)
                        throw new ConfigurationErrorsException(SR.GetString(SR.Invalid_validation_key), ElementInformation.Properties["validationKey"].Source, ElementInformation.Properties["validationKey"].LineNumber); 
                }
                if (fAppSpecific) 
                { 
                    int dwCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode( appName );
                    _ValidationKey[0] = (byte)(dwCode & 0xff); 
                    _ValidationKey[1] = (byte)((dwCode & 0xff00) >> 8);
                    _ValidationKey[2] = (byte)((dwCode & 0xff0000) >> 16);
                    _ValidationKey[3] = (byte)((dwCode & 0xff000000) >> 24);
                } 

                strKey = DecryptionKey; 
                fAppSpecific = StringUtil.StringEndsWith(strKey, ",IsolateApps"); 
                if (fAppSpecific)
                { 
                    strKey = strKey.Substring(0, strKey.Length - ",IsolateApps".Length);
                }

                if (strKey == "AutoGenerate") 
                { // case sensitive
                    _DecryptionKey = new byte[_AutoGenDecryptionKeySize]; 
 
                    if( fNonHttpApp )
                    { 
                        Buffer.BlockCopy( bKeysRandom, _AutoGenValidationKeySize, _DecryptionKey, 0, _AutoGenDecryptionKeySize);
                    }
                    else
                    { 
                        Buffer.BlockCopy(HttpRuntime.s_autogenKeys, _AutoGenValidationKeySize, _DecryptionKey, 0, _AutoGenDecryptionKeySize);
                    } 
 
                    _AutogenKey = true;
                } 
                else
                {
                    _AutogenKey = false;
                    if ((strKey.Length & 1) != 0) 
                        throw new ConfigurationErrorsException(SR.GetString(SR.Invalid_decryption_key), ElementInformation.Properties["decryptionKey"].Source, ElementInformation.Properties["decryptionKey"].LineNumber);
 
                    _DecryptionKey = HexStringToByteArray(strKey); 
                    if (_DecryptionKey == null)
                        throw new ConfigurationErrorsException(SR.GetString(SR.Invalid_decryption_key), ElementInformation.Properties["decryptionKey"].Source, ElementInformation.Properties["decryptionKey"].LineNumber); 
                }
                if (fAppSpecific)
                {
                    int dwCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(appName); 
                    _DecryptionKey[0] = (byte)(dwCode & 0xff);
                    _DecryptionKey[1] = (byte)((dwCode & 0xff00) >> 8); 
                    _DecryptionKey[2] = (byte)((dwCode & 0xff0000) >> 16); 
                    _DecryptionKey[3] = (byte)((dwCode & 0xff000000) >> 24);
                } 
                DataInitialized = true;
            }
        }
 
        internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length)
        { 
            // DevDiv Bugs 137864: IVType.Hash is the default for compatibility reasons. It allows the result to be 
            // consistent across multiple calls with the same data. This was the behavior when there was no padding.
            return EncryptOrDecryptData(fEncrypt, buf, modifier, start, length, false, false, IVType.Hash); 
        }

        internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length, bool useValidationSymAlgo)
        { 
            // DevDiv Bugs 137864: IVType.Hash is the default for compatibility reasons. It allows the result to be
            // consistent across multiple calls with the same data. This was the behavior when there was no padding. 
            return EncryptOrDecryptData(fEncrypt, buf, modifier, start, length, useValidationSymAlgo, false, IVType.Hash); 
        }
 
        internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length,
                                                    bool useValidationSymAlgo, bool useLegacyMode, IVType ivType)
        {
            EnsureConfig(); 

            if (useLegacyMode) 
                useLegacyMode = _UsingCustomEncryption; // only use legacy mode for custom algorithms 

            System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
            ICryptoTransform oDesEnc = GetCryptoTransform(fEncrypt, useValidationSymAlgo, useLegacyMode);
            CryptoStream cs = new CryptoStream(ms, oDesEnc, CryptoStreamMode.Write);

            // DevDiv Bugs 137864: Add Random or Hashed IV to beginning of data to be encrypted. 
            // IVType.None is used by MembershipProvider which requires compatibility even in SP2 mode.
            bool createIV = ((ivType != IVType.None) && (CompatMode > MachineKeyCompatibilityMode.Framework20SP1)); 
 
            if (fEncrypt && createIV)
            { 
                byte[]  iv       = null;
                int     ivLength = (useValidationSymAlgo ? _IVLengthValidation : _IVLengthDecryption);
                switch (ivType)
                { 
                case IVType.Hash:
                    iv = GetIVHash(buf, ivLength); 
                    break; 
                case IVType.Random:
                    iv = new byte[ivLength]; 
                    RandomNumberGenerator.GetBytes(iv);
                    break;
                }
                Debug.Assert(iv != null, "Invalid value for IVType: " + ivType.ToString("G")); 
                cs.Write(iv, 0, iv.Length);
            } 
 
            cs.Write(buf, start, length);
            if (fEncrypt && modifier != null) 
            {
                cs.Write(modifier, 0, modifier.Length);
            }
 
            cs.FlushFinalBlock();
            byte[] paddedData = ms.ToArray(); 
            byte[] bData; 
            cs.Close();
            ReturnCryptoTransform(fEncrypt, oDesEnc, useValidationSymAlgo, useLegacyMode); 

            // DevDiv Bugs 137864: Strip Random or Hashed IV from beginning of unencrypted data
            if (!fEncrypt && createIV)
            { 
                // strip off the first bytes that were either random bits or a hash of the original data
                // either way it is always equal to the key length 
                int ivLength = (useValidationSymAlgo ? _IVLengthValidation : _IVLengthDecryption); 
                int bDataLength = paddedData.Length - ivLength;
 
                // valid if the data is long enough to have included the padding
                if (bDataLength >= 0)
                {
                    bData = new byte[bDataLength]; 
                    // copy from the padded data to non-padded buffer bData.
                    // dont bother with copy if the data is entirely the padding 
                    if (bDataLength > 0) 
                    {
                        Buffer.BlockCopy(paddedData, ivLength, bData, 0, bDataLength); 
                    }
                }
                else
                { 
                    // data is not padded because it is not long enough
                    bData = paddedData; 
                } 
            }
            else 
            {
                bData = paddedData;
            }
 
            if (!fEncrypt && modifier != null && modifier.Length > 0)
            { 
                for(int iter=0; iter _AutoGenValidationKeySize)
            {
                key = new byte[_HashSize]; 
                int hr = UnsafeNativeMethods.GetSHA1Hash(validationKey, validationKey.Length, key, key.Length);
                Marshal.ThrowExceptionForHR(hr); 
            } 

            if (inner == null) 
                inner = new byte[_AutoGenValidationKeySize];
            if (outer == null)
                outer = new byte[_AutoGenValidationKeySize];
 
            int i;
            for (i = 0; i < _AutoGenValidationKeySize; i++) { 
                inner[i] = 0x36; 
                outer[i] = 0x5C;
            } 
            for (i=0; i < validationKey.Length; i++) {
                inner[i] ^= validationKey[i];
                outer[i] ^= validationKey[i];
            } 
        }
 
        private static byte[] GetHMACSHA1Hash(byte[] buf, byte[] modifier, int start, int length) { 
            if (start < 0 || start > buf.Length)
                throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "start")); 
            if (length < 0 || buf == null || (start + length) > buf.Length)
                throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "length"));
            byte[] hash = new byte[_HashSize];
            int hr = UnsafeNativeMethods.GetHMACSHA1Hash(buf, start, length, 
                                                         modifier, (modifier == null) ? 0 : modifier.Length,
                                                         s_inner, s_inner.Length, s_outer, s_outer.Length, 
                                                         hash, hash.Length); 
            if (hr == 0)
                return hash; 
            _UseHMACSHA = false;
            return null;
        }
 
        internal static string HashAndBase64EncodeString(string s)
        { 
            byte[] ab; 
            byte[] hash;
            string result; 

            ab = Encoding.Unicode.GetBytes(s);
            hash = HashData(ab, null, 0, ab.Length);
            result = Convert.ToBase64String(hash); 

            return result; 
        } 

        static internal void DestroyByteArray(byte[] buf) 
        {
            if (buf == null || buf.Length < 1)
                return;
            for (int iter = 0; iter < buf.Length; iter++) 
                buf[iter] = (byte)0;
        } 
 
        internal void DestroyKeys()
        { 
            MachineKeySection.DestroyByteArray(_ValidationKey);
            MachineKeySection.DestroyByteArray(_DecryptionKey);
        }
 
        static char[] s_acharval;
 
        static unsafe internal String ByteArrayToHexString(byte[] buf, int iLen) 
        {
            char[] acharval = s_acharval; 
            if (acharval == null)
            {
                acharval = new char[16];
                for (int i = acharval.Length; --i >= 0; ) 
                {
                    if (i < 10) 
                    { 
                        acharval[i] = (char)('0' + i);
                    } 
                    else
                    {
                        acharval[i] = (char)('A' + (i - 10));
                    } 
                }
 
                s_acharval = acharval; 
            }
 
            if (buf == null)
                return null;

            if (iLen == 0) 
                iLen = buf.Length;
 
            char[] chars = new char[iLen * 2]; 
            fixed (char* fc = chars, fcharval = acharval)
            { 
                fixed (byte* fb = buf)
                {
                    char* pc;
                    byte* pb; 
                    pc = fc;
                    pb = fb; 
                    while (--iLen >= 0) 
                    {
                        *pc++ = fcharval[(*pb & 0xf0) >> 4]; 
                        *pc++ = fcharval[*pb & 0x0f];
                        pb++;
                    }
                } 
            }
 
            return new String(chars); 
        }
 
        static void EnsureConfig()
        {
            if (s_config == null)
            { 
                lock (s_initLock)
                { 
                    if (s_config == null) 
                    {
                        MachineKeySection config = RuntimeConfig.GetAppConfig().MachineKey; 
                        config.ConfigureEncryptionObject();
                        s_config = config;
                        s_compatMode = config.CompatibilityMode;
                    } 
                }
            } 
        } 

        // NOTE: When encoding the data, this method *may* return the same reference to the input "buf" parameter 
        // with the hash appended in the end if there's enough space.  The "length" parameter would also be
        // appropriately adjusted in those cases.  This is an optimization to prevent unnecessary copying of
        // buffers.
        internal static byte[] GetEncodedData(byte[] buf, byte[] modifier, int start, ref int length) 
        {
            EnsureConfig(); 
 
            byte[] bHash = HashData(buf, modifier, start, length);
            byte[] returnBuffer; 

            if (buf.Length - start - length >= bHash.Length)
            {
                // Append hash to end of buffer if there's space 
                Buffer.BlockCopy(bHash, 0, buf, start + length, bHash.Length);
                returnBuffer = buf; 
            } 
            else
            { 
                returnBuffer = new byte[length + bHash.Length];
                Buffer.BlockCopy(buf, start, returnBuffer, 0, length);
                Buffer.BlockCopy(bHash, 0, returnBuffer, length, bHash.Length);
                start = 0; 
            }
            length += bHash.Length; 
 
            if (s_config.Validation == MachineKeyValidation.TripleDES || s_config.Validation == MachineKeyValidation.AES) {
                returnBuffer = EncryptOrDecryptData(true, returnBuffer, modifier, start, length, true); 
                length = returnBuffer.Length;
            }
            return returnBuffer;
        } 

        // NOTE: When decoding the data, this method *may* return the same reference to the input "buf" parameter 
        // with the "dataLength" parameter containing the actual length of the data in the "buf" (i.e. length of actual 
        // data is (total length of data - hash length)). This is an optimization to prevent unnecessary copying of buffers.
        internal static byte[] GetDecodedData(byte[] buf, byte[] modifier, int start, int length, ref int dataLength) 
        {
            EnsureConfig();

            if (s_config.Validation == MachineKeyValidation.TripleDES || s_config.Validation == MachineKeyValidation.AES) { 
                buf = EncryptOrDecryptData(false, buf, modifier, start, length, true);
                if (buf == null || buf.Length < _HashSize) 
                    throw new HttpException(SR.GetString(SR.Unable_to_validate_data)); 
                length = buf.Length;
                start = 0; 
            }

            if (length < _HashSize || start < 0 || start >= length)
                throw new HttpException(SR.GetString(SR.Unable_to_validate_data)); 
            byte[] bHash = HashData(buf, modifier, start, length - _HashSize);
            for (int iter = 0; iter < bHash.Length; iter++) 
                if (bHash[iter] != buf[start + length - _HashSize + iter]) 
                    throw new HttpException(SR.GetString(SR.Unable_to_validate_data));
 
            dataLength = length - _HashSize;
            return buf;
        }
 
        internal static byte[] HashData(byte[] buf, byte[] modifier, int start, int length)
        { 
            EnsureConfig(); 

            if (s_config.Validation == MachineKeyValidation.MD5) 
                return HashDataUsingNonKeyedAlgorithm(null, buf, modifier, start, length, s_validationKey);
            if (_UseHMACSHA) {
                byte [] hash = GetHMACSHA1Hash(buf, modifier, start, length);
                if (hash != null) 
                    return hash;
            } 
            if (_CustomValidationTypeIsKeyed) { 
                return HashDataUsingKeyedAlgorithm(KeyedHashAlgorithm.Create(_CustomValidationName),
                                                   buf, modifier, start, length, s_validationKey); 
            } else {
                return HashDataUsingNonKeyedAlgorithm(HashAlgorithm.Create(_CustomValidationName),
                                                      buf, modifier, start, length, s_validationKey);
            } 
        }
 
 
        private void ConfigureEncryptionObject()
        { 
            using (new ApplicationImpersonationContext())  {
                s_validationKey = ValidationKeyInternal;
                byte[] dKey = DecryptionKeyInternal;
                if (_UseHMACSHA) 
                    SetInnerOuterKeys(s_validationKey, ref s_inner, ref s_outer);
                DestroyKeys(); 
 
                switch (Decryption)
                { 
                case "3DES":
                    s_oSymAlgoDecryption = new TripleDESCryptoServiceProvider();
                    break;
                case "DES": 
                    s_oSymAlgoDecryption = new DESCryptoServiceProvider();
                    break; 
                case "AES": 
                    s_oSymAlgoDecryption = GetAESAlgorithm();
                    break; 
                case "Auto":
                    if (dKey.Length == 8) {
                        s_oSymAlgoDecryption = new DESCryptoServiceProvider();
                    } else { 
                        s_oSymAlgoDecryption = GetAESAlgorithm();
                    } 
                    break; 
                }
 
                if (s_oSymAlgoDecryption == null) // Shouldn't happen!
                    InitValidationAndEncyptionSizes();

                switch(Validation) 
                {
                case MachineKeyValidation.TripleDES: 
                    if (dKey.Length == 8) { 
                        s_oSymAlgoValidation = new DESCryptoServiceProvider();
                    } else { 
                        s_oSymAlgoValidation = new TripleDESCryptoServiceProvider();
                    }
                    break;
                case MachineKeyValidation.AES: 
                    s_oSymAlgoValidation = GetAESAlgorithm();
                    break; 
                } 
                if (s_oSymAlgoValidation != null) {
                    SetKeyOnSymAlgorithm(s_oSymAlgoValidation, dKey); 
                    _IVLengthValidation = RoundupNumBitsToNumBytes(s_oSymAlgoValidation.KeySize);
                }
                SetKeyOnSymAlgorithm(s_oSymAlgoDecryption, dKey);
                _IVLengthDecryption = RoundupNumBitsToNumBytes(s_oSymAlgoDecryption.KeySize); 
                InitLegacyEncAlgorithm(dKey);
                DestroyByteArray(dKey); 
            } 
        }
 
        private void SetKeyOnSymAlgorithm(SymmetricAlgorithm symAlgo, byte[] dKey)
        {
            try {
                if (dKey.Length > 8 && symAlgo is DESCryptoServiceProvider) { 
                    byte[] bTemp = new byte[8];
                    Buffer.BlockCopy(dKey, 0, bTemp, 0, 8); 
                    symAlgo.Key = bTemp; 
                    DestroyByteArray(bTemp);
                } else { 
                    symAlgo.Key = dKey;
                }
                symAlgo.GenerateIV();
                symAlgo.IV = new byte[symAlgo.IV.Length]; 
            } catch (Exception e) {
                throw new ConfigurationErrorsException(SR.GetString(SR.Bad_machine_key, e.Message), ElementInformation.Properties["decryptionKey"].Source, ElementInformation.Properties["decryptionKey"].LineNumber); 
            } 
        }
 
        private static ICryptoTransform GetCryptoTransform(bool fEncrypt, bool useValidationSymAlgo, bool legacyMode)
        {
            SymmetricAlgorithm algo = (legacyMode ? s_oSymAlgoLegacy : (useValidationSymAlgo ? s_oSymAlgoValidation : s_oSymAlgoDecryption));
            lock(algo) 
                return (fEncrypt ? algo.CreateEncryptor() : algo.CreateDecryptor());
        } 
 
        private static void ReturnCryptoTransform(bool fEncrypt, ICryptoTransform ct, bool useValidationSymAlgo, bool legacyMode)
        { 
            ct.Dispose();
        }

 

        static byte[] s_ahexval; 
        static internal byte[] HexStringToByteArray(String str) 
        {
            if (((uint)str.Length & 0x1) == 0x1) // must be 2 nibbles per byte 
            {
                return null;
            }
            byte[] ahexval = s_ahexval; // initialize a table for faster lookups 
            if (ahexval == null)
            { 
                ahexval = new byte['f' + 1]; 
                for (int i = ahexval.Length; --i >= 0; )
                { 
                    if ('0' <= i && i <= '9')
                    {
                        ahexval[i] = (byte)(i - '0');
                    } 
                    else if ('a' <= i && i <= 'f')
                    { 
                        ahexval[i] = (byte)(i - 'a' + 10); 
                    }
                    else if ('A' <= i && i <= 'F') 
                    {
                        ahexval[i] = (byte)(i - 'A' + 10);
                    }
                } 

                s_ahexval = ahexval; 
            } 

            byte[] result = new byte[str.Length / 2]; 
            int istr = 0, ir = 0;
            int n = result.Length;
            while (--n >= 0)
            { 
                int c1, c2;
                try 
                { 
                    c1 = ahexval[str[istr++]];
                } 
                catch (ArgumentNullException)
                {
                    c1 = 0;
                    return null;// Inavlid char 
                }
                catch (ArgumentException) 
                { 
                    c1 = 0;
                    return null;// Inavlid char 
                }
                catch (IndexOutOfRangeException)
                {
                    c1 = 0; 
                    return null;// Inavlid char
                } 
 
                try
                { 
                    c2 = ahexval[str[istr++]];
                }
                catch (ArgumentNullException)
                { 
                    c2 = 0;
                    return null;// Inavlid char 
                } 
                catch (ArgumentException)
                { 
                    c2 = 0;
                    return null;// Inavlid char
                }
                catch (IndexOutOfRangeException) 
                {
                    c2 = 0; 
                    return null;// Inavlid char 
                }
 
                result[ir++] = (byte)((c1 << 4) + c2);
            }

            return result; 
        }
 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        private void InitValidationAndEncyptionSizes() 
        {
            _CustomValidationName = ValidationAlgorithm;
            _CustomValidationTypeIsKeyed = true;
            switch(ValidationAlgorithm) 
            {
            case "AES": 
            case "3DES": 
                _UseHMACSHA = true;
                _HashSize = SHA1_HASH_SIZE; 
                _AutoGenValidationKeySize = SHA1_KEY_SIZE;
                break;
            case "SHA1":
                _UseHMACSHA = true; 
                _HashSize = SHA1_HASH_SIZE;
                _AutoGenValidationKeySize = SHA1_KEY_SIZE; 
                break; 
            case "MD5":
                _CustomValidationTypeIsKeyed = false; 
                _UseHMACSHA = false;
                _HashSize = MD5_HASH_SIZE;
                _AutoGenValidationKeySize = MD5_KEY_SIZE;
                break; 
            case "HMACSHA256":
                _UseHMACSHA = true; 
                _HashSize = HMACSHA256_HASH_SIZE; 
                _AutoGenValidationKeySize = HMACSHA256_KEY_SIZE;
                break; 
            case "HMACSHA384":
                _UseHMACSHA = true;
                _HashSize = HMACSHA384_HASH_SIZE;
                _AutoGenValidationKeySize = HMACSHA384_KEY_SIZE; 
                break;
            case "HMACSHA512": 
                _UseHMACSHA = true; 
                _HashSize = HMACSHA512_HASH_SIZE;
                _AutoGenValidationKeySize = HMACSHA512_KEY_SIZE; 
                break;
            default:
                _UseHMACSHA = false;
                if (!_CustomValidationName.StartsWith(ALGO_PREFIX, StringComparison.Ordinal)) { 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_validation_enum),
                                                           ElementInformation.Properties["validation"].Source, 
                                                           ElementInformation.Properties["validation"].LineNumber); 
                }
                _CustomValidationName = _CustomValidationName.Substring(ALGO_PREFIX.Length); 
                HashAlgorithm alg = null;
                try {
                    _CustomValidationTypeIsKeyed = false;
                    alg = HashAlgorithm.Create(_CustomValidationName); 
                } catch (Exception e) {
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_validation_enum), e, 
                                                           ElementInformation.Properties["validation"].Source, 
                                                           ElementInformation.Properties["validation"].LineNumber);
                } 
                if (alg == null)
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_validation_enum),
                                                           ElementInformation.Properties["validation"].Source,
                                                           ElementInformation.Properties["validation"].LineNumber); 

                _AutoGenValidationKeySize = 0; 
                _HashSize = 0; 
                _CustomValidationTypeIsKeyed = (alg is KeyedHashAlgorithm);
                if (!_CustomValidationTypeIsKeyed) { 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_validation_enum),
                                                           ElementInformation.Properties["validation"].Source,
                                                           ElementInformation.Properties["validation"].LineNumber);
                } 

                try { 
                    _HashSize = RoundupNumBitsToNumBytes(alg.HashSize); 
                    if (_CustomValidationTypeIsKeyed)
                        _AutoGenValidationKeySize = ((KeyedHashAlgorithm) alg).Key.Length; 
                    if (_AutoGenValidationKeySize < 1)
                        _AutoGenValidationKeySize = RoundupNumBitsToNumBytes(alg.InputBlockSize);
                    if (_AutoGenValidationKeySize < 1)
                        _AutoGenValidationKeySize = RoundupNumBitsToNumBytes(alg.OutputBlockSize); 
                } catch {}
 
                if (_HashSize < 1 || _AutoGenValidationKeySize < 1) { 
                    // If we didn't get the hash-size or key-size, perform a hash and get the sizes
                    byte [] buf = new byte[10]; 
                    byte [] buf2 = new byte[512];
                    RandomNumberGenerator.GetBytes(buf);
                    RandomNumberGenerator.GetBytes(buf2);
                    byte [] bHash = alg.ComputeHash(buf); 

                    _HashSize = bHash.Length; 
 
                    if (_AutoGenValidationKeySize < 1) {
                        if (_CustomValidationTypeIsKeyed) 
                            _AutoGenValidationKeySize = ((KeyedHashAlgorithm) alg).Key.Length;
                        else
                            _AutoGenValidationKeySize = RoundupNumBitsToNumBytes(alg.InputBlockSize);
                    } 
                    alg.Clear();
                } 
                if (_HashSize < 1) 
                    _HashSize = HMACSHA512_HASH_SIZE;
                if (_AutoGenValidationKeySize < 1) 
                    _AutoGenValidationKeySize = HMACSHA512_KEY_SIZE;
                break;
            }
 

            _AutoGenDecryptionKeySize = 0; 
            switch(Decryption) { 
            case "AES":
                _AutoGenDecryptionKeySize = 24; 
                break;
            case "3DES":
                _AutoGenDecryptionKeySize = 24;
                break; 
            case "Auto":
                _AutoGenDecryptionKeySize = 24; 
                break; 
            case "DES":
                if (ValidationAlgorithm == "AES" || ValidationAlgorithm == "3DES") 
                    _AutoGenDecryptionKeySize = 24;
                else
                    _AutoGenDecryptionKeySize = 8;
                break; 
            default:
                _UsingCustomEncryption = true; 
                if (!Decryption.StartsWith(ALGO_PREFIX, StringComparison.Ordinal)) { 
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_decryption_enum),
                                                           ElementInformation.Properties["decryption"].Source, 
                                                           ElementInformation.Properties["decryption"].LineNumber);
                }
                try {
                    s_oSymAlgoDecryption = SymmetricAlgorithm.Create(Decryption.Substring(ALGO_PREFIX.Length)); 
                } catch(Exception e) {
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_decryption_enum), e, 
                                                           ElementInformation.Properties["decryption"].Source, 
                                                           ElementInformation.Properties["decryption"].LineNumber);
                } 
                if (s_oSymAlgoDecryption == null)
                    throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_decryption_enum),
                                                           ElementInformation.Properties["decryption"].Source,
                                                           ElementInformation.Properties["decryption"].LineNumber); 

                _AutoGenDecryptionKeySize = RoundupNumBitsToNumBytes(s_oSymAlgoDecryption.KeySize); 
                break; 
            }
        } 

        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        internal static int RoundupNumBitsToNumBytes(int numBits) { 
            if (numBits < 0)
                return 0; 
            return (numBits / 8) + (((numBits & 7) != 0) ? 1 : 0); 
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        private static byte[] HashDataUsingNonKeyedAlgorithm(HashAlgorithm hashAlgo, byte[] buf, byte[] modifier,
                                                             int start, int length, byte[] validationKey) 
        {
            int     totalLength = length + validationKey.Length + ((modifier != null) ? modifier.Length : 0); 
            byte [] bAll        = new byte[totalLength]; 

            Buffer.BlockCopy(buf, start, bAll, 0, length); 
            if (modifier != null) {
                Buffer.BlockCopy(modifier, 0, bAll, length, modifier.Length);
            }
            Buffer.BlockCopy(validationKey, 0, bAll, length, validationKey.Length); 
            if (hashAlgo != null) {
                return hashAlgo.ComputeHash(bAll); 
            } else { 
                byte[] newHash = new byte[MD5_HASH_SIZE];
                int hr = UnsafeNativeMethods.GetSHA1Hash(bAll, bAll.Length, newHash, newHash.Length); 
                Marshal.ThrowExceptionForHR(hr);
                return newHash;
            }
        } 

        ///////////////////////////////////////////////////////////////////////////// 
        ///////////////////////////////////////////////////////////////////////////// 
        private static byte[] HashDataUsingKeyedAlgorithm(KeyedHashAlgorithm hashAlgo, byte[] buf, byte[] modifier,
                                                          int start, int length, byte[] validationKey) 
        {
            int     totalLength = length + ((modifier != null) ? modifier.Length : 0);
            byte [] bAll        = new byte[totalLength];
 
            Buffer.BlockCopy(buf, start, bAll, 0, length);
            if (modifier != null) { 
                Buffer.BlockCopy(modifier, 0, bAll, length, modifier.Length); 
            }
            hashAlgo.Key = validationKey; 
            return hashAlgo.ComputeHash(bAll);
        }

        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        internal static byte[] GetUnHashedData(byte[] bufHashed) 
        { 
            if (!VerifyHashedData(bufHashed))
                return null; 

            byte[] buf2 = new byte[bufHashed.Length - _HashSize];
            Buffer.BlockCopy(bufHashed, 0, buf2, 0, buf2.Length);
           return buf2; 
        }
 
        ///////////////////////////////////////////////////////////////////////////// 
        /////////////////////////////////////////////////////////////////////////////
        internal static bool VerifyHashedData(byte[] bufHashed) 
        {
            EnsureConfig();

            ////////////////////////////////////////////////////////////////////// 
            // Step 1: Get the MAC: Last 20 bytes
            if (bufHashed.Length <= _HashSize) 
                return false; 

            byte[] bMac = HashData(bufHashed, null, 0, bufHashed.Length - _HashSize); 

            //////////////////////////////////////////////////////////////////////
            // Step 2: Make sure the MAC is correct
            if (bMac == null || bMac.Length != _HashSize) 
                return false;
            int lastPos = bufHashed.Length - _HashSize; 
            for (int iter = 0; iter < _HashSize; iter++) 
                if (bMac[iter] != bufHashed[lastPos + iter])
                    return false; 

            return true;
        }
 
        /////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////// 
        internal static SymmetricAlgorithm GetAESAlgorithm() { 
            //try {
            //    return new AesCng(); 
            //} catch {}

            try {
                return new RijndaelManaged(); 
            } catch { }
 
            return new AesCryptoServiceProvider(); 
        }
        internal static bool UsingCustomEncryption { 
            get {
                EnsureConfig();

                return _UsingCustomEncryption; 
            }
        } 
        private static void InitLegacyEncAlgorithm(byte [] dKey) 
        {
            if (!_UsingCustomEncryption) 
                return;

            s_oSymAlgoLegacy = GetAESAlgorithm();
            try { 
                s_oSymAlgoLegacy.Key = dKey;
            } catch { 
                if (dKey.Length <= 24) 
                    throw;
                byte [] buf = new byte[24]; 
                Buffer.BlockCopy(dKey, 0, buf, 0, buf.Length);
                dKey = buf;
                s_oSymAlgoLegacy.Key = dKey;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK