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; i0) { 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DescendantBaseQuery.cs
- WebPartDisplayModeCancelEventArgs.cs
- UIElementPropertyUndoUnit.cs
- Hash.cs
- BitmapFrameEncode.cs
- SchemaObjectWriter.cs
- Trace.cs
- InputGestureCollection.cs
- ReadContentAsBinaryHelper.cs
- WebServiceFaultDesigner.cs
- Size.cs
- LexicalChunk.cs
- SubtreeProcessor.cs
- DateTimeParse.cs
- ConfigXmlSignificantWhitespace.cs
- DataControlLinkButton.cs
- XmlCompatibilityReader.cs
- SqlGatherProducedAliases.cs
- Transform.cs
- Canvas.cs
- ResXDataNode.cs
- Timer.cs
- ComponentResourceKeyConverter.cs
- LazyTextWriterCreator.cs
- PolyLineSegment.cs
- CreateInstanceBinder.cs
- HostProtectionPermission.cs
- KeyTimeConverter.cs
- CodeAttributeDeclarationCollection.cs
- ToolStripGripRenderEventArgs.cs
- DetailsViewRowCollection.cs
- DummyDataSource.cs
- Tag.cs
- WeakEventManager.cs
- StructuralType.cs
- ObjectDataSourceFilteringEventArgs.cs
- CodeCompileUnit.cs
- CurrentChangingEventManager.cs
- HScrollProperties.cs
- UserPreferenceChangedEventArgs.cs
- MetadataPropertyCollection.cs
- ContentElement.cs
- NegationPusher.cs
- assertwrapper.cs
- Menu.cs
- EntityDataSourceConfigureObjectContext.cs
- XamlFilter.cs
- safex509handles.cs
- OAVariantLib.cs
- OrderedDictionary.cs
- ScriptHandlerFactory.cs
- ForeignConstraint.cs
- DiffuseMaterial.cs
- ThreadAbortException.cs
- ArrayElementGridEntry.cs
- ValueChangedEventManager.cs
- LongValidatorAttribute.cs
- WorkflowApplicationException.cs
- SqlNodeTypeOperators.cs
- AttributeEmitter.cs
- StylusEditingBehavior.cs
- BookmarkResumptionRecord.cs
- DataObjectAttribute.cs
- SystemInformation.cs
- OdbcConnectionFactory.cs
- Journal.cs
- CallContext.cs
- PromptStyle.cs
- EntityTypeBase.cs
- LockingPersistenceProvider.cs
- TaskHelper.cs
- coordinatorfactory.cs
- MobileSysDescriptionAttribute.cs
- _ConnectOverlappedAsyncResult.cs
- XamlStackWriter.cs
- IteratorFilter.cs
- SymLanguageVendor.cs
- XPathBinder.cs
- ToolboxComponentsCreatingEventArgs.cs
- ScriptControl.cs
- SQLInt16.cs
- StoryFragments.cs
- AnnotationAdorner.cs
- PointLight.cs
- HtmlInputSubmit.cs
- ThumbAutomationPeer.cs
- ObjectRef.cs
- EntityDataSourceQueryBuilder.cs
- XmlSchemaAttributeGroup.cs
- HashCodeCombiner.cs
- UnsafeNativeMethods.cs
- TabControl.cs
- LogoValidationException.cs
- XmlILAnnotation.cs
- DashStyle.cs
- SchemaReference.cs
- SurrogateEncoder.cs
- Vector3DAnimation.cs
- TextServicesCompartment.cs
- SettingsSavedEventArgs.cs