Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / utils.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 //
10 // Utils.cs
11 //
12 // 05/01/2002
13 //
14
15 namespace System.Security.Cryptography
16 {
17     using Microsoft.Win32;
18     using System.IO;
19     using System.Reflection;
20     using System.Globalization;
21     using System.Runtime.CompilerServices;
22     using System.Runtime.InteropServices;
23 #if FEATURE_MACL
24     using System.Security.AccessControl;
25 #endif // FEATURE_MACL
26     using System.Security.Cryptography.X509Certificates;
27     using System.Security.Permissions;
28 #if FEATURE_IMPERSONATION
29     using System.Security.Principal;
30 #endif // FEATURE_IMPERSONATION
31     using System.Text;
32     using System.Threading;
33     using System.Diagnostics.Contracts;
34     using System.Runtime.Versioning;
35
36 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
37     [Serializable]
38     internal enum CspAlgorithmType {
39         Rsa = 0,
40         Dss = 1
41     }
42 #elif SILVERLIGHT
43     internal enum CspAlgorithmType {
44         Rsa = 0,
45         Dss = 1
46     }
47 #endif
48
49     internal static class Constants {
50 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
51         internal const int S_OK                   = 0;
52         internal const int NTE_FILENOTFOUND       = unchecked((int) 0x80070002); // The system cannot find the file specified.
53         internal const int NTE_NO_KEY             = unchecked((int) 0x8009000D); // Key does not exist.
54         internal const int NTE_BAD_KEYSET         = unchecked((int) 0x80090016); // Keyset does not exist.
55         internal const int NTE_KEYSET_NOT_DEF     = unchecked((int) 0x80090019); // The keyset is not defined.
56
57         internal const int KP_IV                  = 1;
58         internal const int KP_MODE                = 4;
59         internal const int KP_MODE_BITS           = 5;
60         internal const int KP_EFFECTIVE_KEYLEN    = 19;
61
62         internal const int ALG_CLASS_SIGNATURE    = (1 << 13);
63         internal const int ALG_CLASS_DATA_ENCRYPT = (3 << 13);
64         internal const int ALG_CLASS_HASH         = (4 << 13);
65         internal const int ALG_CLASS_KEY_EXCHANGE = (5 << 13);
66
67         internal const int ALG_TYPE_DSS           = (1 << 9);
68         internal const int ALG_TYPE_RSA           = (2 << 9);
69         internal const int ALG_TYPE_BLOCK         = (3 << 9);
70         internal const int ALG_TYPE_STREAM        = (4 << 9);
71         internal const int ALG_TYPE_ANY           = (0);
72
73         internal const int CALG_MD5               = (ALG_CLASS_HASH | ALG_TYPE_ANY | 3);
74         internal const int CALG_SHA1              = (ALG_CLASS_HASH | ALG_TYPE_ANY | 4);
75         internal const int CALG_SHA_256           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 12);
76         internal const int CALG_SHA_384           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 13);
77         internal const int CALG_SHA_512           = (ALG_CLASS_HASH | ALG_TYPE_ANY | 14);
78         internal const int CALG_RSA_KEYX          = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | 0); 
79         internal const int CALG_RSA_SIGN          = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | 0);
80         internal const int CALG_DSS_SIGN          = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | 0);
81         internal const int CALG_DES               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 1);
82         internal const int CALG_RC2               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 2);
83         internal const int CALG_3DES              = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 3);
84         internal const int CALG_3DES_112          = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 9);
85         internal const int CALG_AES_128           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 14);
86         internal const int CALG_AES_192           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 15);
87         internal const int CALG_AES_256           = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | 16);
88         internal const int CALG_RC4               = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | 1);
89 #endif // FEATURE_CRYPTO
90
91         internal const int PROV_RSA_FULL          = 1;
92         internal const int PROV_DSS_DH            = 13;
93         internal const int PROV_RSA_AES           = 24;
94
95 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
96         internal const int AT_KEYEXCHANGE         = 1;
97 #endif // FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
98         internal const int AT_SIGNATURE           = 2;
99 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
100         internal const int PUBLICKEYBLOB          = 0x6;
101         internal const int PRIVATEKEYBLOB         = 0x7;
102         internal const int CRYPT_OAEP             = 0x40;
103
104
105         internal const uint CRYPT_VERIFYCONTEXT    = 0xF0000000;
106         internal const uint CRYPT_NEWKEYSET        = 0x00000008;
107         internal const uint CRYPT_DELETEKEYSET     = 0x00000010;
108         internal const uint CRYPT_MACHINE_KEYSET   = 0x00000020;
109         internal const uint CRYPT_SILENT           = 0x00000040;
110         internal const uint CRYPT_EXPORTABLE       = 0x00000001;
111
112         internal const uint CLR_KEYLEN            = 1;
113         internal const uint CLR_PUBLICKEYONLY     = 2;
114         internal const uint CLR_EXPORTABLE        = 3;
115         internal const uint CLR_REMOVABLE         = 4;
116         internal const uint CLR_HARDWARE          = 5;
117         internal const uint CLR_ACCESSIBLE        = 6;
118         internal const uint CLR_PROTECTED         = 7;
119         internal const uint CLR_UNIQUE_CONTAINER  = 8;
120         internal const uint CLR_ALGID             = 9;
121         internal const uint CLR_PP_CLIENT_HWND    = 10;
122         internal const uint CLR_PP_PIN            = 11;
123
124         internal const string OID_RSA_SMIMEalgCMS3DESwrap   = "1.2.840.113549.1.9.16.3.6";
125         internal const string OID_RSA_MD5                   = "1.2.840.113549.2.5";
126         internal const string OID_RSA_RC2CBC                = "1.2.840.113549.3.2";
127         internal const string OID_RSA_DES_EDE3_CBC          = "1.2.840.113549.3.7";
128         internal const string OID_OIWSEC_desCBC             = "1.3.14.3.2.7";
129         internal const string OID_OIWSEC_SHA1               = "1.3.14.3.2.26";
130         internal const string OID_OIWSEC_SHA256             = "2.16.840.1.101.3.4.2.1";
131         internal const string OID_OIWSEC_SHA384             = "2.16.840.1.101.3.4.2.2";
132         internal const string OID_OIWSEC_SHA512             = "2.16.840.1.101.3.4.2.3";
133         internal const string OID_OIWSEC_RIPEMD160          = "1.3.36.3.2.1";
134 #endif // FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
135     }
136
137     internal static class Utils {
138
139 #if !FEATURE_PAL && FEATURE_CRYPTO
140         [SecuritySafeCritical]
141 #endif
142         static Utils()
143         {
144         }
145
146 #if MONO
147         // The default provider value must remain '1' for Mono, otherwise we won't be able
148         // to locate keypairs that were serialized by Mono versions 4.0 and lower.
149         // (The ProviderType property in the CspParameters class affects serialization)
150         internal const int DefaultRsaProviderType = 1;
151 #else
152         // Provider type to use by default for RSA operations. We want to use RSA-AES CSP
153         // since it enables access to SHA-2 operations. All currently supported OSes support RSA-AES.
154         internal const int DefaultRsaProviderType = Constants.PROV_RSA_AES;
155 #endif
156
157 #if !MONO
158 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
159         // Private object for locking instead of locking on a public type for SQL reliability work.
160         private static Object s_InternalSyncObject = new Object();
161
162         private static Object InternalSyncObject {
163             get { return s_InternalSyncObject; }
164         }
165
166         [System.Security.SecurityCritical] // auto-generated
167         private static volatile SafeProvHandle _safeProvHandle;
168         internal static SafeProvHandle StaticProvHandle {
169             [System.Security.SecurityCritical]  // auto-generated
170             get {
171                 if (_safeProvHandle == null) {
172                     lock (InternalSyncObject) {
173                         if (_safeProvHandle == null) {
174                             _safeProvHandle = AcquireProvHandle(new CspParameters(DefaultRsaProviderType));
175                         }
176                     }
177                 }
178                 return _safeProvHandle;
179             }
180         }
181
182         [System.Security.SecurityCritical] // auto-generated
183         private static volatile SafeProvHandle _safeDssProvHandle;
184         internal static SafeProvHandle StaticDssProvHandle {
185             [System.Security.SecurityCritical]  // auto-generated
186             get {
187                 if (_safeDssProvHandle == null) {
188                     lock (InternalSyncObject) {
189                         if (_safeDssProvHandle == null) {
190                             _safeDssProvHandle = CreateProvHandle(new CspParameters(Constants.PROV_DSS_DH), true);
191                         }
192                     }
193                 }
194                 return _safeDssProvHandle;
195             }
196         }
197
198 #if !FEATURE_PAL
199         [System.Security.SecurityCritical]  // auto-generated
200         [ResourceExposure(ResourceScope.None)]
201         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
202         internal static SafeProvHandle AcquireProvHandle (CspParameters parameters) {
203             if (parameters == null)
204                 parameters = new CspParameters(DefaultRsaProviderType);
205
206             SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
207             Utils._AcquireCSP(parameters, ref safeProvHandle);
208             return safeProvHandle;
209         }
210
211         [System.Security.SecurityCritical]  // auto-generated
212         [ResourceExposure(ResourceScope.None)]
213         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
214         internal static SafeProvHandle CreateProvHandle (CspParameters parameters, bool randomKeyContainer) {
215             SafeProvHandle safeProvHandle = SafeProvHandle.InvalidHandle;
216             int hr = Utils._OpenCSP(parameters, 0, ref safeProvHandle);
217             KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
218             if (hr != Constants.S_OK) {
219                 // If UseExistingKey flag is used and the key container does not exist
220                 // throw an exception without attempting to create the container.
221                 if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || (hr != Constants.NTE_KEYSET_NOT_DEF && hr != Constants.NTE_BAD_KEYSET && hr != Constants.NTE_FILENOTFOUND))
222                     throw new CryptographicException(hr);
223                 if (!randomKeyContainer) {
224                     if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
225                         KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Create);
226                         kp.AccessEntries.Add(entry);
227                         kp.Demand();
228                     }
229                 }
230                 Utils._CreateCSP(parameters, randomKeyContainer, ref safeProvHandle);
231             } else {
232                 if (!randomKeyContainer) {
233                     if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
234                         KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open);
235                         kp.AccessEntries.Add(entry);
236                         kp.Demand();
237                     }
238                 }
239             }
240             return safeProvHandle;
241         }
242 #endif // !FEATURE_PAL
243
244 #if FEATURE_MACL
245         [System.Security.SecurityCritical]  // auto-generated
246         internal static CryptoKeySecurity GetKeySetSecurityInfo (SafeProvHandle hProv, AccessControlSections accessControlSections) {
247             SecurityInfos securityInfo = 0;
248             Privilege privilege = null;
249
250             if ((accessControlSections & AccessControlSections.Owner) != 0)
251                 securityInfo |= SecurityInfos.Owner;
252             if ((accessControlSections & AccessControlSections.Group) != 0)
253                 securityInfo |= SecurityInfos.Group;
254             if ((accessControlSections & AccessControlSections.Access) != 0)
255                 securityInfo |= SecurityInfos.DiscretionaryAcl;
256
257             byte[] rawSecurityDescriptor = null;
258             int error;
259
260             RuntimeHelpers.PrepareConstrainedRegions();
261             try {
262                 if ((accessControlSections & AccessControlSections.Audit) != 0) {
263                     securityInfo |= SecurityInfos.SystemAcl;
264                     privilege = new Privilege("SeSecurityPrivilege");
265                     privilege.Enable();
266                 }
267                 rawSecurityDescriptor = _GetKeySetSecurityInfo(hProv, securityInfo, out error);
268             }
269             finally {
270                 if (privilege != null)
271                     privilege.Revert();
272             }
273
274             // This means that the object doesn't have a security descriptor. And thus we throw
275             // a specific exception for the caller to catch and handle properly.
276             if (error == Win32Native.ERROR_SUCCESS && (rawSecurityDescriptor == null || rawSecurityDescriptor.Length == 0))
277                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NoSecurityDescriptor"));
278             if (error == Win32Native.ERROR_NOT_ENOUGH_MEMORY)
279                 throw new OutOfMemoryException();
280             if (error == Win32Native.ERROR_ACCESS_DENIED)
281                 throw new UnauthorizedAccessException();
282             if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD)
283                 throw new PrivilegeNotHeldException( "SeSecurityPrivilege" );
284             if (error != Win32Native.ERROR_SUCCESS)
285                 throw new CryptographicException(error);
286
287             CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false /* isContainer */,
288                                                                        false /* isDS */,
289                                                                        new RawSecurityDescriptor(rawSecurityDescriptor, 0),
290                                                                        true);
291             return new CryptoKeySecurity(sd);
292         }
293
294         [System.Security.SecurityCritical]  // auto-generated
295         internal static void SetKeySetSecurityInfo (SafeProvHandle hProv, CryptoKeySecurity cryptoKeySecurity, AccessControlSections accessControlSections) {
296             SecurityInfos securityInfo = 0;
297             Privilege privilege = null;
298
299             if ((accessControlSections & AccessControlSections.Owner) != 0 && cryptoKeySecurity._securityDescriptor.Owner != null)
300                 securityInfo |= SecurityInfos.Owner;
301             if ((accessControlSections & AccessControlSections.Group) != 0 && cryptoKeySecurity._securityDescriptor.Group != null)
302                 securityInfo |= SecurityInfos.Group;
303             if ((accessControlSections & AccessControlSections.Audit) != 0)
304                 securityInfo |= SecurityInfos.SystemAcl;
305             if ((accessControlSections & AccessControlSections.Access) != 0 && cryptoKeySecurity._securityDescriptor.IsDiscretionaryAclPresent)
306                 securityInfo |= SecurityInfos.DiscretionaryAcl;
307
308             if (securityInfo == 0) {
309                 // Nothing to persist
310                 return;
311             }
312
313             int error = 0;
314
315             RuntimeHelpers.PrepareConstrainedRegions();
316             try {
317                 if ((securityInfo & SecurityInfos.SystemAcl) != 0) {
318                     privilege = new Privilege("SeSecurityPrivilege");
319                     privilege.Enable();
320                 }
321
322                 byte[] sd = cryptoKeySecurity.GetSecurityDescriptorBinaryForm();
323                 if (sd != null && sd.Length > 0)
324                     error = SetKeySetSecurityInfo (hProv, securityInfo, sd);
325             }
326             finally {
327                 if (privilege != null)
328                     privilege.Revert();
329             }
330
331             if (error == Win32Native.ERROR_ACCESS_DENIED || error == Win32Native.ERROR_INVALID_OWNER || error == Win32Native.ERROR_INVALID_PRIMARY_GROUP)
332                 throw new UnauthorizedAccessException();
333             else if (error == Win32Native.ERROR_PRIVILEGE_NOT_HELD)
334                 throw new PrivilegeNotHeldException("SeSecurityPrivilege");
335             else if (error == Win32Native.ERROR_INVALID_HANDLE)
336                 throw new NotSupportedException(Environment.GetResourceString("AccessControl_InvalidHandle"));
337             else if (error != Win32Native.ERROR_SUCCESS)
338                 throw new CryptographicException(error);
339         }
340 #endif //FEATURE_MACL
341
342         [System.Security.SecurityCritical]  // auto-generated
343         internal static byte[] ExportCspBlobHelper (bool includePrivateParameters, CspParameters parameters, SafeKeyHandle safeKeyHandle) {
344             if (includePrivateParameters) {
345                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
346                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
347                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Export);
348                     kp.AccessEntries.Add(entry);
349                     kp.Demand();
350                 }
351             }
352             byte[] blob = null;
353             Utils.ExportCspBlob(safeKeyHandle, includePrivateParameters ? Constants.PRIVATEKEYBLOB : Constants.PUBLICKEYBLOB, JitHelpers.GetObjectHandleOnStack(ref blob));
354             return blob;
355         }
356
357         [System.Security.SecuritySafeCritical]  // auto-generated
358         [ResourceExposure(ResourceScope.None)]
359         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
360         internal static void GetKeyPairHelper (CspAlgorithmType keyType, CspParameters parameters, bool randomKeyContainer, int dwKeySize, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) {
361             SafeProvHandle TempFetchedProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
362
363 #if FEATURE_MACL
364             // If the user wanted to set the security descriptor on the provider context, apply it now.
365             if (parameters.CryptoKeySecurity != null) {
366                 KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
367                 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.ChangeAcl);
368                 kp.AccessEntries.Add(entry);
369                 kp.Demand();
370                 SetKeySetSecurityInfo(TempFetchedProvHandle, parameters.CryptoKeySecurity, parameters.CryptoKeySecurity.ChangedAccessControlSections);
371             }
372 #endif //FEATURE_MACL
373
374 #if FEATURE_X509_SECURESTRINGS
375             // If the user wanted to specify a PIN or HWND for a smart card CSP, apply those settings now.
376             if (parameters.ParentWindowHandle != IntPtr.Zero) {
377                 // Copy the value onto the stack.
378                 // Then, for versions beyond 4.6.2 take the address of that copy, since &hwnd is what the API wants.
379                 IntPtr parentWindowHandle = parameters.ParentWindowHandle;
380                 IntPtr pHwnd = parentWindowHandle;
381
382                 if (!AppContextSwitches.DoNotAddrOfCspParentWindowHandle) {
383                     unsafe {
384                         pHwnd = new IntPtr(&parentWindowHandle);
385                     }
386                 }
387
388                 SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_CLIENT_HWND, pHwnd);
389             }
390             else if (parameters.KeyPassword != null) {
391                 IntPtr szPassword = Marshal.SecureStringToCoTaskMemAnsi(parameters.KeyPassword);
392                 try {
393                     SetProviderParameter(TempFetchedProvHandle, parameters.KeyNumber, Constants.CLR_PP_PIN, szPassword);
394                 }
395                 finally {
396                     if (szPassword != IntPtr.Zero)
397                         Marshal.ZeroFreeCoTaskMemAnsi(szPassword);
398                 }
399             }
400 #endif //FEATURE_X509_SECURESTRINGS
401
402             safeProvHandle = TempFetchedProvHandle;
403
404             // If the key already exists, use it, else generate a new one
405             SafeKeyHandle TempFetchedKeyHandle = SafeKeyHandle.InvalidHandle;
406             int hr = Utils._GetUserKey(safeProvHandle, parameters.KeyNumber, ref TempFetchedKeyHandle);
407             if (hr != Constants.S_OK) {
408                 if ((parameters.Flags & CspProviderFlags.UseExistingKey) != 0 || hr != Constants.NTE_NO_KEY)
409                     throw new CryptographicException(hr);
410                 // _GenerateKey will check for failures and throw an exception
411                 Utils._GenerateKey(safeProvHandle, parameters.KeyNumber, parameters.Flags, dwKeySize, ref TempFetchedKeyHandle);
412             }
413
414             // check that this is indeed an RSA/DSS key.
415             byte[] algid = (byte[]) Utils._GetKeyParameter(TempFetchedKeyHandle, Constants.CLR_ALGID);
416             int dwAlgId = (algid[0] | (algid[1] << 8) | (algid[2] << 16) | (algid[3] << 24));
417             if ((keyType == CspAlgorithmType.Rsa && dwAlgId != Constants.CALG_RSA_KEYX && dwAlgId != Constants.CALG_RSA_SIGN) ||
418                     (keyType == CspAlgorithmType.Dss && dwAlgId != Constants.CALG_DSS_SIGN)) {
419                 TempFetchedKeyHandle.Dispose();
420                 throw new CryptographicException(Environment.GetResourceString("Cryptography_CSP_WrongKeySpec"));
421             }
422
423             safeKeyHandle = TempFetchedKeyHandle;
424         }
425
426         [System.Security.SecurityCritical]  // auto-generated
427         internal static void ImportCspBlobHelper (CspAlgorithmType keyType, byte[] keyBlob, bool publicOnly, ref CspParameters parameters, bool randomKeyContainer, ref SafeProvHandle safeProvHandle, ref SafeKeyHandle safeKeyHandle) {
428             // Free the current key handle
429             if (safeKeyHandle != null && !safeKeyHandle.IsClosed)
430                 safeKeyHandle.Dispose();
431             safeKeyHandle = SafeKeyHandle.InvalidHandle;
432
433             if (publicOnly) {
434                 parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, keyType == CspAlgorithmType.Dss ? Utils.StaticDssProvHandle : Utils.StaticProvHandle, (CspProviderFlags) 0, ref safeKeyHandle);
435             } else {
436                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
437                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
438                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Import);
439                     kp.AccessEntries.Add(entry);
440                     kp.Demand();
441                 }
442                 if (safeProvHandle == null)
443                     safeProvHandle = Utils.CreateProvHandle(parameters, randomKeyContainer);
444                 parameters.KeyNumber = Utils._ImportCspBlob(keyBlob, safeProvHandle, parameters.Flags, ref safeKeyHandle);
445             }
446         }
447 #endif // FEATURE_CRYPTO
448
449 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
450         [System.Security.SecurityCritical]  // auto-generated
451         [ResourceExposure(ResourceScope.None)]
452         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
453         internal static CspParameters SaveCspParameters (CspAlgorithmType keyType, CspParameters userParameters, CspProviderFlags defaultFlags, ref bool randomKeyContainer) {
454
455             CspParameters parameters;
456             if (userParameters == null) {
457                 parameters = new CspParameters(keyType == CspAlgorithmType.Dss ? Constants.PROV_DSS_DH : DefaultRsaProviderType, null, null, defaultFlags);
458             } else {
459                 ValidateCspFlags(userParameters.Flags);
460                 parameters = new CspParameters(userParameters);
461             }
462
463             if (parameters.KeyNumber == -1)
464                 parameters.KeyNumber = keyType == CspAlgorithmType.Dss ? Constants.AT_SIGNATURE : Constants.AT_KEYEXCHANGE;
465             else if (parameters.KeyNumber == Constants.CALG_DSS_SIGN || parameters.KeyNumber == Constants.CALG_RSA_SIGN)
466                 parameters.KeyNumber = Constants.AT_SIGNATURE;
467             else if (parameters.KeyNumber == Constants.CALG_RSA_KEYX)
468                 parameters.KeyNumber = Constants.AT_KEYEXCHANGE;
469
470             // If no key container was specified and UseDefaultKeyContainer is not used, then use CRYPT_VERIFYCONTEXT
471             // to generate an ephemeral key
472             randomKeyContainer = (parameters.Flags & CspProviderFlags.CreateEphemeralKey) == CspProviderFlags.CreateEphemeralKey;
473             if (parameters.KeyContainerName == null && (parameters.Flags & CspProviderFlags.UseDefaultKeyContainer) == 0) {
474                 parameters.Flags |= CspProviderFlags.CreateEphemeralKey;
475                 randomKeyContainer = true;
476             }
477
478             return parameters;
479         }
480
481         [System.Security.SecurityCritical]  // auto-generated
482         private static void ValidateCspFlags (CspProviderFlags flags) {
483             // check that the flags are consistent.
484             if ((flags & CspProviderFlags.UseExistingKey) != 0) {
485                 CspProviderFlags keyFlags = (CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseArchivableKey | CspProviderFlags.UseUserProtectedKey);
486                 if ((flags & keyFlags) != CspProviderFlags.NoFlags)
487                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"));
488             }
489
490             // make sure we are allowed to display the key protection UI if a user protected key is requested.
491             if ((flags & CspProviderFlags.UseUserProtectedKey) != 0) {
492                 // UI only allowed in interactive session.
493                 if (!System.Environment.UserInteractive)
494                     throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NotInteractive"));
495
496                 // we need to demand UI permission here.
497                 UIPermission uiPermission = new UIPermission(UIPermissionWindow.SafeTopLevelWindows);
498                 uiPermission.Demand();
499             }
500         }
501 #endif // FEATURE_CRYPTO
502
503 #endif
504         private static volatile RNGCryptoServiceProvider _rng;
505         internal static RNGCryptoServiceProvider StaticRandomNumberGenerator {
506             get {
507                 if (_rng == null)
508                     _rng = new RNGCryptoServiceProvider();
509                 return _rng;
510             }
511         }
512
513         //
514         // internal static methods
515         //
516
517         internal static byte[] GenerateRandom (int keySize) {
518             byte[] key = new byte[keySize];
519             StaticRandomNumberGenerator.GetBytes(key);
520             return key;
521         }
522 #if !MONO
523 #if FEATURE_CRYPTO
524         /// <summary>
525         ///     Read the FIPS policy from the pre-Vista registry key
526         /// </summary>
527         /// <returns>
528         ///     True if the FIPS policy is enabled, false otherwise.  An error reading the policy key is
529         ///     interpreted as if the policy is enabled, and a missing key is interpreted as the policy being
530         ///     disabled.
531         /// </returns>
532         [System.Security.SecurityCritical]  // auto-generated
533         [RegistryPermissionAttribute(SecurityAction.Assert, Read="HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Lsa")]
534         internal static bool ReadLegacyFipsPolicy()
535         {
536             Contract.Assert(Environment.OSVersion.Version.Major < 6, "CryptGetFIPSAlgorithmMode should be used on Vista+");
537
538             try
539             {
540                 using (RegistryKey fipsAlgorithmPolicyKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa", false))
541                 {
542                     if (fipsAlgorithmPolicyKey == null)
543                         return false;
544
545                     object data = fipsAlgorithmPolicyKey.GetValue("FIPSAlgorithmPolicy");
546
547                     if (data == null)
548                     {
549                         return false;
550                     }
551                     else if (fipsAlgorithmPolicyKey.GetValueKind("FIPSAlgorithmPolicy") != RegistryValueKind.DWord)
552                     {
553                         return true;
554                     }
555                     else
556                     {
557                         return ((int)data != 0);
558                     }
559                 }
560             }
561             catch (SecurityException)
562             {
563                 // If we could not open the registry key, we'll assume the setting is to enforce FIPS policy.
564                 return true;
565             }
566         }
567 #endif //FEATURE_CRYPTO
568 #endif
569 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
570         // dwKeySize = 0 means the default key size
571         [System.Security.SecurityCritical]  // auto-generated
572         internal static bool HasAlgorithm (int dwCalg, int dwKeySize) {
573 #if MONO
574             return true;
575 #else
576             bool r = false;
577             // We need to take a lock here since we are querying the provider handle in a loop.
578             // If multiple threads are racing in this code, not all algorithms/key sizes combinations
579             // will be examined; which may lead to a situation where false is wrongfully returned.
580             lock (InternalSyncObject) {
581                 r = SearchForAlgorithm(StaticProvHandle, dwCalg, dwKeySize);
582             }
583             return r;
584 #endif
585         }
586 #if !MONO
587         internal static int ObjToAlgId(object hashAlg, OidGroup group) {
588             if (hashAlg == null)
589                 throw new ArgumentNullException("hashAlg");
590             Contract.EndContractBlock();
591
592             string oidValue = null;
593             string hashAlgString = hashAlg as string;
594             if (hashAlgString != null) {
595                 oidValue = CryptoConfig.MapNameToOID(hashAlgString, group);
596                 if (oidValue == null)
597                     oidValue = hashAlgString; // maybe we were passed the OID value
598             }
599             else if (hashAlg is HashAlgorithm) {
600                 oidValue = CryptoConfig.MapNameToOID(hashAlg.GetType().ToString(), group);
601             }
602             else if (hashAlg is Type) {
603                 oidValue = CryptoConfig.MapNameToOID(hashAlg.ToString(), group);
604             }
605
606             if (oidValue == null)
607                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
608
609             return X509Utils.GetAlgIdFromOid(oidValue, group);
610         }
611
612         internal static HashAlgorithm ObjToHashAlgorithm (Object hashAlg) {
613             if (hashAlg == null)
614                 throw new ArgumentNullException("hashAlg");
615             Contract.EndContractBlock();
616
617             HashAlgorithm hash = null;
618             if (hashAlg is String) {
619                 hash = (HashAlgorithm) CryptoConfig.CreateFromName((string) hashAlg);
620                 if (hash == null) {
621                     string oidFriendlyName = X509Utils.GetFriendlyNameFromOid((string) hashAlg, OidGroup.HashAlgorithm);
622                     if (oidFriendlyName != null)
623                         hash = (HashAlgorithm) CryptoConfig.CreateFromName(oidFriendlyName);
624                 }
625             }
626             else if (hashAlg is HashAlgorithm) {
627                 hash = (HashAlgorithm) hashAlg;
628             }
629             else if (hashAlg is Type) {
630                 hash = (HashAlgorithm) CryptoConfig.CreateFromName(hashAlg.ToString());
631             }
632
633             if (hash == null)
634                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
635
636             return hash;
637         }
638 #endif
639         internal static String DiscardWhiteSpaces (string inputBuffer) {
640             return DiscardWhiteSpaces(inputBuffer, 0, inputBuffer.Length);
641         }
642
643         internal static String DiscardWhiteSpaces (string inputBuffer, int inputOffset, int inputCount) {
644             int i, iCount = 0;
645             for (i=0; i<inputCount; i++)
646                 if (Char.IsWhiteSpace(inputBuffer[inputOffset + i])) iCount++;
647             char[] output = new char[inputCount - iCount];
648             iCount = 0;
649             for (i=0; i<inputCount; i++) {
650                 if (!Char.IsWhiteSpace(inputBuffer[inputOffset + i]))
651                     output[iCount++] = inputBuffer[inputOffset + i];
652             }
653             return new String(output);
654         }
655
656         internal static int ConvertByteArrayToInt (byte[] input) {
657             // Input to this routine is always big endian
658             int dwOutput = 0;
659             for (int i = 0; i < input.Length; i++) {
660                 dwOutput *= 256;
661                 dwOutput += input[i];
662             }
663             return(dwOutput);
664         }
665
666         // output of this routine is always big endian
667         internal static byte[] ConvertIntToByteArray (int dwInput) {
668             byte[] temp = new byte[8]; // int can never be greater than Int64
669             int t1;  // t1 is remaining value to account for
670             int t2;  // t2 is t1 % 256
671             int i = 0;
672
673             if (dwInput == 0) return new byte[1]; 
674             t1 = dwInput; 
675             while (t1 > 0) {
676                 Contract.Assert(i < 8, "Got too big an int here!");
677                 t2 = t1 % 256;
678                 temp[i] = (byte) t2;
679                 t1 = (t1 - t2)/256;
680                 i++;
681             }
682
683             // Now, copy only the non-zero part of temp and reverse
684             byte[] output = new byte[i];
685             // copy and reverse in one pass
686             for (int j = 0; j < i; j++) {
687                 output[j] = temp[i-j-1];
688             }
689             return output;
690         }
691
692         // output is little endian
693         internal static void ConvertIntToByteArray (uint dwInput, ref byte[] counter) {
694             uint t1 = dwInput;  // t1 is remaining value to account for
695             uint t2;  // t2 is t1 % 256
696             int i = 0;
697
698             // clear the array first
699             Array.Clear(counter, 0, counter.Length);
700             if (dwInput == 0) return;
701             while (t1 > 0) {
702                 Contract.Assert(i < 4, "Got too big an int here!");
703                 t2 = t1 % 256;
704                 counter[3 - i] = (byte) t2;
705                 t1 = (t1 - t2)/256;
706                 i++;
707             }
708         }
709
710         internal static byte[] FixupKeyParity (byte[] key) {
711             byte[] oddParityKey = new byte[key.Length];
712             for (int index=0; index < key.Length; index++) {
713                 // Get the bits we are interested in
714                 oddParityKey[index] = (byte) (key[index] & 0xfe);
715                 // Get the parity of the sum of the previous bits
716                 byte tmp1 = (byte)((oddParityKey[index] & 0xF) ^ (oddParityKey[index] >> 4));
717                 byte tmp2 = (byte)((tmp1 & 0x3) ^ (tmp1 >> 2));
718                 byte sumBitsMod2 = (byte)((tmp2 & 0x1) ^ (tmp2 >> 1));
719                 // We need to set the last bit in oddParityKey[index] to the negation
720                 // of the last bit in sumBitsMod2
721                 if (sumBitsMod2 == 0)
722                     oddParityKey[index] |= 1;
723             }
724             return oddParityKey;
725         }
726
727         // digits == number of DWORDs
728         [System.Security.SecurityCritical]  // auto-generated
729         internal unsafe static void DWORDFromLittleEndian (uint* x, int digits, byte* block) {
730             int i;
731             int j;
732
733             for (i = 0, j = 0; i < digits; i++, j += 4)
734                 x[i] =  (uint) (block[j] | (block[j+1] << 8) | (block[j+2] << 16) | (block[j+3] << 24));
735         }
736
737         // encodes x (DWORD) into block (unsigned char), least significant byte first. 
738         // digits == number of DWORDs
739         internal static void DWORDToLittleEndian (byte[] block, uint[] x, int digits) {
740             int i;
741             int j;
742
743             for (i = 0, j = 0; i < digits; i++, j += 4) {
744                 block[j]   = (byte)(x[i] & 0xff);
745                 block[j+1] = (byte)((x[i] >> 8) & 0xff);
746                 block[j+2] = (byte)((x[i] >> 16) & 0xff);
747                 block[j+3] = (byte)((x[i] >> 24) & 0xff);
748             }
749         }
750 #endif // FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
751
752         // digits == number of DWORDs
753         [System.Security.SecurityCritical]  // auto-generated
754         internal unsafe static void DWORDFromBigEndian (uint* x, int digits, byte* block) {
755             int i;
756             int j;
757
758             for (i = 0, j = 0; i < digits; i++, j += 4)
759                 x[i] = (uint)((block[j] << 24) | (block[j + 1] << 16) | (block[j + 2] << 8) | block[j + 3]);
760         }
761
762         // encodes x (DWORD) into block (unsigned char), most significant byte first. 
763         // digits == number of DWORDs
764         internal static void DWORDToBigEndian (byte[] block, uint[] x, int digits) {
765             int i;
766             int j;
767
768             for (i = 0, j = 0; i < digits; i++, j += 4) {
769                 block[j] = (byte)((x[i] >> 24) & 0xff);
770                 block[j+1] = (byte)((x[i] >> 16) & 0xff);
771                 block[j+2] = (byte)((x[i] >> 8) & 0xff);
772                 block[j+3] = (byte)(x[i] & 0xff);
773             }
774         }
775
776 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
777         // digits == number of QWORDs
778         [System.Security.SecurityCritical]  // auto-generated
779         internal unsafe static void QuadWordFromBigEndian (UInt64* x, int digits, byte* block) {
780             int i;
781             int j;
782
783             for (i = 0, j = 0; i < digits; i++, j += 8)
784                 x[i] =  (
785                          (((UInt64)block[j]) << 56) | (((UInt64)block[j+1]) << 48) |
786                          (((UInt64)block[j+2]) << 40) | (((UInt64)block[j+3]) << 32) |
787                          (((UInt64)block[j+4]) << 24) | (((UInt64)block[j+5]) << 16) |
788                          (((UInt64)block[j+6]) << 8) | ((UInt64)block[j+7])
789                         );
790         }
791
792         // encodes x (DWORD) into block (unsigned char), most significant byte first.
793         // digits = number of QWORDS
794         internal static void QuadWordToBigEndian (byte[] block, UInt64[] x, int digits) {
795             int i;
796             int j;
797
798             for (i = 0, j = 0; i < digits; i++, j += 8) {
799                 block[j] = (byte)((x[i] >> 56) & 0xff);
800                 block[j+1] = (byte)((x[i] >> 48) & 0xff);
801                 block[j+2] = (byte)((x[i] >> 40) & 0xff);
802                 block[j+3] = (byte)((x[i] >> 32) & 0xff);
803                 block[j+4] = (byte)((x[i] >> 24) & 0xff);
804                 block[j+5] = (byte)((x[i] >> 16) & 0xff);
805                 block[j+6] = (byte)((x[i] >> 8) & 0xff);
806                 block[j+7] = (byte)(x[i] & 0xff);
807             }
808         }
809 #endif // FEATURE_CRYPTO
810
811         // encodes the integer i into a 4-byte array, in big endian.
812         internal static byte[] Int(uint i) {
813             return unchecked(new byte[] { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i });
814         }
815
816 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
817         [System.Security.SecurityCritical]  // auto-generated
818         internal static byte[] RsaOaepEncrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, RandomNumberGenerator rng, byte[] data) {
819 #if MONO
820             // It looks like .net managed implementation is buggy. It returns quite different
821             // result compare to old mono code, even PSLength calculation is quite different
822             return Mono.Security.Cryptography.PKCS1.Encrypt_OAEP (rsa, hash, rng, data);
823 #else
824             int cb = rsa.KeySize / 8;
825
826             //  1. Hash the parameters to get PHash
827             int cbHash = hash.HashSize / 8;
828             if ((data.Length + 2 + 2*cbHash) > cb)
829                 throw new CryptographicException(String.Format(null, Environment.GetResourceString("Cryptography_Padding_EncDataTooBig"), cb-2-2*cbHash));
830             hash.ComputeHash(EmptyArray<Byte>.Value); // Use an empty octet string
831
832             //  2.  Create DB object
833             byte[] DB = new byte[cb - cbHash + 1];
834
835             //  Structure is as follows:
836             //      pHash || PS || 01 || M
837             //      PS consists of all zeros
838
839             Buffer.InternalBlockCopy(hash.Hash, 0, DB, 0, cbHash);
840             DB[DB.Length - data.Length - 1] = 1;
841             Buffer.InternalBlockCopy(data, 0, DB, DB.Length-data.Length, data.Length);
842
843             // 3. Create a random value of size hLen
844             byte[] seed = new byte[cbHash];
845             rng.GetBytes(seed);
846
847             // 4.  Compute the mask value
848             byte[] mask = mgf.GenerateMask(seed, DB.Length);
849
850             // 5.  Xor maskDB into DB
851             for (int i=0; i < DB.Length; i++) {
852                 DB[i] = (byte) (DB[i] ^ mask[i]);
853             }
854
855             // 6.  Compute seed mask value
856             mask = mgf.GenerateMask(DB, cbHash);
857
858             // 7.  Xor mask into seed
859             for (int i=0; i < seed.Length; i++) {
860                 seed[i] ^= mask[i];
861             }
862
863             // 8. Concatenate seed and DB to form value to encrypt
864             byte[] pad = new byte[cb];
865             Buffer.InternalBlockCopy(seed, 0, pad, 0, seed.Length);
866             Buffer.InternalBlockCopy(DB, 0, pad, seed.Length, DB.Length);
867
868             return rsa.EncryptValue(pad);
869 #endif
870         }
871
872         [System.Security.SecurityCritical]  // auto-generated
873         internal static byte[] RsaOaepDecrypt (RSA rsa, HashAlgorithm hash, PKCS1MaskGenerationMethod mgf, byte[] encryptedData) {
874 #if MONO
875             var result = Mono.Security.Cryptography.PKCS1.Decrypt_OAEP (rsa, hash, encryptedData);
876             if (result == null)
877                 throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
878             return result;
879 #else
880             int cb = rsa.KeySize / 8;
881
882             // 1. Decode the input data
883             // It is important that the Integer to Octet String conversion errors be indistinguishable from the other decoding
884             // errors to protect against chosen cipher text attacks
885             // A lecture given by James Manger during Crypto 2001 explains the issue in details
886             byte[] data = null;
887             try {
888                 data = rsa.DecryptValue(encryptedData);
889             }
890             catch (CryptographicException) {
891                 throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
892             }
893
894             // 2. Create the hash object so we can get its size info.
895             int cbHash = hash.HashSize / 8;
896
897             //  3.  Let maskedSeed be the first hLen octects and maskedDB
898             //      be the remaining bytes.
899             int zeros = cb - data.Length;
900             if (zeros < 0 || zeros >= cbHash)
901                 throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
902
903             const int leading_zeros = 0;
904             byte[] seed = new byte[cbHash];
905             Buffer.InternalBlockCopy(data, leading_zeros, seed, zeros, seed.Length - zeros);
906
907             byte[] DB = new byte[data.Length - seed.Length + zeros - leading_zeros];
908             Buffer.InternalBlockCopy(data, seed.Length - zeros + leading_zeros, DB, 0, DB.Length);
909
910             //  4.  seedMask = MGF(maskedDB, hLen);
911             byte[] mask = mgf.GenerateMask(DB, seed.Length);
912
913             //  5.  seed = seedMask XOR maskedSeed
914             int i = 0;
915             for (i=0; i < seed.Length; i++) {
916                 seed[i] ^= mask[i];
917             }
918
919             //  6.  dbMask = MGF(seed, |EM| - hLen);
920             mask = mgf.GenerateMask(seed, DB.Length);
921
922             //  7.  DB = maskedDB xor dbMask
923             for (i=0; i < DB.Length; i++) {
924                 DB[i] = (byte) (DB[i] ^ mask[i]);
925             }
926
927             //  8.  pHash = HASH(P)
928             hash.ComputeHash(EmptyArray<Byte>.Value);
929
930             //  9.  DB = pHash' || PS || 01 || M
931             //  10.  Check that pHash = pHash'
932
933             byte[] hashValue = hash.Hash;
934             for (i=0; i < cbHash; i++) {
935                 if (DB[i] != hashValue[i])
936                     throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
937             }
938
939             //  Check that PS is all zeros
940             for (; i<DB.Length; i++) {
941                 if (DB[i] == 1)
942                     break;
943                 else if (DB[i] != 0)
944                     throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
945             }
946
947             if (i == DB.Length)
948                 throw new CryptographicException(Environment.GetResourceString("Cryptography_OAEPDecoding"));
949
950             i++; // skip over the one
951
952             //  11. Output M.
953             byte[] output = new byte[DB.Length - i];
954             Buffer.InternalBlockCopy(DB, i, output, 0, output.Length);
955             return output;
956  #endif
957         }
958
959         [System.Security.SecurityCritical]  // auto-generated
960         internal static byte[] RsaPkcs1Padding (RSA rsa, byte[] oid, byte[] hash) {
961             int cb = rsa.KeySize/8;
962             byte[] pad = new byte[cb];
963
964             //
965             //  We want to pad this to the following format:
966             //
967             //  00 || 01 || FF ... FF || 00 || prefix || Data
968             //
969             // We want basically to ASN 1 encode the OID + hash:
970             // STRUCTURE {
971             //  STRUCTURE {
972             //    OID <hash algorithm OID>
973             //    NULL (0x05 0x00)  // this is actually an ANY and contains the parameters of the algorithm specified by the OID, I think
974             //  }
975             //  OCTET STRING <hashvalue>
976             // }
977             //
978
979             // Get the correct prefix
980             byte[] data = new byte[oid.Length + 8 + hash.Length];
981             data[0] = 0x30; // a structure follows
982             int tmp = data.Length - 2;
983             data[1] = (byte) tmp;
984             data[2] = 0x30;
985             tmp = oid.Length + 2;
986             data[3] = (byte) tmp;
987             Buffer.InternalBlockCopy(oid, 0, data, 4, oid.Length);
988             data[4 + oid.Length] = 0x05;
989             data[4 + oid.Length + 1] = 0x00;
990             data[4 + oid.Length + 2] = 0x04; // an octet string follows
991             data[4 + oid.Length + 3] = (byte) hash.Length;
992             Buffer.InternalBlockCopy(hash, 0, data, oid.Length + 8, hash.Length);
993
994             // Construct the whole array
995             int cb1 = cb - data.Length;
996             if (cb1 <= 2)
997                 throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_InvalidOID"));
998
999             pad[0] = 0;
1000             pad[1] = 1;
1001             for (int i=2; i<cb1-1; i++) {
1002                 pad[i] = 0xff;
1003             }
1004             pad[cb1-1] = 0;
1005             Buffer.InternalBlockCopy(data, 0, pad, cb1, data.Length);
1006             return pad;
1007         }
1008
1009         // This routine compares 2 big ints; ignoring any leading zeros
1010         internal static bool CompareBigIntArrays (byte[] lhs, byte[] rhs) {
1011             if (lhs == null)
1012                 return (rhs == null);
1013
1014             int i = 0, j = 0;
1015             while (i < lhs.Length && lhs[i] == 0) i++;
1016             while (j < rhs.Length && rhs[j] == 0) j++;
1017
1018             int count = (lhs.Length - i);
1019             if ((rhs.Length - j) != count)
1020                 return false;
1021
1022             for (int k = 0; k < count; k++) {
1023                 if (lhs[i + k] != rhs[j + k])
1024                     return false;
1025             }
1026             return true;
1027         }
1028 #if !MONO
1029         [System.Security.SecurityCritical]  // auto-generated
1030         [ResourceExposure(ResourceScope.None)]  // Creates a process resource, but it can't be scoped.
1031         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1032         internal static extern SafeHashHandle CreateHash(SafeProvHandle hProv, int algid);
1033 #endif
1034         internal static HashAlgorithmName OidToHashAlgorithmName(string oid)
1035         {
1036             switch (oid)
1037             {
1038                 case Constants.OID_OIWSEC_SHA1:
1039                     return HashAlgorithmName.SHA1;
1040
1041                 case Constants.OID_OIWSEC_SHA256:
1042                     return HashAlgorithmName.SHA256;
1043
1044                 case Constants.OID_OIWSEC_SHA384:
1045                     return HashAlgorithmName.SHA384;
1046
1047                 case Constants.OID_OIWSEC_SHA512:
1048                     return HashAlgorithmName.SHA512;
1049
1050                 default:
1051                     throw new NotSupportedException();
1052             }
1053         }
1054
1055         //
1056         // Backward-compat hack for third-party RSA-derived classes:
1057         // 
1058         // Because the SignHash()/VerifyHash()/Encrypt()/Decrypt() methods are new on RSA, we may 
1059         // encounter older third-party RSA-derived classes that don't override them
1060         // (and if they don't override them, these methods will throw since they are effectively abstract methods that had to declared non-abstract
1061         // for backward compat reasons.)
1062         //
1063         internal static bool DoesRsaKeyOverride(RSA rsaKey, string methodName, Type[] parameterTypes)
1064         {
1065             // A fast-path check for the common cases where we know we implemented the overrides.
1066             Type t = rsaKey.GetType();
1067             if (rsaKey is RSACryptoServiceProvider)
1068             {
1069 #if DEBUG
1070                 // On checked builds, do the slow-path check anyway so it gets exercised.
1071                 bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
1072                 BCLDebug.Assert(foundOverride, "RSACryptoServiceProvider expected to override " + methodName);
1073 #endif
1074                 return true;
1075             }
1076
1077             string fullName = t.FullName;
1078             if (fullName == "System.Security.Cryptography.RSACng")
1079             {
1080 #if DEBUG
1081                 // On checked builds, do the slow-path check anyway so it gets exercised.
1082                 bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
1083                 BCLDebug.Assert(foundOverride, "RSACng expected to override " + methodName);
1084 #endif
1085                 return true;
1086             }
1087             return DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
1088         }
1089
1090         private static bool DoesRsaKeyOverrideSlowPath(Type t, string methodName, Type[] parameterTypes)
1091         {
1092             MethodInfo method = t.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance, null, parameterTypes, null);
1093             BCLDebug.Assert(method != null, "method != null"); 
1094             Type declaringType = method.DeclaringType;
1095             if (declaringType == typeof(RSA))
1096                 return false;
1097
1098             return true;
1099         }
1100 #if !MONO
1101         [System.Security.SecurityCritical]  // auto-generated
1102         [ResourceExposure(ResourceScope.None)]
1103         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1104         private static extern void EndHash(SafeHashHandle hHash, ObjectHandleOnStack retHash);
1105
1106         [System.Security.SecurityCritical]  // auto-generated
1107         internal static byte[] EndHash(SafeHashHandle hHash)
1108         {
1109             byte[] hash = null;
1110             EndHash(hHash, JitHelpers.GetObjectHandleOnStack(ref hash));
1111             return hash;
1112         }
1113
1114         [System.Security.SecurityCritical]  // auto-generated
1115         [ResourceExposure(ResourceScope.None)]
1116         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1117         private static extern void ExportCspBlob(SafeKeyHandle hKey, int blobType, ObjectHandleOnStack retBlob);
1118
1119         [System.Security.SecurityCritical]  // auto-generated
1120         [ResourceExposure(ResourceScope.None)]
1121         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1122         internal static extern bool GetPersistKeyInCsp(SafeProvHandle hProv);
1123
1124         [System.Security.SecurityCritical]  // auto-generated
1125         [ResourceExposure(ResourceScope.None)]
1126         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1127         private static extern void HashData(SafeHashHandle hHash, byte[] data, int cbData, int ibStart, int cbSize);
1128
1129         [System.Security.SecurityCritical]  // auto-generated
1130         internal static void HashData(SafeHashHandle hHash, byte[] data, int ibStart, int cbSize)
1131         {
1132             HashData(hHash, data, data.Length, ibStart, cbSize);
1133         }
1134
1135         [System.Security.SecurityCritical]  // auto-generated
1136         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1137         [ResourceExposure(ResourceScope.None)]
1138         private static extern bool SearchForAlgorithm(SafeProvHandle hProv, int algID, int keyLength);
1139
1140         [System.Security.SecurityCritical]  // auto-generated
1141         [ResourceExposure(ResourceScope.None)]
1142         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1143         internal static extern void SetKeyParamDw(SafeKeyHandle hKey, int param, int dwValue);
1144
1145         [System.Security.SecurityCritical]  // auto-generated
1146         [ResourceExposure(ResourceScope.None)]
1147         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1148         internal static extern void SetKeyParamRgb(SafeKeyHandle hKey, int param, byte[] value, int cbValue);
1149
1150 #if FEATURE_MACL
1151         [System.Security.SecurityCritical]  // auto-generated
1152         [ResourceExposure(ResourceScope.None)]
1153         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1154         private static extern int SetKeySetSecurityInfo(SafeProvHandle hProv, SecurityInfos securityInfo, byte[] sd);
1155 #endif //FEATURE_MACL
1156         [System.Security.SecurityCritical]  // auto-generated
1157         [ResourceExposure(ResourceScope.None)]
1158         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1159         internal static extern void SetPersistKeyInCsp(SafeProvHandle hProv, bool fPersistKeyInCsp);
1160
1161         [System.Security.SecurityCritical]  // auto-generated
1162         [ResourceExposure(ResourceScope.None)]
1163         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1164         internal static extern void SetProviderParameter(SafeProvHandle hProv, int keyNumber, uint paramID, IntPtr pbData);
1165
1166         [System.Security.SecurityCritical]  // auto-generated
1167         [ResourceExposure(ResourceScope.None)]
1168         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1169         private static extern void SignValue(SafeKeyHandle hKey, int keyNumber, int calgKey, int calgHash, byte[] hash, int cbHash, ObjectHandleOnStack retSignature);
1170
1171         [System.Security.SecurityCritical]  // auto-generated
1172         internal static byte[] SignValue(SafeKeyHandle hKey, int keyNumber, int calgKey, int calgHash, byte[] hash)
1173         {
1174             byte[] signature = null;
1175             SignValue(hKey, keyNumber, calgKey, calgHash, hash, hash.Length, JitHelpers.GetObjectHandleOnStack(ref signature));
1176             return signature;
1177         }
1178
1179         [System.Security.SecurityCritical]  // auto-generated
1180         [ResourceExposure(ResourceScope.None)]
1181         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
1182         private static extern bool VerifySign(SafeKeyHandle hKey, int calgKey, int calgHash, byte[] hash, int cbHash, byte[] signature, int cbSignature);
1183
1184         [System.Security.SecurityCritical]  // auto-generated
1185         internal static bool VerifySign(SafeKeyHandle hKey, int calgKey, int calgHash, byte[] hash, byte[] signature)
1186         {
1187             return VerifySign(hKey, calgKey, calgHash, hash, hash.Length, signature, signature.Length);
1188         }
1189
1190         [System.Security.SecurityCritical]  // auto-generated
1191         [ResourceExposure(ResourceScope.Machine)]
1192         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1193         internal static extern void _CreateCSP(CspParameters param, bool randomKeyContainer, ref SafeProvHandle hProv);
1194         [System.Security.SecurityCritical]  // auto-generated
1195         [ResourceExposure(ResourceScope.None)]
1196         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1197         internal static extern int _DecryptData(SafeKeyHandle hKey, byte[] data, int ib, int cb, ref byte[] outputBuffer, int outputOffset, PaddingMode PaddingMode, bool fDone);
1198         [System.Security.SecurityCritical]  // auto-generated
1199         [ResourceExposure(ResourceScope.None)]
1200         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1201         internal static extern int _EncryptData(SafeKeyHandle hKey, byte[] data, int ib, int cb, ref byte[] outputBuffer, int outputOffset, PaddingMode PaddingMode, bool fDone);
1202         [System.Security.SecurityCritical]  // auto-generated
1203         [ResourceExposure(ResourceScope.None)]
1204         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1205         internal static extern void _ExportKey(SafeKeyHandle hKey, int blobType, object cspObject);
1206         [System.Security.SecurityCritical]  // auto-generated
1207         [ResourceExposure(ResourceScope.None)]
1208         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1209         internal static extern void _GenerateKey(SafeProvHandle hProv, int algid, CspProviderFlags flags, int keySize, ref SafeKeyHandle hKey);
1210 #endif
1211 #endif // FEATURE_CRYPTO
1212 #if !MONO
1213         [System.Security.SecurityCritical]  // auto-generated
1214         [ResourceExposure(ResourceScope.None)]
1215         [MethodImpl(MethodImplOptions.InternalCall)]
1216         internal static extern bool _GetEnforceFipsPolicySetting();
1217 #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
1218         [System.Security.SecurityCritical]  // auto-generated
1219         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1220         internal static extern byte[] _GetKeyParameter(SafeKeyHandle hKey, uint paramID);
1221 #if FEATURE_MACL
1222         [System.Security.SecurityCritical]  // auto-generated
1223         [ResourceExposure(ResourceScope.None)]
1224         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1225         internal static extern byte[] _GetKeySetSecurityInfo(SafeProvHandle hProv, SecurityInfos securityInfo, out int error);
1226 #endif //FEATURE_MACL
1227         [System.Security.SecurityCritical]  // auto-generated
1228         [ResourceExposure(ResourceScope.None)]
1229         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1230         internal static extern object _GetProviderParameter(SafeProvHandle hProv, int keyNumber, uint paramID);
1231         [System.Security.SecurityCritical]  // auto-generated
1232         [ResourceExposure(ResourceScope.None)]
1233         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1234         internal static extern int _GetUserKey(SafeProvHandle hProv, int keyNumber, ref SafeKeyHandle hKey);
1235         [System.Security.SecurityCritical]  // auto-generated
1236         [ResourceExposure(ResourceScope.None)]
1237         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1238         internal static extern void _ImportBulkKey(SafeProvHandle hProv, int algid, bool useSalt, byte[] key, ref SafeKeyHandle hKey);
1239         [System.Security.SecurityCritical]  // auto-generated
1240         [ResourceExposure(ResourceScope.None)]
1241         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1242         internal static extern int _ImportCspBlob(byte[] keyBlob, SafeProvHandle hProv, CspProviderFlags flags, ref SafeKeyHandle hKey);
1243         [System.Security.SecurityCritical]  // auto-generated
1244         [ResourceExposure(ResourceScope.None)]
1245         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1246         internal static extern void _ImportKey(SafeProvHandle hCSP, int keyNumber, CspProviderFlags flags, object cspObject, ref SafeKeyHandle hKey);
1247         [System.Security.SecurityCritical]  // auto-generated
1248         [ResourceExposure(ResourceScope.None)]
1249         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1250         internal static extern bool _ProduceLegacyHmacValues();
1251 #endif // FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
1252         [System.Security.SecurityCritical]  // auto-generated
1253         [ResourceExposure(ResourceScope.Machine)]
1254         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1255         internal static extern int _OpenCSP(CspParameters param, uint flags, ref SafeProvHandle hProv);
1256         [System.Security.SecurityCritical]  // auto-generated
1257         [ResourceExposure(ResourceScope.Machine)]
1258         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1259         internal static extern void _AcquireCSP(CspParameters param, ref SafeProvHandle hProv);
1260
1261 #else
1262         internal static bool _ProduceLegacyHmacValues()
1263         {
1264 #if FULL_AOT_RUNTIME
1265             return false;
1266 #else
1267             return Environment.GetEnvironmentVariable ("legacyHMACMode") == "1";
1268 #endif
1269         }
1270 #endif
1271     }
1272 }
1273