Utils.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / BCL / System / Security / Cryptography / Utils.cs / 7 / Utils.cs

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

// 
// Utils.cs 
//
// 05/01/2002 
//

namespace System.Security.Cryptography
{ 
    using Microsoft.Win32;
    using System.IO; 
    using System.Globalization; 
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices; 
    using System.Security.AccessControl;
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Permissions;
    using System.Security.Principal; 
    using System.Text;
    using System.Threading; 
    using System.Runtime.Versioning; 

    [Serializable] 
    internal enum CspAlgorithmType {
        Rsa = 0,
        Dss = 1
    } 

    internal static class Constants { 
        internal const int S_OK                   = 0; 
        internal const int NTE_NO_KEY             = unchecked((int) 0x8009000D); // Key does not exist.
        internal const int NTE_BAD_KEYSET         = unchecked((int) 0x80090016); // Keyset does not exist. 
        internal const int NTE_KEYSET_NOT_DEF     = unchecked((int) 0x80090019); // The keyset is not defined.

        internal const int KP_IV                  = 1;
        internal const int KP_MODE                = 4; 
        internal const int KP_MODE_BITS           = 5;
        internal const int KP_EFFECTIVE_KEYLEN    = 19; 
 
        internal const int ALG_CLASS_SIGNATURE    = (1 << 13);
        internal const int ALG_CLASS_DATA_ENCRYPT = (3 << 13); 
        internal const int ALG_CLASS_HASH         = (4 << 13);
        internal const int ALG_CLASS_KEY_EXCHANGE = (5 << 13);

        internal const int ALG_TYPE_DSS           = (1 << 9); 
        internal const int ALG_TYPE_RSA           = (2 << 9);
        internal const int ALG_TYPE_BLOCK         = (3 << 9); 
        internal const int ALG_TYPE_STREAM        = (4 << 9); 
        internal const int ALG_TYPE_ANY           = (0);
 
        internal const int CALG_MD5               = (ALG_CLASS_HASH | ALG_TYPE_ANY | 3);
        internal const int CALG_SHA1              = (ALG_CLASS_HASH | ALG_TYPE_ANY | 4);
        internal const int CALG_SHA_256           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 12);
        internal const int CALG_SHA_384           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 13); 
        internal const int CALG_SHA_512           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 14);
        internal const int CALG_RSA_KEYX          = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | 0); 
        internal const int CALG_RSA_SIGN          = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | 0); 
        internal const int CALG_DSS_SIGN          = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | 0);
        internal const int CALG_DES               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 1); 
        internal const int CALG_RC2               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 2);
        internal const int CALG_3DES              = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 3);
        internal const int CALG_3DES_112          = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 9);
        internal const int CALG_AES_128           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 14); 
        internal const int CALG_AES_192           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 15);
        internal const int CALG_AES_256           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 16); 
        internal const int CALG_RC4               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | 1); 

        internal const int PROV_RSA_FULL          = 1; 
        internal const int PROV_DSS_DH            = 13;
        internal const int PROV_RSA_AES           = 24;

        internal const int AT_KEYEXCHANGE         = 1; 
        internal const int AT_SIGNATURE           = 2;
        internal const int PUBLICKEYBLOB          = 0x6; 
        internal const int PRIVATEKEYBLOB         = 0x7; 
        internal const int CRYPT_OAEP             = 0x40;
 

        internal const uint CRYPT_VERIFYCONTEXT    = 0xF0000000;
        internal const uint CRYPT_NEWKEYSET        = 0x00000008;
        internal const uint CRYPT_DELETEKEYSET     = 0x00000010; 
        internal const uint CRYPT_MACHINE_KEYSET   = 0x00000020;
        internal const uint CRYPT_SILENT           = 0x00000040; 
        internal const uint CRYPT_EXPORTABLE       = 0x00000001; 

        internal const uint CLR_KEYLEN            = 1; 
        internal const uint CLR_PUBLICKEYONLY     = 2;
        internal const uint CLR_EXPORTABLE        = 3;
        internal const uint CLR_REMOVABLE         = 4;
        internal const uint CLR_HARDWARE          = 5; 
        internal const uint CLR_ACCESSIBLE        = 6;
        internal const uint CLR_PROTECTED         = 7; 
        internal const uint CLR_UNIQUE_CONTAINER  = 8; 
        internal const uint CLR_ALGID             = 9;
        internal const uint CLR_PP_CLIENT_HWND    = 10; 
        internal const uint CLR_PP_PIN            = 11;

        internal const string OID_RSA_SMIMEalgCMS3DESwrap   = "1.2.840.113549.1.9.16.3.6";
        internal const string OID_RSA_MD5                   = "1.2.840.113549.2.5"; 
        internal const string OID_RSA_RC2CBC                = "1.2.840.113549.3.2";
        internal const string OID_RSA_DES_EDE3_CBC          = "1.2.840.113549.3.7"; 
        internal const string OID_OIWSEC_desCBC             = "1.3.14.3.2.7"; 
        internal const string OID_OIWSEC_SHA1               = "1.3.14.3.2.26";
        internal const string OID_OIWSEC_SHA256             = "2.16.840.1.101.3.4.2.1"; 
        internal const string OID_OIWSEC_SHA384             = "2.16.840.1.101.3.4.2.2";
        internal const string OID_OIWSEC_SHA512             = "2.16.840.1.101.3.4.2.3";
        internal const string OID_OIWSEC_RIPEMD160          = "1.3.36.3.2.1";
    } 

    internal static class Utils { 
 
        // Private object for locking instead of locking on a public type for SQL reliability work.
        private static Object s_InternalSyncObject; 
        private static Object InternalSyncObject {
            get {
                if (s_InternalSyncObject == null) {
                    Object o = new Object(); 
                    Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
                } 
                return s_InternalSyncObject; 
            }
        } 

        // Provider type to use by default for RSA operations. On systems which support the RSA-AES CSP, we
        // want to use that since it enables access to SHA-2 operations, downlevel we fall back to the
        // RSA-FULL CSP. 
        private static int _defaultRsaProviderType = -1;
        internal static int DefaultRsaProviderType { 
            get { 
                if (_defaultRsaProviderType == -1) {
                    // The AES CSP is only supported on WinXP and higher 
                    bool osSupportsAesCsp = Environment.OSVersion.Version.Major > 5 ||
                                            (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1);
                    _defaultRsaProviderType = osSupportsAesCsp ? Constants.PROV_RSA_AES : Constants.PROV_RSA_FULL;
                } 

                return _defaultRsaProviderType; 
            } 
        }
 
        private static SafeProvHandle _safeProvHandle = null;
        internal static SafeProvHandle StaticProvHandle {
            get {
                if (_safeProvHandle == null) { 
                    lock (InternalSyncObject) {
                        if (_safeProvHandle == null) { 
                            SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(DefaultRsaProviderType)); 
                            Thread.MemoryBarrier();
                            _safeProvHandle = safeProvHandle; 
                        }
                    }
                }
                return _safeProvHandle; 
            }
        } 
 
        private static SafeProvHandle _safeDssProvHandle = null;
        internal static SafeProvHandle StaticDssProvHandle { 
            get {
                if (_safeDssProvHandle == null) {
                    lock (InternalSyncObject) {
                        if (_safeDssProvHandle == null) { 
                            SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(Constants.PROV_DSS_DH));
                            Thread.MemoryBarrier(); 
                            _safeDssProvHandle = safeProvHandle; 
                        }
                    } 
                }
                return _safeDssProvHandle;
            }
        } 

        internal static SafeProvHandle AcquireProvHandle (CspParameters parameters) { 
            if (parameters == null) 
                parameters = new CspParameters(DefaultRsaProviderType);
 
            SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
            if (Utils.Win2KCrypto == 1) {
                Utils._AcquireCSP(parameters, ref safeProvHandle); // CRYPT_VERIFYCONTEXT is only supported in Win2K
            } else { 
                // Using the default key container is a bad idea since this might lead to ----s
                // if multiple threads are trying to access, delete or generate keys inside the container. 
                if (parameters.KeyContainerName == null && 
                    (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer) == 0)
                    parameters.KeyContainerName = _GetRandomKeyContainer(); 
                safeProvHandle = CreateProvHandle(parameters, true);
            }

            return safeProvHandle; 
        }
 
        internal static SafeProvHandle CreateProvHandle (CspParameters parameters, bool randomKeyContainer) { 
            SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
            int hr = Utils._OpenCSP(parameters, 0, ref safeProvHandle); 
            KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
            if (hr != Constants.S_OK) {
                // If UseExistingKey flag is used and the key container does not exist
                // throw an exception without attempting to create the container. 
                if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || (hr != Constants.NTE_KEYSET_NOT_DEF && hr != Constants.NTE_BAD_KEYSET))
                    throw new CryptographicException(hr); 
                if (!randomKeyContainer) { 
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Create);
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();
                }
                Utils._CreateCSP(parameters, randomKeyContainer, ref safeProvHandle);
            } else { 
                if (!randomKeyContainer) {
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open); 
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();
                } 
            }
            return safeProvHandle;
        }
 
        internal static CryptoKeySecurity GetKeySetSecurityInfo (SafeProvHandle hProv, AccessControlSections accessControlSections) {
            if (Utils.Win2KCrypto != 1) 
                throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_RequiresNT")); 

            SecurityInfos securityInfo = 0; 
            Privilege privilege = null;

            if ((accessControlSections & AccessControlSections.Owner) != 0)
                securityInfo |= SecurityInfos.Owner; 
            if ((accessControlSections & AccessControlSections.Group) != 0)
                securityInfo |= SecurityInfos.Group; 
            if ((accessControlSections & AccessControlSections.Access) != 0) 
                securityInfo |= SecurityInfos.DiscretionaryAcl;
 
            byte[] rawSecurityDescriptor = null;
            int error;

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                if ((accessControlSections & AccessControlSections.Audit) != 0) { 
                    securityInfo |= SecurityInfos.SystemAcl; 
                    privilege = new Privilege("SeSecurityPrivilege");
                    privilege.Enable(); 
                }
                rawSecurityDescriptor = _GetKeySetSecurityInfo(hProv, securityInfo, out error);
            }
            finally { 
                if (privilege != null)
                    privilege.Revert(); 
            } 

            // This means that the object doesn't have a security descriptor. And thus we throw 
            // a specific exception for the caller to catch and handle properly.
            if (error == Win32Native.ERROR_SUCCESS && (rawSecurityDescriptor == null || rawSecurityDescriptor.Length == 0))
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoSecurityDescriptor"));
            if (error == Win32Native.ERROR_NOT_ENOUGH_MEMORY) 
                throw new OutOfMemoryException();
            if (error == Win32Native.ERROR_ACCESS_DENIED) 
                throw new UnauthorizedAccessException(); 
            if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD)
                throw new PrivilegeNotHeldException( "SeSecurityPrivilege" ); 
            if (error != Win32Native.ERROR_SUCCESS)
                throw new CryptographicException(error);

            CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false /* isContainer */, 
                                                                       false /* isDS */,
                                                                       new RawSecurityDescriptor(rawSecurityDescriptor, 0), 
                                                                       true); 
            return new CryptoKeySecurity(sd);
        } 

        internal static void SetKeySetSecurityInfo (SafeProvHandle hProv, CryptoKeySecurity cryptoKeySecurity, AccessControlSections accessControlSections) {
            if (Utils.Win2KCrypto != 1)
                throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_RequiresNT")); 

            SecurityInfos securityInfo = 0; 
            Privilege privilege = null; 

            if ((accessControlSections & AccessControlSections.Owner) != 0 && cryptoKeySecurity._securityDescriptor.Owner != null) 
                securityInfo |= SecurityInfos.Owner;
            if ((accessControlSections & AccessControlSections.Group) != 0 && cryptoKeySecurity._securityDescriptor.Group != null)
                securityInfo |= SecurityInfos.Group;
            if ((accessControlSections & AccessControlSections.Audit) != 0) 
                securityInfo |= SecurityInfos.SystemAcl;
            if ((accessControlSections & AccessControlSections.Access) != 0 && cryptoKeySecurity._securityDescriptor.IsDiscretionaryAclPresent) 
                securityInfo |= SecurityInfos.DiscretionaryAcl; 

            if (securityInfo == 0) { 
                // Nothing to persist
                return;
            }
 
            int error = 0;
 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                if ((securityInfo & SecurityInfos.SystemAcl) != 0) { 
                    privilege = new Privilege("SeSecurityPrivilege");
                    privilege.Enable();
                }
 
                byte[] sd = cryptoKeySecurity.GetSecurityDescriptorBinaryForm();
                if (sd != null && sd.Length > 0) 
                    error = _SetKeySetSecurityInfo (hProv, securityInfo, sd); 
            }
            finally { 
                if (privilege != null)
                    privilege.Revert();
            }
 
            if (error == Win32Native.ERROR_ACCESS_DENIED || error == Win32Native.ERROR_INVALID_OWNER || error == Win32Native.ERROR_INVALID_PRIMARY_GROUP)
                throw new UnauthorizedAccessException(); 
            else if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD) 
                throw new PrivilegeNotHeldException("SeSecurityPrivilege");
            else if (error == Win32Native.ERROR_INVALID_HANDLE) 
                throw new NotSupportedException(Environment.GetResourceString("AccessControl_InvalidHandle"));
            else if (error != Win32Native.ERROR_SUCCESS)
                throw new CryptographicException(error);
        } 

        internal static byte[] ExportCspBlobHelper (bool includePrivateParameters, CspParameters parameters, SafeKeyHandle safeKeyHandle) { 
            if (includePrivateParameters) { 
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Export); 
                kp.AccessEntries.Add(entry);
                kp.Demand();
            }
            return Utils._ExportCspBlob(safeKeyHandle, includePrivateParameters ? Constants.PRIVATEKEYBLOB : Constants.PUBLICKEYBLOB); 
        }
 
        internal static void GetKeyPairHelper (CspAlgorithmType keyType, CspParameters parameters, bool randomKeyContainer, int dwKeySize, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) { 
            SafeProvHandle TempFetchedProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
 
            // If the user wanted to set the security descriptor on the provider context, apply it now.
            if (parameters.CryptoKeySecurity != null) {
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.ChangeAcl); 
                kp.AccessEntries.Add(entry);
                kp.Demand(); 
                SetKeySetSecurityInfo(TempFetchedProvHandle, parameters.CryptoKeySecurity, parameters.CryptoKeySecurity.ChangedAccessControlSections); 
            }
 
            // If the user wanted to specify a PIN or HWND for a smart card CSP, apply those settings now.
            if (parameters.ParentWindowHandle != IntPtr.Zero)
                _SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_CLIENT_HWND, parameters.ParentWindowHandle);
            else if (parameters.KeyPassword != null) { 
                IntPtr szPassword = Marshal.SecureStringToCoTaskMemAnsi(parameters.KeyPassword);
                try { 
                    _SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_PIN, szPassword); 
                }
                finally { 
                    if (szPassword != IntPtr.Zero)
                        Marshal.ZeroFreeCoTaskMemAnsi(szPassword);
                }
            } 

            safeProvHandle = TempFetchedProvHandle; 
 
            // If the key already exists, use it, else generate a new one
            SafeKeyHandle TempFetchedKeyHandle = SafeKeyHandle.InvalidHandle; 
            int hr = Utils._GetUserKey(safeProvHandle, parameters.KeyNumber, ref TempFetchedKeyHandle);
            if (hr != Constants.S_OK) {
                if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || hr != Constants.NTE_NO_KEY)
                    throw new CryptographicException(hr); 
                // _GenerateKey will check for failures and throw an exception
                Utils._GenerateKey(safeProvHandle, parameters.KeyNumber, parameters.Flags, dwKeySize, ref TempFetchedKeyHandle); 
            } 

            // check that this is indeed an RSA/DSS key. 
            byte[] algid = (byte[]) Utils._GetKeyParameter(TempFetchedKeyHandle, Constants.CLR_ALGID);
            int dwAlgId = (algid[0] | (algid[1] << 8) | (algid[2] << 16) | (algid[3] << 24));
            if ((keyType == CspAlgorithmType.Rsa && dwAlgId != Constants.CALG_RSA_KEYX && dwAlgId != Constants.CALG_RSA_SIGN) ||
                    (keyType == CspAlgorithmType.Dss && dwAlgId != Constants.CALG_DSS_SIGN)) { 
                TempFetchedKeyHandle.Dispose();
                throw new CryptographicException(Environment.GetResourceString("Cryptography_CSP_WrongKeySpec")); 
            } 

            safeKeyHandle = TempFetchedKeyHandle; 
        }

        internal static void ImportCspBlobHelper (CspAlgorithmType keyType, byte[] keyBlob, bool publicOnly, ref CspParameters parameters, bool randomKeyContainer, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) {
            // Free the current key handle 
            if (safeKeyHandle != null && !safeKeyHandle.IsClosed)
                safeKeyHandle.Dispose(); 
            safeKeyHandle = SafeKeyHandle.InvalidHandle; 

            if (publicOnly) { 
                parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, keyType == CspAlgorithmType.Dss ? Utils.StaticDssProvHandle : Utils.StaticProvHandle, (CspProviderFlags) 0, ref safeKeyHandle);
            } else {
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Import); 
                kp.AccessEntries.Add(entry);
                kp.Demand(); 
                if (safeProvHandle == null) 
                    safeProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
                parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, safeProvHandle, parameters.Flags, ref safeKeyHandle); 
            }
        }

        internal static CspParameters SaveCspParameters (CspAlgorithmType keyType, CspParameters userParameters, CspProviderFlags defaultFlags, ref bool randomKeyContainer) { 
            CspParameters parameters;
            if (userParameters == null) { 
                parameters = new CspParameters(keyType == CspAlgorithmType.Dss ? Constants.PROV_DSS_DH : DefaultRsaProviderType, null, null, defaultFlags); 
            } else {
                ValidateCspFlags(userParameters.Flags); 
                parameters = new CspParameters(userParameters);
            }

            if (parameters.KeyNumber == -1) 
                parameters.KeyNumber = keyType == CspAlgorithmType.Dss ? Constants.AT_SIGNATURE : Constants.AT_KEYEXCHANGE;
            else if (parameters.KeyNumber == Constants.CALG_DSS_SIGN || parameters.KeyNumber == Constants.CALG_RSA_SIGN) 
                parameters.KeyNumber = Constants.AT_SIGNATURE; 
            else if (parameters.KeyNumber == Constants.CALG_RSA_KEYX)
                parameters.KeyNumber = Constants.AT_KEYEXCHANGE; 

            // If no key container was specified and UseDefaultKeyContainer is not used,
            // generate a random key container name
            randomKeyContainer = false; 
            if (parameters.KeyContainerName == null &&
                (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer) == 0) { 
                parameters.KeyContainerName = Utils._GetRandomKeyContainer(); 
                randomKeyContainer = true;
            } 

            return parameters;
        }
 
        private static void ValidateCspFlags (CspProviderFlags flags) {
            // check that the flags are consistent. 
            if ((flags & CspProviderFlags.UseExistingKey) != 0) { 
                CspProviderFlags keyFlags = (CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseArchivableKey | CspProviderFlags.UseUserProtectedKey);
                if ((flags & keyFlags) != CspProviderFlags.NoFlags) 
                    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"));
            }

            // make sure we are allowed to display the key protection UI if a user protected key is requested. 
            if ((flags & CspProviderFlags.UseUserProtectedKey) != 0) {
                // UI only allowed in interactive session. 
                if (!System.Environment.UserInteractive) 
                    throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NotInteractive"));
 
                // we need to demand UI permission here.
                UIPermission uiPermission = new UIPermission(UIPermissionWindow.SafeTopLevelWindows);
                uiPermission.Demand();
            } 
        }
 
        private static RNGCryptoServiceProvider _rng = null; 
        internal static RNGCryptoServiceProvider StaticRandomNumberGenerator {
            get { 
                if (_rng == null)
                    _rng = new RNGCryptoServiceProvider();
                return _rng;
            } 
        }
 
        // 
        // internal static methods
        // 

        internal static byte[] GenerateRandom (int keySize) {
            byte[] key = new byte[keySize];
            StaticRandomNumberGenerator.GetBytes(key); 
            return key;
        } 
 
        // dwKeySize = 0 means the default key size
        internal static bool HasAlgorithm (int dwCalg, int dwKeySize) { 
            bool r = false;
            // We need to take a lock here since we are querying the provider handle in a loop.
            // If multiple threads are racing in this code, not all algorithms/key sizes combinations
            // will be examined; which may lead to a situation where false is wrongfully returned. 
            lock (InternalSyncObject) {
                r = _SearchForAlgorithm(StaticProvHandle, dwCalg, dwKeySize); 
            } 
            return r;
        } 

        private static int s_hasEnhProv = -1;
        internal static int HasEnhProv {
            get { 
                if (s_hasEnhProv == -1)
                    s_hasEnhProv = Utils.HasAlgorithm(Constants.CALG_RSA_KEYX, 2048) ? 1 : 0; 
 
                return s_hasEnhProv;
            } 
        }

        private static int s_fipsAlgorithmPolicy = -1;
        internal static int FipsAlgorithmPolicy { 
            [RegistryPermissionAttribute(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
            get {
                if (s_fipsAlgorithmPolicy == -1) { 
                    if (!_GetEnforceFipsPolicySetting()) {
                        s_fipsAlgorithmPolicy = 0;
                    }
                    else if (Environment.OSVersion.Version.Major >= 6) { 
                        bool fipsEnabled;
                        uint policyReadStatus = Win32Native.BCryptGetFipsAlgorithmMode(out fipsEnabled); 
 
                        bool readPolicy = policyReadStatus == Win32Native.STATUS_SUCCESS ||
                                          policyReadStatus == Win32Native.STATUS_OBJECT_NAME_NOT_FOUND; 

                        if (!readPolicy || fipsEnabled) {
                            s_fipsAlgorithmPolicy = 1;
                        } 
                        else {
                            s_fipsAlgorithmPolicy = 0; 
                        } 
                    }
                    else 
                    {
                        using (RegistryKey fipsAlgorithmPolicyKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa", false)) {
                            if (fipsAlgorithmPolicyKey != null) {
                                object data = fipsAlgorithmPolicyKey.GetValue("FIPSAlgorithmPolicy"); 
                                if (data != null)
                                    s_fipsAlgorithmPolicy = (int) data; 
                            } 
                        }
                    } 
                }
                return s_fipsAlgorithmPolicy;
            }
        } 

        private static int s_win2KCrypto = -1; 
        internal static int Win2KCrypto { 
            get {
                if (s_win2KCrypto == -1) { 
                    // cut-and-paste from Environment.OSVersion so we avoid the demand for EnvironmentPermission.
                    // there's a side effect here that you can do a timing attack on how long it takes to spin up this
                    // function and figure out whether you're pre- or post-Win2K crypto.  But you could do that
                    // anyway by looking at what CSPs are on the system. 
                    Win32Native.OSVERSIONINFO osvi = new Win32Native.OSVERSIONINFO();
                    bool r = Win32Native.GetVersionEx(osvi); 
                    s_win2KCrypto = (r && (osvi.PlatformId == Win32Native.VER_PLATFORM_WIN32_NT) && (osvi.MajorVersion >= 5)) ? 1 : 0; 
                }
                return s_win2KCrypto; 
            }
        }

        internal static string ObjToOidValue (Object hashAlg) { 
            if (hashAlg == null)
                throw new ArgumentNullException("hashAlg"); 
 
            string oidValue = null;
            if (hashAlg is String) { 
                oidValue = CryptoConfig.MapNameToOID((string) hashAlg);
                if (oidValue == null)
                    oidValue = (string) hashAlg; // maybe we were passed the OID value
            } 
            else if (hashAlg is HashAlgorithm) {
                oidValue = CryptoConfig.MapNameToOID(hashAlg.GetType().ToString()); 
            } 
            else if (hashAlg is Type) {
                oidValue = CryptoConfig.MapNameToOID(hashAlg.ToString()); 
            }

            if (oidValue == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue")); 

            return oidValue; 
        } 

        internal static HashAlgorithm ObjToHashAlgorithm (Object hashAlg) { 
            if (hashAlg == null)
                throw new ArgumentNullException("hashAlg");

            HashAlgorithm hash = null; 
            if (hashAlg is String) {
                hash = (HashAlgorithm) CryptoConfig.CreateFromName((string) hashAlg); 
                if (hash == null) { 
                    string oidFriendlyName = X509Utils._GetFriendlyNameFromOid((string) hashAlg);
                    if (oidFriendlyName != null) 
                        hash = (HashAlgorithm) CryptoConfig.CreateFromName(oidFriendlyName);
                }
            }
            else if (hashAlg is HashAlgorithm) { 
                hash = (HashAlgorithm) hashAlg;
            } 
            else if (hashAlg is Type) { 
                hash = (HashAlgorithm) CryptoConfig.CreateFromName(hashAlg.ToString());
            } 

            if (hash == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
 
            return hash;
        } 
 
        internal static String DiscardWhiteSpaces (string inputBuffer) {
            return DiscardWhiteSpaces(inputBuffer, 0, inputBuffer.Length); 
        }

        internal static String DiscardWhiteSpaces (string inputBuffer, int inputOffset, int inputCount) {
            int i, iCount = 0; 
            for (i=0; i 0) {
                BCLDebug.Assert(i < 8, "Got too big an int here!"); 
                t2 = t1 % 256;
                temp[i] = (byte) t2;
                t1 = (t1 - t2)/256;
                i++; 
            }
 
            // Now, copy only the non-zero part of temp and reverse 
            byte[] output = new byte[i];
            // copy and reverse in one pass 
            for (int j = 0; j < i; j++) {
                output[j] = temp[i-j-1];
            }
            return output; 
        }
 
        // output is little endian 
        internal static void ConvertIntToByteArray (uint dwInput, ref byte[] counter) {
            uint t1 = dwInput;  // t1 is remaining value to account for 
            uint t2;  // t2 is t1 % 256
            int i = 0;

            // clear the array first 
            Array.Clear(counter, 0, counter.Length);
            if (dwInput == 0) return; 
            while (t1 > 0) { 
                BCLDebug.Assert(i < 4, "Got too big an int here!");
                t2 = t1 % 256; 
                counter[3 - i] = (byte) t2;
                t1 = (t1 - t2)/256;
                i++;
            } 
        }
 
        internal static byte[] FixupKeyParity (byte[] key) { 
            byte[] oddParityKey = new byte[key.Length];
            for (int index=0; index < key.Length; index++) { 
                // Get the bits we are interested in
                oddParityKey[index] = (byte) (key[index] & 0xfe);
                // Get the parity of the sum of the previous bits
                byte tmp1 = (byte)((oddParityKey[index] & 0xF) ^ (oddParityKey[index] >> 4)); 
                byte tmp2 = (byte)((tmp1 & 0x3) ^ (tmp1 >> 2));
                byte sumBitsMod2 = (byte)((tmp2 & 0x1) ^ (tmp2 >> 1)); 
                // We need to set the last bit in oddParityKey[index] to the negation 
                // of the last bit in sumBitsMod2
                if (sumBitsMod2 == 0) 
                    oddParityKey[index] |= 1;
            }
            return oddParityKey;
        } 

        // digits == number of DWORDs 
        internal unsafe static void DWORDFromLittleEndian (uint* x, int digits, byte* block) { 
            int i;
            int j; 

            for (i = 0, j = 0; i < digits; i++, j += 4)
                x[i] =  (uint) (block[j] | (block[j+1] << 8) | (block[j+2] << 16) | (block[j+3] << 24));
        } 

        // encodes x (DWORD) into block (unsigned char), least significant byte first. 
        // digits == number of DWORDs 
        internal static void DWORDToLittleEndian (byte[] block, uint[] x, int digits) {
            int i; 
            int j;

            for (i = 0, j = 0; i < digits; i++, j += 4) {
                block[j]   = (byte)(x[i] & 0xff); 
                block[j+1] = (byte)((x[i] >> 8) & 0xff);
                block[j+2] = (byte)((x[i] >> 16) & 0xff); 
                block[j+3] = (byte)((x[i] >> 24) & 0xff); 
            }
        } 

        // digits == number of DWORDs
        internal unsafe static void DWORDFromBigEndian (uint* x, int digits, byte* block) {
            int i; 
            int j;
 
            for (i = 0, j = 0; i < digits; i++, j += 4) 
                x[i] = (uint)((block[j] << 24) | (block[j + 1] << 16) | (block[j + 2] << 8) | block[j + 3]);
        } 

        // encodes x (DWORD) into block (unsigned char), most significant byte first.
        // digits == number of DWORDs
        internal static void DWORDToBigEndian (byte[] block, uint[] x, int digits) { 
            int i;
            int j; 
 
            for (i = 0, j = 0; i < digits; i++, j += 4) {
                block[j] = (byte)((x[i] >> 24) & 0xff); 
                block[j+1] = (byte)((x[i] >> 16) & 0xff);
                block[j+2] = (byte)((x[i] >> 8) & 0xff);
                block[j+3] = (byte)(x[i] & 0xff);
            } 
        }
 
        // digits == number of QWORDs 
        internal unsafe static void QuadWordFromBigEndian (UInt64* x, int digits, byte* block) {
            int i; 
            int j;

            for (i = 0, j = 0; i < digits; i++, j += 8)
                x[i] =  ( 
                         (((UInt64)block[j]) << 56) | (((UInt64)block[j+1]) << 48) |
                         (((UInt64)block[j+2]) << 40) | (((UInt64)block[j+3]) << 32) | 
                         (((UInt64)block[j+4]) << 24) | (((UInt64)block[j+5]) << 16) | 
                         (((UInt64)block[j+6]) << 8) | ((UInt64)block[j+7])
                        ); 
        }

        // encodes x (DWORD) into block (unsigned char), most significant byte first.
        // digits = number of QWORDS 
        internal static void QuadWordToBigEndian (byte[] block, UInt64[] x, int digits) {
            int i; 
            int j; 

            for (i = 0, j = 0; i < digits; i++, j += 8) { 
                block[j] = (byte)((x[i] >> 56) & 0xff);
                block[j+1] = (byte)((x[i] >> 48) & 0xff);
                block[j+2] = (byte)((x[i] >> 40) & 0xff);
                block[j+3] = (byte)((x[i] >> 32) & 0xff); 
                block[j+4] = (byte)((x[i] >> 24) & 0xff);
                block[j+5] = (byte)((x[i] >> 16) & 0xff); 
                block[j+6] = (byte)((x[i] >> 8) & 0xff); 
                block[j+7] = (byte)(x[i] & 0xff);
            } 
        }

        // encodes the integer i into a 4-byte array, in big endian.
        internal static byte[] Int(uint i) { 
            byte[] b = BitConverter.GetBytes(i);
            byte[] littleEndianBytes = {b[3], b[2], b[1], b[0]}; 
            return BitConverter.IsLittleEndian ? littleEndianBytes : b; 
        }
 
        internal unsafe static void BlockCopy (byte* src, int srcOffset, byte* dst, int dstOffset, int count) {
            for (int i = 0; i < count; i++) {
                dst[dstOffset + i] = src[srcOffset + i];
            } 
        }
 
        internal unsafe static void BlockCopy (byte[] src, int srcOffset, int* dst, int dstOffset, int count) { 
            fixed (byte* _src = src) {
                BlockCopy(_src, srcOffset, (byte*)dst, dstOffset, count); 
            }
        }

        internal unsafe static void BlockCopy (int* src, int srcOffset, int[] dst, int dstOffset, int count) { 
            fixed (int* _dst = &dst[dstOffset]) {
                BlockCopy((byte*)&src[srcOffset], srcOffset, (byte*)_dst, 0, count); 
            } 
        }
 
        internal static byte[] RsaOaepEncrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, RandomNumberGenerator rng, byte[] data) {
            int cb = rsa.KeySize / 8;

            //  1. Hash the parameters to get PHash 
            int cbHash = hash.HashSize / 8;
            if ((data.Length + 2 + 2*cbHash) > cb) 
                throw new CryptographicException(String.Format(null, Environment.GetResourceString("Cryptography_Padding_EncDataTooBig"), cb-2-2*cbHash)); 
            hash.ComputeHash(new byte[0]); // Use an empty octet string
 
            //  2.  Create DB object
            byte[] DB = new byte[cb - cbHash];

            //  Structure is as follows: 
            //      pHash || PS || 01 || M
            //      PS consists of all zeros 
 
            Buffer.InternalBlockCopy(hash.Hash, 0, DB, 0, cbHash);
            DB[DB.Length - data.Length - 1] = 1; 
            Buffer.InternalBlockCopy(data, 0, DB, DB.Length-data.Length, data.Length);

            // 3. Create a random value of size hLen
            byte[] seed = new byte[cbHash]; 
            rng.GetBytes(seed);
 
            // 4.  Compute the mask value 
            byte[] mask = mgf.GenerateMask(seed, DB.Length);
 
            // 5.  Xor maskDB into DB
            for (int i=0; i < DB.Length; i++) {
                DB[i] = (byte) (DB[i] ^ mask[i]);
            } 

            // 6.  Compute seed mask value 
            mask = mgf.GenerateMask(DB, cbHash); 

            // 7.  Xor mask into seed 
            for (int i=0; i < seed.Length; i++) {
                seed[i] ^= mask[i];
            }
 
            // 8. Concatenate seed and DB to form value to encrypt
            byte[] pad = new byte[cb]; 
            Buffer.InternalBlockCopy(seed, 0, pad, 0, seed.Length); 
            Buffer.InternalBlockCopy(DB, 0, pad, seed.Length, DB.Length);
 
            return rsa.EncryptValue(pad);
        }

        internal static byte[] RsaOaepDecrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, byte[] encryptedData) { 
            int cb = rsa.KeySize / 8;
 
            // 1. Decode the input data 
            // It is important that the Integer to Octet String conversion errors be indistinguishable from the other decoding
            // errors to protect against chosen cipher text attacks 
            // A lecture given by James Manger during Crypto 2001 explains the issue in details
            byte[] data = null;
            try {
                data = rsa.DecryptValue(encryptedData); 
            }
            catch (CryptographicException) { 
                throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding")); 
            }
 
            // 2. Create the hash object so we can get its size info.
            int cbHash = hash.HashSize / 8;

            //  3.  Let maskedSeed be the first hLen octects and maskedDB 
            //      be the remaining bytes.
            int zeros = cb - data.Length; 
            if (zeros < 0 || zeros >= cbHash) 
                throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
 
            byte[] seed = new byte[cbHash];
            Buffer.InternalBlockCopy(data, 0, seed, zeros, seed.Length - zeros);

            byte[] DB = new byte[data.Length - seed.Length + zeros]; 
            Buffer.InternalBlockCopy(data, seed.Length - zeros, DB, 0, DB.Length);
 
            //  4.  seedMask = MGF(maskedDB, hLen); 
            byte[] mask = mgf.GenerateMask(DB, seed.Length);
 
            //  5.  seed = seedMask XOR maskedSeed
            int i = 0;
            for (i=0; i < seed.Length; i++) {
                seed[i] ^= mask[i]; 
            }
 
            //  6.  dbMask = MGF(seed, |EM| - hLen); 
            mask = mgf.GenerateMask(seed, DB.Length);
 
            //  7.  DB = maskedDB xor dbMask
            for (i=0; i < DB.Length; i++) {
                DB[i] = (byte) (DB[i] ^ mask[i]);
            } 

            //  8.  pHash = HASH(P) 
            hash.ComputeHash(new byte[0]); 

            //  9.  DB = pHash' || PS || 01 || M 
            //  10.  Check that pHash = pHash'

            byte[] hashValue = hash.Hash;
            for (i=0; i < cbHash; i++) { 
                if (DB[i] != hashValue[i])
                    throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding")); 
            } 

            //  Check that PS is all zeros 
            for (; i 
            //    NULL (0x05 0x00)  // this is actually an ANY and contains the parameters of the algorithm specified by the OID, I think
            //  } 
            //  OCTET STRING  
            // }
            // 

            // Get the correct prefix
            byte[] data = new byte[oid.Length + 8 + hash.Length];
            data[0] = 0x30; // a structure follows 
            int tmp = data.Length - 2;
            data[1] = (byte) tmp; 
            data[2] = 0x30; 
            tmp = oid.Length + 2;
            data[3] = (byte) tmp; 
            Buffer.InternalBlockCopy(oid, 0, data, 4, oid.Length);
            data[4 + oid.Length] = 0x05;
            data[4 + oid.Length + 1] = 0x00;
            data[4 + oid.Length + 2] = 0x04; // an octet string follows 
            data[4 + oid.Length + 3] = (byte) hash.Length;
            Buffer.InternalBlockCopy(hash, 0, data, oid.Length + 8, hash.Length); 
 
            // Construct the whole array
            int cb1 = cb - data.Length; 
            if (cb1 <= 2)
                throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_InvalidOID"));

            pad[0] = 0; 
            pad[1] = 1;
            for (int i=2; i 5 ||
                                            (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1);
                    _defaultRsaProviderType = osSupportsAesCsp ? Constants.PROV_RSA_AES : Constants.PROV_RSA_FULL;
                } 

                return _defaultRsaProviderType; 
            } 
        }
 
        private static SafeProvHandle _safeProvHandle = null;
        internal static SafeProvHandle StaticProvHandle {
            get {
                if (_safeProvHandle == null) { 
                    lock (InternalSyncObject) {
                        if (_safeProvHandle == null) { 
                            SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(DefaultRsaProviderType)); 
                            Thread.MemoryBarrier();
                            _safeProvHandle = safeProvHandle; 
                        }
                    }
                }
                return _safeProvHandle; 
            }
        } 
 
        private static SafeProvHandle _safeDssProvHandle = null;
        internal static SafeProvHandle StaticDssProvHandle { 
            get {
                if (_safeDssProvHandle == null) {
                    lock (InternalSyncObject) {
                        if (_safeDssProvHandle == null) { 
                            SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(Constants.PROV_DSS_DH));
                            Thread.MemoryBarrier(); 
                            _safeDssProvHandle = safeProvHandle; 
                        }
                    } 
                }
                return _safeDssProvHandle;
            }
        } 

        internal static SafeProvHandle AcquireProvHandle (CspParameters parameters) { 
            if (parameters == null) 
                parameters = new CspParameters(DefaultRsaProviderType);
 
            SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
            if (Utils.Win2KCrypto == 1) {
                Utils._AcquireCSP(parameters, ref safeProvHandle); // CRYPT_VERIFYCONTEXT is only supported in Win2K
            } else { 
                // Using the default key container is a bad idea since this might lead to ----s
                // if multiple threads are trying to access, delete or generate keys inside the container. 
                if (parameters.KeyContainerName == null && 
                    (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer) == 0)
                    parameters.KeyContainerName = _GetRandomKeyContainer(); 
                safeProvHandle = CreateProvHandle(parameters, true);
            }

            return safeProvHandle; 
        }
 
        internal static SafeProvHandle CreateProvHandle (CspParameters parameters, bool randomKeyContainer) { 
            SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
            int hr = Utils._OpenCSP(parameters, 0, ref safeProvHandle); 
            KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
            if (hr != Constants.S_OK) {
                // If UseExistingKey flag is used and the key container does not exist
                // throw an exception without attempting to create the container. 
                if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || (hr != Constants.NTE_KEYSET_NOT_DEF && hr != Constants.NTE_BAD_KEYSET))
                    throw new CryptographicException(hr); 
                if (!randomKeyContainer) { 
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Create);
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();
                }
                Utils._CreateCSP(parameters, randomKeyContainer, ref safeProvHandle);
            } else { 
                if (!randomKeyContainer) {
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open); 
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();
                } 
            }
            return safeProvHandle;
        }
 
        internal static CryptoKeySecurity GetKeySetSecurityInfo (SafeProvHandle hProv, AccessControlSections accessControlSections) {
            if (Utils.Win2KCrypto != 1) 
                throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_RequiresNT")); 

            SecurityInfos securityInfo = 0; 
            Privilege privilege = null;

            if ((accessControlSections & AccessControlSections.Owner) != 0)
                securityInfo |= SecurityInfos.Owner; 
            if ((accessControlSections & AccessControlSections.Group) != 0)
                securityInfo |= SecurityInfos.Group; 
            if ((accessControlSections & AccessControlSections.Access) != 0) 
                securityInfo |= SecurityInfos.DiscretionaryAcl;
 
            byte[] rawSecurityDescriptor = null;
            int error;

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                if ((accessControlSections & AccessControlSections.Audit) != 0) { 
                    securityInfo |= SecurityInfos.SystemAcl; 
                    privilege = new Privilege("SeSecurityPrivilege");
                    privilege.Enable(); 
                }
                rawSecurityDescriptor = _GetKeySetSecurityInfo(hProv, securityInfo, out error);
            }
            finally { 
                if (privilege != null)
                    privilege.Revert(); 
            } 

            // This means that the object doesn't have a security descriptor. And thus we throw 
            // a specific exception for the caller to catch and handle properly.
            if (error == Win32Native.ERROR_SUCCESS && (rawSecurityDescriptor == null || rawSecurityDescriptor.Length == 0))
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoSecurityDescriptor"));
            if (error == Win32Native.ERROR_NOT_ENOUGH_MEMORY) 
                throw new OutOfMemoryException();
            if (error == Win32Native.ERROR_ACCESS_DENIED) 
                throw new UnauthorizedAccessException(); 
            if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD)
                throw new PrivilegeNotHeldException( "SeSecurityPrivilege" ); 
            if (error != Win32Native.ERROR_SUCCESS)
                throw new CryptographicException(error);

            CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false /* isContainer */, 
                                                                       false /* isDS */,
                                                                       new RawSecurityDescriptor(rawSecurityDescriptor, 0), 
                                                                       true); 
            return new CryptoKeySecurity(sd);
        } 

        internal static void SetKeySetSecurityInfo (SafeProvHandle hProv, CryptoKeySecurity cryptoKeySecurity, AccessControlSections accessControlSections) {
            if (Utils.Win2KCrypto != 1)
                throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_RequiresNT")); 

            SecurityInfos securityInfo = 0; 
            Privilege privilege = null; 

            if ((accessControlSections & AccessControlSections.Owner) != 0 && cryptoKeySecurity._securityDescriptor.Owner != null) 
                securityInfo |= SecurityInfos.Owner;
            if ((accessControlSections & AccessControlSections.Group) != 0 && cryptoKeySecurity._securityDescriptor.Group != null)
                securityInfo |= SecurityInfos.Group;
            if ((accessControlSections & AccessControlSections.Audit) != 0) 
                securityInfo |= SecurityInfos.SystemAcl;
            if ((accessControlSections & AccessControlSections.Access) != 0 && cryptoKeySecurity._securityDescriptor.IsDiscretionaryAclPresent) 
                securityInfo |= SecurityInfos.DiscretionaryAcl; 

            if (securityInfo == 0) { 
                // Nothing to persist
                return;
            }
 
            int error = 0;
 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                if ((securityInfo & SecurityInfos.SystemAcl) != 0) { 
                    privilege = new Privilege("SeSecurityPrivilege");
                    privilege.Enable();
                }
 
                byte[] sd = cryptoKeySecurity.GetSecurityDescriptorBinaryForm();
                if (sd != null && sd.Length > 0) 
                    error = _SetKeySetSecurityInfo (hProv, securityInfo, sd); 
            }
            finally { 
                if (privilege != null)
                    privilege.Revert();
            }
 
            if (error == Win32Native.ERROR_ACCESS_DENIED || error == Win32Native.ERROR_INVALID_OWNER || error == Win32Native.ERROR_INVALID_PRIMARY_GROUP)
                throw new UnauthorizedAccessException(); 
            else if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD) 
                throw new PrivilegeNotHeldException("SeSecurityPrivilege");
            else if (error == Win32Native.ERROR_INVALID_HANDLE) 
                throw new NotSupportedException(Environment.GetResourceString("AccessControl_InvalidHandle"));
            else if (error != Win32Native.ERROR_SUCCESS)
                throw new CryptographicException(error);
        } 

        internal static byte[] ExportCspBlobHelper (bool includePrivateParameters, CspParameters parameters, SafeKeyHandle safeKeyHandle) { 
            if (includePrivateParameters) { 
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Export); 
                kp.AccessEntries.Add(entry);
                kp.Demand();
            }
            return Utils._ExportCspBlob(safeKeyHandle, includePrivateParameters ? Constants.PRIVATEKEYBLOB : Constants.PUBLICKEYBLOB); 
        }
 
        internal static void GetKeyPairHelper (CspAlgorithmType keyType, CspParameters parameters, bool randomKeyContainer, int dwKeySize, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) { 
            SafeProvHandle TempFetchedProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
 
            // If the user wanted to set the security descriptor on the provider context, apply it now.
            if (parameters.CryptoKeySecurity != null) {
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.ChangeAcl); 
                kp.AccessEntries.Add(entry);
                kp.Demand(); 
                SetKeySetSecurityInfo(TempFetchedProvHandle, parameters.CryptoKeySecurity, parameters.CryptoKeySecurity.ChangedAccessControlSections); 
            }
 
            // If the user wanted to specify a PIN or HWND for a smart card CSP, apply those settings now.
            if (parameters.ParentWindowHandle != IntPtr.Zero)
                _SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_CLIENT_HWND, parameters.ParentWindowHandle);
            else if (parameters.KeyPassword != null) { 
                IntPtr szPassword = Marshal.SecureStringToCoTaskMemAnsi(parameters.KeyPassword);
                try { 
                    _SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_PIN, szPassword); 
                }
                finally { 
                    if (szPassword != IntPtr.Zero)
                        Marshal.ZeroFreeCoTaskMemAnsi(szPassword);
                }
            } 

            safeProvHandle = TempFetchedProvHandle; 
 
            // If the key already exists, use it, else generate a new one
            SafeKeyHandle TempFetchedKeyHandle = SafeKeyHandle.InvalidHandle; 
            int hr = Utils._GetUserKey(safeProvHandle, parameters.KeyNumber, ref TempFetchedKeyHandle);
            if (hr != Constants.S_OK) {
                if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || hr != Constants.NTE_NO_KEY)
                    throw new CryptographicException(hr); 
                // _GenerateKey will check for failures and throw an exception
                Utils._GenerateKey(safeProvHandle, parameters.KeyNumber, parameters.Flags, dwKeySize, ref TempFetchedKeyHandle); 
            } 

            // check that this is indeed an RSA/DSS key. 
            byte[] algid = (byte[]) Utils._GetKeyParameter(TempFetchedKeyHandle, Constants.CLR_ALGID);
            int dwAlgId = (algid[0] | (algid[1] << 8) | (algid[2] << 16) | (algid[3] << 24));
            if ((keyType == CspAlgorithmType.Rsa && dwAlgId != Constants.CALG_RSA_KEYX && dwAlgId != Constants.CALG_RSA_SIGN) ||
                    (keyType == CspAlgorithmType.Dss && dwAlgId != Constants.CALG_DSS_SIGN)) { 
                TempFetchedKeyHandle.Dispose();
                throw new CryptographicException(Environment.GetResourceString("Cryptography_CSP_WrongKeySpec")); 
            } 

            safeKeyHandle = TempFetchedKeyHandle; 
        }

        internal static void ImportCspBlobHelper (CspAlgorithmType keyType, byte[] keyBlob, bool publicOnly, ref CspParameters parameters, bool randomKeyContainer, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) {
            // Free the current key handle 
            if (safeKeyHandle != null && !safeKeyHandle.IsClosed)
                safeKeyHandle.Dispose(); 
            safeKeyHandle = SafeKeyHandle.InvalidHandle; 

            if (publicOnly) { 
                parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, keyType == CspAlgorithmType.Dss ? Utils.StaticDssProvHandle : Utils.StaticProvHandle, (CspProviderFlags) 0, ref safeKeyHandle);
            } else {
                KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
                KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Import); 
                kp.AccessEntries.Add(entry);
                kp.Demand(); 
                if (safeProvHandle == null) 
                    safeProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
                parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, safeProvHandle, parameters.Flags, ref safeKeyHandle); 
            }
        }

        internal static CspParameters SaveCspParameters (CspAlgorithmType keyType, CspParameters userParameters, CspProviderFlags defaultFlags, ref bool randomKeyContainer) { 
            CspParameters parameters;
            if (userParameters == null) { 
                parameters = new CspParameters(keyType == CspAlgorithmType.Dss ? Constants.PROV_DSS_DH : DefaultRsaProviderType, null, null, defaultFlags); 
            } else {
                ValidateCspFlags(userParameters.Flags); 
                parameters = new CspParameters(userParameters);
            }

            if (parameters.KeyNumber == -1) 
                parameters.KeyNumber = keyType == CspAlgorithmType.Dss ? Constants.AT_SIGNATURE : Constants.AT_KEYEXCHANGE;
            else if (parameters.KeyNumber == Constants.CALG_DSS_SIGN || parameters.KeyNumber == Constants.CALG_RSA_SIGN) 
                parameters.KeyNumber = Constants.AT_SIGNATURE; 
            else if (parameters.KeyNumber == Constants.CALG_RSA_KEYX)
                parameters.KeyNumber = Constants.AT_KEYEXCHANGE; 

            // If no key container was specified and UseDefaultKeyContainer is not used,
            // generate a random key container name
            randomKeyContainer = false; 
            if (parameters.KeyContainerName == null &&
                (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer) == 0) { 
                parameters.KeyContainerName = Utils._GetRandomKeyContainer(); 
                randomKeyContainer = true;
            } 

            return parameters;
        }
 
        private static void ValidateCspFlags (CspProviderFlags flags) {
            // check that the flags are consistent. 
            if ((flags & CspProviderFlags.UseExistingKey) != 0) { 
                CspProviderFlags keyFlags = (CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseArchivableKey | CspProviderFlags.UseUserProtectedKey);
                if ((flags & keyFlags) != CspProviderFlags.NoFlags) 
                    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"));
            }

            // make sure we are allowed to display the key protection UI if a user protected key is requested. 
            if ((flags & CspProviderFlags.UseUserProtectedKey) != 0) {
                // UI only allowed in interactive session. 
                if (!System.Environment.UserInteractive) 
                    throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NotInteractive"));
 
                // we need to demand UI permission here.
                UIPermission uiPermission = new UIPermission(UIPermissionWindow.SafeTopLevelWindows);
                uiPermission.Demand();
            } 
        }
 
        private static RNGCryptoServiceProvider _rng = null; 
        internal static RNGCryptoServiceProvider StaticRandomNumberGenerator {
            get { 
                if (_rng == null)
                    _rng = new RNGCryptoServiceProvider();
                return _rng;
            } 
        }
 
        // 
        // internal static methods
        // 

        internal static byte[] GenerateRandom (int keySize) {
            byte[] key = new byte[keySize];
            StaticRandomNumberGenerator.GetBytes(key); 
            return key;
        } 
 
        // dwKeySize = 0 means the default key size
        internal static bool HasAlgorithm (int dwCalg, int dwKeySize) { 
            bool r = false;
            // We need to take a lock here since we are querying the provider handle in a loop.
            // If multiple threads are racing in this code, not all algorithms/key sizes combinations
            // will be examined; which may lead to a situation where false is wrongfully returned. 
            lock (InternalSyncObject) {
                r = _SearchForAlgorithm(StaticProvHandle, dwCalg, dwKeySize); 
            } 
            return r;
        } 

        private static int s_hasEnhProv = -1;
        internal static int HasEnhProv {
            get { 
                if (s_hasEnhProv == -1)
                    s_hasEnhProv = Utils.HasAlgorithm(Constants.CALG_RSA_KEYX, 2048) ? 1 : 0; 
 
                return s_hasEnhProv;
            } 
        }

        private static int s_fipsAlgorithmPolicy = -1;
        internal static int FipsAlgorithmPolicy { 
            [RegistryPermissionAttribute(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
            get {
                if (s_fipsAlgorithmPolicy == -1) { 
                    if (!_GetEnforceFipsPolicySetting()) {
                        s_fipsAlgorithmPolicy = 0;
                    }
                    else if (Environment.OSVersion.Version.Major >= 6) { 
                        bool fipsEnabled;
                        uint policyReadStatus = Win32Native.BCryptGetFipsAlgorithmMode(out fipsEnabled); 
 
                        bool readPolicy = policyReadStatus == Win32Native.STATUS_SUCCESS ||
                                          policyReadStatus == Win32Native.STATUS_OBJECT_NAME_NOT_FOUND; 

                        if (!readPolicy || fipsEnabled) {
                            s_fipsAlgorithmPolicy = 1;
                        } 
                        else {
                            s_fipsAlgorithmPolicy = 0; 
                        } 
                    }
                    else 
                    {
                        using (RegistryKey fipsAlgorithmPolicyKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa", false)) {
                            if (fipsAlgorithmPolicyKey != null) {
                                object data = fipsAlgorithmPolicyKey.GetValue("FIPSAlgorithmPolicy"); 
                                if (data != null)
                                    s_fipsAlgorithmPolicy = (int) data; 
                            } 
                        }
                    } 
                }
                return s_fipsAlgorithmPolicy;
            }
        } 

        private static int s_win2KCrypto = -1; 
        internal static int Win2KCrypto { 
            get {
                if (s_win2KCrypto == -1) { 
                    // cut-and-paste from Environment.OSVersion so we avoid the demand for EnvironmentPermission.
                    // there's a side effect here that you can do a timing attack on how long it takes to spin up this
                    // function and figure out whether you're pre- or post-Win2K crypto.  But you could do that
                    // anyway by looking at what CSPs are on the system. 
                    Win32Native.OSVERSIONINFO osvi = new Win32Native.OSVERSIONINFO();
                    bool r = Win32Native.GetVersionEx(osvi); 
                    s_win2KCrypto = (r && (osvi.PlatformId == Win32Native.VER_PLATFORM_WIN32_NT) && (osvi.MajorVersion >= 5)) ? 1 : 0; 
                }
                return s_win2KCrypto; 
            }
        }

        internal static string ObjToOidValue (Object hashAlg) { 
            if (hashAlg == null)
                throw new ArgumentNullException("hashAlg"); 
 
            string oidValue = null;
            if (hashAlg is String) { 
                oidValue = CryptoConfig.MapNameToOID((string) hashAlg);
                if (oidValue == null)
                    oidValue = (string) hashAlg; // maybe we were passed the OID value
            } 
            else if (hashAlg is HashAlgorithm) {
                oidValue = CryptoConfig.MapNameToOID(hashAlg.GetType().ToString()); 
            } 
            else if (hashAlg is Type) {
                oidValue = CryptoConfig.MapNameToOID(hashAlg.ToString()); 
            }

            if (oidValue == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue")); 

            return oidValue; 
        } 

        internal static HashAlgorithm ObjToHashAlgorithm (Object hashAlg) { 
            if (hashAlg == null)
                throw new ArgumentNullException("hashAlg");

            HashAlgorithm hash = null; 
            if (hashAlg is String) {
                hash = (HashAlgorithm) CryptoConfig.CreateFromName((string) hashAlg); 
                if (hash == null) { 
                    string oidFriendlyName = X509Utils._GetFriendlyNameFromOid((string) hashAlg);
                    if (oidFriendlyName != null) 
                        hash = (HashAlgorithm) CryptoConfig.CreateFromName(oidFriendlyName);
                }
            }
            else if (hashAlg is HashAlgorithm) { 
                hash = (HashAlgorithm) hashAlg;
            } 
            else if (hashAlg is Type) { 
                hash = (HashAlgorithm) CryptoConfig.CreateFromName(hashAlg.ToString());
            } 

            if (hash == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
 
            return hash;
        } 
 
        internal static String DiscardWhiteSpaces (string inputBuffer) {
            return DiscardWhiteSpaces(inputBuffer, 0, inputBuffer.Length); 
        }

        internal static String DiscardWhiteSpaces (string inputBuffer, int inputOffset, int inputCount) {
            int i, iCount = 0; 
            for (i=0; i 0) {
                BCLDebug.Assert(i < 8, "Got too big an int here!"); 
                t2 = t1 % 256;
                temp[i] = (byte) t2;
                t1 = (t1 - t2)/256;
                i++; 
            }
 
            // Now, copy only the non-zero part of temp and reverse 
            byte[] output = new byte[i];
            // copy and reverse in one pass 
            for (int j = 0; j < i; j++) {
                output[j] = temp[i-j-1];
            }
            return output; 
        }
 
        // output is little endian 
        internal static void ConvertIntToByteArray (uint dwInput, ref byte[] counter) {
            uint t1 = dwInput;  // t1 is remaining value to account for 
            uint t2;  // t2 is t1 % 256
            int i = 0;

            // clear the array first 
            Array.Clear(counter, 0, counter.Length);
            if (dwInput == 0) return; 
            while (t1 > 0) { 
                BCLDebug.Assert(i < 4, "Got too big an int here!");
                t2 = t1 % 256; 
                counter[3 - i] = (byte) t2;
                t1 = (t1 - t2)/256;
                i++;
            } 
        }
 
        internal static byte[] FixupKeyParity (byte[] key) { 
            byte[] oddParityKey = new byte[key.Length];
            for (int index=0; index < key.Length; index++) { 
                // Get the bits we are interested in
                oddParityKey[index] = (byte) (key[index] & 0xfe);
                // Get the parity of the sum of the previous bits
                byte tmp1 = (byte)((oddParityKey[index] & 0xF) ^ (oddParityKey[index] >> 4)); 
                byte tmp2 = (byte)((tmp1 & 0x3) ^ (tmp1 >> 2));
                byte sumBitsMod2 = (byte)((tmp2 & 0x1) ^ (tmp2 >> 1)); 
                // We need to set the last bit in oddParityKey[index] to the negation 
                // of the last bit in sumBitsMod2
                if (sumBitsMod2 == 0) 
                    oddParityKey[index] |= 1;
            }
            return oddParityKey;
        } 

        // digits == number of DWORDs 
        internal unsafe static void DWORDFromLittleEndian (uint* x, int digits, byte* block) { 
            int i;
            int j; 

            for (i = 0, j = 0; i < digits; i++, j += 4)
                x[i] =  (uint) (block[j] | (block[j+1] << 8) | (block[j+2] << 16) | (block[j+3] << 24));
        } 

        // encodes x (DWORD) into block (unsigned char), least significant byte first. 
        // digits == number of DWORDs 
        internal static void DWORDToLittleEndian (byte[] block, uint[] x, int digits) {
            int i; 
            int j;

            for (i = 0, j = 0; i < digits; i++, j += 4) {
                block[j]   = (byte)(x[i] & 0xff); 
                block[j+1] = (byte)((x[i] >> 8) & 0xff);
                block[j+2] = (byte)((x[i] >> 16) & 0xff); 
                block[j+3] = (byte)((x[i] >> 24) & 0xff); 
            }
        } 

        // digits == number of DWORDs
        internal unsafe static void DWORDFromBigEndian (uint* x, int digits, byte* block) {
            int i; 
            int j;
 
            for (i = 0, j = 0; i < digits; i++, j += 4) 
                x[i] = (uint)((block[j] << 24) | (block[j + 1] << 16) | (block[j + 2] << 8) | block[j + 3]);
        } 

        // encodes x (DWORD) into block (unsigned char), most significant byte first.
        // digits == number of DWORDs
        internal static void DWORDToBigEndian (byte[] block, uint[] x, int digits) { 
            int i;
            int j; 
 
            for (i = 0, j = 0; i < digits; i++, j += 4) {
                block[j] = (byte)((x[i] >> 24) & 0xff); 
                block[j+1] = (byte)((x[i] >> 16) & 0xff);
                block[j+2] = (byte)((x[i] >> 8) & 0xff);
                block[j+3] = (byte)(x[i] & 0xff);
            } 
        }
 
        // digits == number of QWORDs 
        internal unsafe static void QuadWordFromBigEndian (UInt64* x, int digits, byte* block) {
            int i; 
            int j;

            for (i = 0, j = 0; i < digits; i++, j += 8)
                x[i] =  ( 
                         (((UInt64)block[j]) << 56) | (((UInt64)block[j+1]) << 48) |
                         (((UInt64)block[j+2]) << 40) | (((UInt64)block[j+3]) << 32) | 
                         (((UInt64)block[j+4]) << 24) | (((UInt64)block[j+5]) << 16) | 
                         (((UInt64)block[j+6]) << 8) | ((UInt64)block[j+7])
                        ); 
        }

        // encodes x (DWORD) into block (unsigned char), most significant byte first.
        // digits = number of QWORDS 
        internal static void QuadWordToBigEndian (byte[] block, UInt64[] x, int digits) {
            int i; 
            int j; 

            for (i = 0, j = 0; i < digits; i++, j += 8) { 
                block[j] = (byte)((x[i] >> 56) & 0xff);
                block[j+1] = (byte)((x[i] >> 48) & 0xff);
                block[j+2] = (byte)((x[i] >> 40) & 0xff);
                block[j+3] = (byte)((x[i] >> 32) & 0xff); 
                block[j+4] = (byte)((x[i] >> 24) & 0xff);
                block[j+5] = (byte)((x[i] >> 16) & 0xff); 
                block[j+6] = (byte)((x[i] >> 8) & 0xff); 
                block[j+7] = (byte)(x[i] & 0xff);
            } 
        }

        // encodes the integer i into a 4-byte array, in big endian.
        internal static byte[] Int(uint i) { 
            byte[] b = BitConverter.GetBytes(i);
            byte[] littleEndianBytes = {b[3], b[2], b[1], b[0]}; 
            return BitConverter.IsLittleEndian ? littleEndianBytes : b; 
        }
 
        internal unsafe static void BlockCopy (byte* src, int srcOffset, byte* dst, int dstOffset, int count) {
            for (int i = 0; i < count; i++) {
                dst[dstOffset + i] = src[srcOffset + i];
            } 
        }
 
        internal unsafe static void BlockCopy (byte[] src, int srcOffset, int* dst, int dstOffset, int count) { 
            fixed (byte* _src = src) {
                BlockCopy(_src, srcOffset, (byte*)dst, dstOffset, count); 
            }
        }

        internal unsafe static void BlockCopy (int* src, int srcOffset, int[] dst, int dstOffset, int count) { 
            fixed (int* _dst = &dst[dstOffset]) {
                BlockCopy((byte*)&src[srcOffset], srcOffset, (byte*)_dst, 0, count); 
            } 
        }
 
        internal static byte[] RsaOaepEncrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, RandomNumberGenerator rng, byte[] data) {
            int cb = rsa.KeySize / 8;

            //  1. Hash the parameters to get PHash 
            int cbHash = hash.HashSize / 8;
            if ((data.Length + 2 + 2*cbHash) > cb) 
                throw new CryptographicException(String.Format(null, Environment.GetResourceString("Cryptography_Padding_EncDataTooBig"), cb-2-2*cbHash)); 
            hash.ComputeHash(new byte[0]); // Use an empty octet string
 
            //  2.  Create DB object
            byte[] DB = new byte[cb - cbHash];

            //  Structure is as follows: 
            //      pHash || PS || 01 || M
            //      PS consists of all zeros 
 
            Buffer.InternalBlockCopy(hash.Hash, 0, DB, 0, cbHash);
            DB[DB.Length - data.Length - 1] = 1; 
            Buffer.InternalBlockCopy(data, 0, DB, DB.Length-data.Length, data.Length);

            // 3. Create a random value of size hLen
            byte[] seed = new byte[cbHash]; 
            rng.GetBytes(seed);
 
            // 4.  Compute the mask value 
            byte[] mask = mgf.GenerateMask(seed, DB.Length);
 
            // 5.  Xor maskDB into DB
            for (int i=0; i < DB.Length; i++) {
                DB[i] = (byte) (DB[i] ^ mask[i]);
            } 

            // 6.  Compute seed mask value 
            mask = mgf.GenerateMask(DB, cbHash); 

            // 7.  Xor mask into seed 
            for (int i=0; i < seed.Length; i++) {
                seed[i] ^= mask[i];
            }
 
            // 8. Concatenate seed and DB to form value to encrypt
            byte[] pad = new byte[cb]; 
            Buffer.InternalBlockCopy(seed, 0, pad, 0, seed.Length); 
            Buffer.InternalBlockCopy(DB, 0, pad, seed.Length, DB.Length);
 
            return rsa.EncryptValue(pad);
        }

        internal static byte[] RsaOaepDecrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, byte[] encryptedData) { 
            int cb = rsa.KeySize / 8;
 
            // 1. Decode the input data 
            // It is important that the Integer to Octet String conversion errors be indistinguishable from the other decoding
            // errors to protect against chosen cipher text attacks 
            // A lecture given by James Manger during Crypto 2001 explains the issue in details
            byte[] data = null;
            try {
                data = rsa.DecryptValue(encryptedData); 
            }
            catch (CryptographicException) { 
                throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding")); 
            }
 
            // 2. Create the hash object so we can get its size info.
            int cbHash = hash.HashSize / 8;

            //  3.  Let maskedSeed be the first hLen octects and maskedDB 
            //      be the remaining bytes.
            int zeros = cb - data.Length; 
            if (zeros < 0 || zeros >= cbHash) 
                throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
 
            byte[] seed = new byte[cbHash];
            Buffer.InternalBlockCopy(data, 0, seed, zeros, seed.Length - zeros);

            byte[] DB = new byte[data.Length - seed.Length + zeros]; 
            Buffer.InternalBlockCopy(data, seed.Length - zeros, DB, 0, DB.Length);
 
            //  4.  seedMask = MGF(maskedDB, hLen); 
            byte[] mask = mgf.GenerateMask(DB, seed.Length);
 
            //  5.  seed = seedMask XOR maskedSeed
            int i = 0;
            for (i=0; i < seed.Length; i++) {
                seed[i] ^= mask[i]; 
            }
 
            //  6.  dbMask = MGF(seed, |EM| - hLen); 
            mask = mgf.GenerateMask(seed, DB.Length);
 
            //  7.  DB = maskedDB xor dbMask
            for (i=0; i < DB.Length; i++) {
                DB[i] = (byte) (DB[i] ^ mask[i]);
            } 

            //  8.  pHash = HASH(P) 
            hash.ComputeHash(new byte[0]); 

            //  9.  DB = pHash' || PS || 01 || M 
            //  10.  Check that pHash = pHash'

            byte[] hashValue = hash.Hash;
            for (i=0; i < cbHash; i++) { 
                if (DB[i] != hashValue[i])
                    throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding")); 
            } 

            //  Check that PS is all zeros 
            for (; i 
            //    NULL (0x05 0x00)  // this is actually an ANY and contains the parameters of the algorithm specified by the OID, I think
            //  } 
            //  OCTET STRING  
            // }
            // 

            // Get the correct prefix
            byte[] data = new byte[oid.Length + 8 + hash.Length];
            data[0] = 0x30; // a structure follows 
            int tmp = data.Length - 2;
            data[1] = (byte) tmp; 
            data[2] = 0x30; 
            tmp = oid.Length + 2;
            data[3] = (byte) tmp; 
            Buffer.InternalBlockCopy(oid, 0, data, 4, oid.Length);
            data[4 + oid.Length] = 0x05;
            data[4 + oid.Length + 1] = 0x00;
            data[4 + oid.Length + 2] = 0x04; // an octet string follows 
            data[4 + oid.Length + 3] = (byte) hash.Length;
            Buffer.InternalBlockCopy(hash, 0, data, oid.Length + 8, hash.Length); 
 
            // Construct the whole array
            int cb1 = cb - data.Length; 
            if (cb1 <= 2)
                throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_InvalidOID"));

            pad[0] = 0; 
            pad[1] = 1;
            for (int i=2; i

                        

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