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