Merge pull request #3248 from esdrubal/web_request_abort
[mono.git] / mcs / class / referencesource / System.Core / System / Security / Cryptography / NCryptNative.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 using System;
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.Diagnostics.CodeAnalysis;
11 #if !MONO
12 using System.Numerics;
13 #endif
14 using System.Runtime.CompilerServices;
15 using System.Runtime.ConstrainedExecution;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
18 using System.Text;
19 using System.Diagnostics.Contracts;
20 using Microsoft.Win32;
21 using Microsoft.Win32.SafeHandles;
22
23 namespace System.Security.Cryptography {
24
25     //
26     // Public facing enumerations
27     //
28
29     /// <summary>
30     ///     Flags to control how often and in which format a key is allowed to be exported
31     /// </summary>
32     [Flags]
33     public enum CngExportPolicies {
34         None = 0x00000000,
35         AllowExport = 0x00000001,                       // NCRYPT_ALLOW_EXPORT_FLAG
36         AllowPlaintextExport = 0x00000002,              // NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG
37         AllowArchiving = 0x00000004,                    // NCRYPT_ALLOW_ARCHIVING_FLAG
38         AllowPlaintextArchiving = 0x00000008            // NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG
39     }
40
41     /// <summary>
42     ///     Flags controlling how the key is created
43     /// </summary>
44     [Flags]
45     public enum CngKeyCreationOptions {
46         None = 0x00000000,
47         MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
48         OverwriteExistingKey = 0x00000080               // NCRYPT_OVERWRITE_KEY_FLAG               
49     }
50
51     /// <summary>
52     ///     Flags controlling how a key is opened
53     /// </summary>
54     [Flags]
55     [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Approved API exception to have an easy way to express user keys")]
56     public enum CngKeyOpenOptions {
57         None = 0x00000000,
58         UserKey = 0x00000000,
59         MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
60         Silent = 0x00000040                             // NCRYPT_SILENT_FLAG                      
61     }
62
63     /// <summary>
64     ///     Flags indicating the type of key
65     /// </summary>
66     [Flags]
67     internal enum CngKeyTypes {
68         None = 0x00000000,
69         MachineKey = 0x00000020                         // NCRYPT_MACHINE_KEY_FLAG
70     }
71
72     /// <summary>
73     ///     Bits defining what operations are valid to use a key with
74     /// </summary>
75     [Flags]
76     [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
77     public enum CngKeyUsages {
78         None = 0x00000000,
79         Decryption = 0x00000001,                        // NCRYPT_ALLOW_DECRYPT_FLAG
80         Signing = 0x00000002,                           // NCRYPT_ALLOW_SIGNING_FLAG
81         KeyAgreement = 0x00000004,                      // NCRYPT_ALLOW_KEY_AGREEMENT_FLAG
82         AllUsages = 0x00ffffff                          // NCRYPT_ALLOW_ALL_USAGES
83     }
84
85     /// <summary>
86     ///     Options affecting how a property is interpreted by CNG
87     /// </summary>
88     [Flags]
89     [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
90     public enum CngPropertyOptions {
91         None = 0x00000000,
92         CustomProperty = 0x40000000,                    // NCRYPT_PERSIST_ONLY_FLAG
93         Persist = unchecked((int)0x80000000)            // NCRYPT_PERSIST_FLAG
94     }
95
96     /// <summary>
97     ///     Levels of UI protection available for a key
98     /// </summary>
99     [Flags]
100     public enum CngUIProtectionLevels {
101         None = 0x00000000,
102         ProtectKey = 0x00000001,                        // NCRYPT_UI_PROTECT_KEY_FLAG    
103         ForceHighProtection = 0x00000002                // NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG
104     }
105 #if !MONO
106     /// <summary>
107     ///     Native interop with CNG's NCrypt layer. Native definitions are in ncrypt.h
108     /// </summary>
109     internal static class NCryptNative {
110         //
111         // Enumerations
112         //
113
114         /// <summary>
115         ///     Types of NCryptBuffers
116         /// </summary>
117         internal enum BufferType {
118             KdfHashAlgorithm = 0x00000000,              // KDF_HASH_ALGORITHM
119             KdfSecretPrepend = 0x00000001,              // KDF_SECRET_PREPEND
120             KdfSecretAppend = 0x00000002,               // KDF_SECRET_APPEND
121             KdfHmacKey = 0x00000003,                    // KDF_HMAC_KEY
122             KdfTlsLabel = 0x00000004,                   // KDF_TLS_PRF_LABEL
123             KdfTlsSeed = 0x00000005                     // KDF_TLS_PRF_SEED
124         }
125
126         /// <summary>
127         ///     Result codes from NCrypt APIs
128         /// </summary>
129         internal enum ErrorCode {
130             Success = 0,                                            // ERROR_SUCCESS
131             BadSignature = unchecked((int)0x80090006),              // NTE_BAD_SIGNATURE
132             NotFound = unchecked((int)0x80090011),                  // NTE_NOT_FOUND
133             KeyDoesNotExist = unchecked((int)0x80090016),           // NTE_BAD_KEYSET
134             BufferTooSmall = unchecked((int)0x80090028),             // NTE_BUFFER_TOO_SMALL
135             NoMoreItems = unchecked((int)0x8009002a)               // NTE_NO_MORE_ITEMS
136         }
137
138         /// <summary>
139         ///     Well known names of key properties
140         /// </summary>
141         internal static class KeyPropertyName {
142             internal const string Algorithm = "Algorithm Name";                 // NCRYPT_ALGORITHM_PROPERTY
143             internal const string AlgorithmGroup = "Algorithm Group";           // NCRYPT_ALGORITHM_GROUP_PROPERTY
144             internal const string ExportPolicy = "Export Policy";               // NCRYPT_EXPORT_POLICY_PROPERTY
145             internal const string KeyType = "Key Type";                         // NCRYPT_KEY_TYPE_PROPERTY
146             internal const string KeyUsage = "Key Usage";                       // NCRYPT_KEY_USAGE_PROPERTY
147             internal const string Length = "Length";                            // NCRYPT_LENGTH_PROPERTY
148             internal const string Name = "Name";                                // NCRYPT_NAME_PROPERTY
149             internal const string ParentWindowHandle = "HWND Handle";           // NCRYPT_WINDOW_HANDLE_PROPERTY
150             internal const string ProviderHandle = "Provider Handle";           // NCRYPT_PROVIDER_HANDLE_PROPERTY
151             internal const string UIPolicy = "UI Policy";                       // NCRYPT_UI_POLICY_PROPERTY
152             internal const string UniqueName = "Unique Name";                   // NCRYPT_UNIQUE_NAME_PROPERTY
153             internal const string UseContext = "Use Context";                   // NCRYPT_USE_CONTEXT_PROPERTY
154
155             //
156             // Properties defined by the CLR
157             //
158
159             /// <summary>
160             ///     Is the key a CLR created ephemeral key, it will contain a single byte with value 1 if the
161             ///     key was created by the CLR as an ephemeral key.
162             /// </summary>
163             internal const string ClrIsEphemeral = "CLR IsEphemeral";
164         }
165
166         /// <summary>
167         ///     Well known names of provider properties
168         /// </summary>
169         internal static class ProviderPropertyName {
170             internal const string Name = "Name";        // NCRYPT_NAME_PROPERTY
171         }
172
173         /// <summary>
174         ///     Flags for code:System.Security.Cryptography.NCryptNative.UnsafeNativeMethods.NCryptSecretAgreement
175         /// </summary>
176         [Flags]
177         internal enum SecretAgreementFlags {
178             None = 0x00000000,
179             UseSecretAsHmacKey = 0x00000001             // KDF_USE_SECRET_AS_HMAC_KEY_FLAG
180         }
181
182         //
183         // Structures
184         //
185
186         [StructLayout(LayoutKind.Sequential)]
187         internal struct NCRYPT_UI_POLICY {
188             public int dwVersion;
189             public CngUIProtectionLevels dwFlags;
190
191             [MarshalAs(UnmanagedType.LPWStr)]
192             public string pszCreationTitle;
193
194             [MarshalAs(UnmanagedType.LPWStr)]
195             public string pszFriendlyName;
196
197             [MarshalAs(UnmanagedType.LPWStr)]
198             public string pszDescription;
199         }
200
201         [StructLayout(LayoutKind.Sequential)]
202         internal struct NCryptBuffer {
203             public int cbBuffer;
204             public BufferType BufferType;
205             public IntPtr pvBuffer;
206         }
207
208         [StructLayout(LayoutKind.Sequential)]
209         internal struct NCryptBufferDesc {
210             public int ulVersion;
211             public int cBuffers;
212             public IntPtr pBuffers;         // NCryptBuffer[cBuffers]
213         }
214
215         [SuppressUnmanagedCodeSecurity]
216 #pragma warning disable 618 // System.Core.dll still uses SecurityRuleSet.Level1
217         [SecurityCritical(SecurityCriticalScope.Everything)]
218 #pragma warning restore 618
219         internal static class UnsafeNativeMethods {
220             /// <summary>
221             ///     Create an NCrypt key
222             /// </summary>
223             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
224             internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider,
225                                                                       [Out] out SafeNCryptKeyHandle phKey,
226                                                                       string pszAlgId,
227                                                                       string pszKeyName,
228                                                                       int dwLegacyKeySpec,
229                                                                       CngKeyCreationOptions dwFlags);
230
231             /// <summary>
232             ///     Delete a key
233             /// </summary>
234             [DllImport("ncrypt.dll")]
235             internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int flags);
236
237             /// <summary>
238             ///     Generate a key from a secret agreement
239             /// </summary>
240             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
241             internal static extern ErrorCode NCryptDeriveKey(SafeNCryptSecretHandle hSharedSecret,
242                                                              string pwszKDF,
243                                                              [In] ref NCryptBufferDesc pParameterList,
244                                                              [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbDerivedKey,
245                                                              int cbDerivedKey,
246                                                              [Out] out int pcbResult,
247                                                              SecretAgreementFlags dwFlags);
248
249             /// <summary>
250             ///     Export a key from the KSP
251             /// </summary>
252             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
253             internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey,
254                                                              IntPtr hExportKey,               // NCRYPT_KEY_HANDLE
255                                                              string pszBlobType,
256                                                              IntPtr pParameterList,           // NCryptBufferDesc *
257                                                              [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
258                                                              int cbOutput,
259                                                              [Out] out int pcbResult,
260                                                              int dwFlags);
261
262             /// <summary>
263             ///     Finalize a key to prepare it for use
264             /// </summary>
265             [DllImport("ncrypt.dll")]
266             internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags);
267
268             /// <summary>
269             ///     Get the value of a property of an NCrypt object
270             /// </summary>
271             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
272             internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
273                                                                string pszProperty,
274                                                                [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
275                                                                int cbOutput,
276                                                                [Out] out int pcbResult,
277                                                                CngPropertyOptions dwFlags);
278
279             /// <summary>
280             ///     Get the value of a pointer property of an NCrypt object
281             /// </summary>
282             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
283             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
284             internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
285                                                                string pszProperty,
286                                                                [Out] out IntPtr pbOutput,
287                                                                int cbOutput,
288                                                                [Out] out int pcbResult,
289                                                                CngPropertyOptions dwFlags);
290
291             /// <summary>
292             ///     Import a key into the KSP
293             /// </summary>
294             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
295             internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider,
296                                                              IntPtr hImportKey,     // NCRYPT_KEY_HANDLE
297                                                              string pszBlobType,
298                                                              IntPtr pParameterList, // NCryptBufferDesc *
299                                                              [Out] out SafeNCryptKeyHandle phKey,
300                                                              [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
301                                                              int cbData,
302                                                              int dwFlags);
303                                 
304             /// <summary>
305             ///     Open an existing key
306             /// </summary>
307             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
308             internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider,
309                                                            [Out] out SafeNCryptKeyHandle phKey,
310                                                            string pszKeyName,
311                                                            int dwLegacyKeySpec,
312                                                            CngKeyOpenOptions dwFlags);
313
314             /// <summary>
315             ///     Acquire a handle to a key storage provider
316             /// </summary>
317             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
318             internal static extern ErrorCode NCryptOpenStorageProvider([Out] out SafeNCryptProviderHandle phProvider,
319                                                                        string pszProviderName,
320                                                                        int dwFlags);
321
322             /// <summary>
323             ///     Generate a secret agreement for generating shared key material
324             /// </summary>
325             [DllImport("ncrypt.dll")]
326             internal static extern ErrorCode NCryptSecretAgreement(SafeNCryptKeyHandle hPrivKey,
327                                                                    SafeNCryptKeyHandle hPubKey,
328                                                                    [Out] out SafeNCryptSecretHandle phSecret,
329                                                                    int dwFlags);
330
331             /// <summary>
332             ///     Set a property value on an NCrypt object
333             /// </summary>
334             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
335             internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
336                                                                string pszProperty,
337                                                                [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
338                                                                int cbInput,
339                                                                CngPropertyOptions dwFlags);
340
341             /// <summary>
342             ///     Set a string property value on an NCrypt object
343             /// </summary>
344             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
345             internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
346                                                                string pszProperty,
347                                                                string pbInput,
348                                                                int cbInput,
349                                                                CngPropertyOptions dwFlags);
350
351             /// <summary>
352             ///     Set a property value on an NCrypt object when a pointer to the buffer already exists in
353             ///     managed code. To set a pointer valued property, use the ref IntPtr overload.
354             /// </summary>
355             [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
356             internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
357                                                                string pszProperty,
358                                                                IntPtr pbInput,
359                                                                int cbInput,
360                                                                CngPropertyOptions dwFlags);
361
362             /// <summary>
363             ///     Create a signature for a hash value
364             /// </summary>
365             [DllImport("ncrypt.dll")]
366             internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
367                                                             IntPtr pPaddingInfo,
368                                                             [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
369                                                             int cbHashValue,
370                                                             [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
371                                                             int cbSignature,
372                                                             [Out] out int pcbResult,
373                                                             int dwFlags);
374
375             /// <summary>
376             ///     Verify a signature over a hash value
377             /// </summary>
378             [DllImport("ncrypt.dll")]
379             internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
380                                                                    IntPtr pPaddingInfo,
381                                                                    [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
382                                                                    int cbHashValue,
383                                                                    [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
384                                                                    int cbSignature,
385                                                                    int dwFlags);
386
387             [DllImport("ncrypt.dll")]
388             internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
389                                                             [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
390                                                             [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
391                                                             int cbHashValue,
392                                                             [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
393                                                             int cbSignature,
394                                                             [Out] out int pcbResult,
395                                                             AsymmetricPaddingMode dwFlags);
396
397             [DllImport("ncrypt.dll")]
398             internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
399                                                             [In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
400                                                             [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
401                                                             int cbHashValue,
402                                                             [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
403                                                             int cbSignature,
404                                                             [Out] out int pcbResult,
405                                                             AsymmetricPaddingMode dwFlags);
406             [DllImport("ncrypt.dll")]
407             internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
408                                                                    [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
409                                                                    [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
410                                                                    int cbHashValue,
411                                                                    [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
412                                                                    int cbSignature,
413                                                                    AsymmetricPaddingMode dwFlags);
414
415             [DllImport("ncrypt.dll")]
416             internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
417                                                                    [In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
418                                                                    [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
419                                                                    int cbHashValue,
420                                                                    [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
421                                                                    int cbSignature,
422                                                                    AsymmetricPaddingMode dwFlags);
423
424             [DllImport("ncrypt.dll")]
425             internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
426                                                            [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
427                                                            int cbInput,
428                                                            [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
429                                                            [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
430                                                            int cbOutput,
431                                                            [Out] out int pcbResult,
432                                                            AsymmetricPaddingMode dwFlags);
433
434             [DllImport("ncrypt.dll")]
435             internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
436                                                            [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
437                                                            int cbInput,
438                                                            [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
439                                                            [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
440                                                            int cbOutput,
441                                                            [Out] out int pcbResult,
442                                                            AsymmetricPaddingMode dwFlags);
443
444             [DllImport("ncrypt.dll")]
445             internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
446                                                            [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
447                                                            int cbInput,
448                                                            [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
449                                                            [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
450                                                            int cbOutput,
451                                                            [Out] out int pcbResult,
452                                                            AsymmetricPaddingMode dwFlags);
453
454             [DllImport("ncrypt.dll")]
455             internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
456                                                            [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
457                                                            int cbInput,
458                                                            [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
459                                                            [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
460                                                            int cbOutput,
461                                                            [Out] out int pcbResult,
462                                                            AsymmetricPaddingMode dwFlags);
463         }
464
465
466         /// <summary>
467         ///     Adapter to wrap specific NCryptDecrypt P/Invokes with specific padding info
468         /// </summary>
469         [SecuritySafeCritical]
470         private delegate ErrorCode NCryptDecryptor<T>(SafeNCryptKeyHandle hKey,
471                                                       byte[] pbInput,
472                                                       int cbInput,
473                                                       ref T pvPadding,
474                                                       byte[] pbOutput,
475                                                       int cbOutput,
476                                                       out int pcbResult,
477                                                       AsymmetricPaddingMode dwFlags);
478
479         /// <summary>
480         ///     Adapter to wrap specific NCryptEncrypt P/Invokes with specific padding info
481         /// </summary>
482         [SecuritySafeCritical]
483         private delegate ErrorCode NCryptEncryptor<T>(SafeNCryptKeyHandle hKey,
484                                                       byte[] pbInput,
485                                                       int cbInput,
486                                                       ref T pvPadding,
487                                                       byte[] pbOutput,
488                                                       int cbOutput,
489                                                       out int pcbResult,
490                                                       AsymmetricPaddingMode dwFlags);
491
492         /// <summary>
493         ///     Adapter to wrap specific NCryptSignHash P/Invokes with a specific padding info
494         /// </summary>
495         [SecuritySafeCritical]
496         private delegate ErrorCode NCryptHashSigner<T>(SafeNCryptKeyHandle hKey,
497                                                        ref T pvPaddingInfo,
498                                                        byte[] pbHashValue,
499                                                        int cbHashValue,
500                                                        byte[] pbSignature,
501                                                        int cbSignature,
502                                                        out int pcbResult,
503                                                        AsymmetricPaddingMode dwFlags);
504
505         /// <summary>
506         ///     Adapter to wrap specific NCryptVerifySignature P/Invokes with a specific padding info
507         /// </summary>
508         [SecuritySafeCritical]
509         private delegate ErrorCode NCryptSignatureVerifier<T>(SafeNCryptKeyHandle hKey,
510                                                               ref T pvPaddingInfo,
511                                                               byte[] pbHashValue,
512                                                               int cbHashValue,
513                                                               byte[] pbSignature,
514                                                               int cbSignature,
515                                                               AsymmetricPaddingMode dwFlags) where T : struct;
516
517         //
518         // Utility and wrapper functions
519         //
520
521         private static volatile bool s_haveNcryptSupported;
522         private static volatile bool s_ncryptSupported;
523
524
525         /// <summary>
526         ///     Generic decryption method, wrapped by decryption calls for specific padding modes
527         /// </summary>
528         [SecuritySafeCritical]
529         private static byte[] DecryptData<T>(SafeNCryptKeyHandle key,
530                                              byte[] data,
531                                              ref T paddingInfo,
532                                              AsymmetricPaddingMode paddingMode,
533                                              NCryptDecryptor<T> decryptor) where T : struct {
534             Debug.Assert(key != null, "key != null");
535             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
536             Debug.Assert(data != null, "data != null");
537             Debug.Assert(decryptor != null, "decryptor != null");
538
539             // Figure out how big of a buffer is needed to store the decrypted data
540             int decryptedSize = 0;
541             ErrorCode error = decryptor(key,
542                                         data,
543                                         data.Length,
544                                         ref paddingInfo,
545                                         null,
546                                         0,
547                                         out decryptedSize,
548                                         paddingMode);
549             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
550                 throw new CryptographicException((int)error);
551             }
552
553             // Do the decryption
554             byte[] decrypted = new byte[decryptedSize];
555             error = decryptor(key,
556                               data,
557                               data.Length,
558                               ref paddingInfo,
559                               decrypted,
560                               decrypted.Length,
561                               out decryptedSize,
562                               paddingMode);
563             if (error != ErrorCode.Success) {
564                 throw new CryptographicException((int)error);
565             }
566
567             // Sometimes decryptedSize can be less than the allocated buffer size
568             // So resize the array to the actual returned plaintext 
569             Array.Resize(ref decrypted, decryptedSize);
570
571             return decrypted;
572         }
573
574         /// <summary>
575         ///     Decrypt data using PKCS1 padding
576         /// </summary>        
577         [SecuritySafeCritical]
578         internal static byte[] DecryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
579             BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
580
581             return DecryptData(key,
582                                data,
583                                ref pkcs1Info,
584                                AsymmetricPaddingMode.Pkcs1,
585                                UnsafeNativeMethods.NCryptDecrypt);
586         }
587
588         /// <summary>
589         ///     Decrypt data using OAEP padding
590         /// </summary>        
591         [SecuritySafeCritical]
592         internal static byte[] DecryptDataOaep(SafeNCryptKeyHandle key,
593                                                byte[] data,
594                                                string hashAlgorithm) {
595             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
596
597             BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
598             oaepInfo.pszAlgId = hashAlgorithm;
599
600             return DecryptData(key,
601                                data,
602                                ref oaepInfo,
603                                AsymmetricPaddingMode.Oaep,
604                                UnsafeNativeMethods.NCryptDecrypt);
605         }
606
607         /// <summary>
608         ///     Generic encryption method, wrapped by decryption calls for specific padding modes
609         /// </summary>        
610         [SecuritySafeCritical]
611         private static byte[] EncryptData<T>(SafeNCryptKeyHandle key,
612                                              byte[] data,
613                                              ref T paddingInfo,
614                                              AsymmetricPaddingMode paddingMode,
615                                              NCryptEncryptor<T> encryptor) where T : struct {
616             Debug.Assert(key != null, "key != null");
617             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
618             Debug.Assert(data != null, "data != null");
619             Debug.Assert(encryptor != null, "encryptor != null");
620
621             // Figure out how big of a buffer is to encrypt the data
622             int encryptedSize = 0;
623             ErrorCode error = encryptor(key,
624                                         data,
625                                         data.Length,
626                                         ref paddingInfo,
627                                         null,
628                                         0,
629                                         out encryptedSize,
630                                         paddingMode);
631             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
632                 throw new CryptographicException((int)error);
633             }
634
635             // Do the encryption
636             byte[] encrypted = new byte[encryptedSize];
637             error = encryptor(key,
638                               data,
639                               data.Length,
640                               ref paddingInfo,
641                               encrypted,
642                               encrypted.Length,
643                               out encryptedSize,
644                               paddingMode);
645             if (error != ErrorCode.Success) {
646                 throw new CryptographicException((int)error);
647             }
648
649             return encrypted;
650         }
651
652         /// <summary>
653         ///     Encrypt data using OAEP padding
654         /// </summary>        
655         [SecuritySafeCritical]
656         internal static byte[] EncryptDataOaep(SafeNCryptKeyHandle key,
657                                                byte[] data,
658                                                string hashAlgorithm) {
659             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
660
661             BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
662             oaepInfo.pszAlgId = hashAlgorithm;
663
664             return EncryptData(key,
665                                data,
666                                ref oaepInfo,
667                                AsymmetricPaddingMode.Oaep,
668                                UnsafeNativeMethods.NCryptEncrypt);
669         }
670
671         /// <summary>
672         ///     Encrypt data using PKCS1 padding
673         /// </summary>        
674         [SecuritySafeCritical]
675         internal static byte[] EncryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
676             BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
677
678             return EncryptData(key,
679                                data,
680                                ref pkcs1Info,
681                                AsymmetricPaddingMode.Pkcs1,
682                                UnsafeNativeMethods.NCryptEncrypt);
683         }
684
685         /// <summary>
686         ///     Generic signature method, wrapped by signature calls for specific padding modes
687         /// </summary>
688         [SecuritySafeCritical]
689         private static byte[] SignHash<T>(SafeNCryptKeyHandle key,
690                                           byte[] hash,
691                                           ref T paddingInfo,
692                                           AsymmetricPaddingMode paddingMode,
693                                           NCryptHashSigner<T> signer) where T : struct {
694             Debug.Assert(key != null, "key != null");
695             Debug.Assert(!key.IsInvalid && !key.IsClosed, "!key.IsInvalid && !key.IsClosed");
696             Debug.Assert(hash != null, "hash != null");
697             Debug.Assert(signer != null, "signer != null");
698
699             // Figure out how big the signature is
700             int signatureSize = 0;
701             ErrorCode error = signer(key,
702                                      ref paddingInfo,
703                                      hash,
704                                      hash.Length,
705                                      null,
706                                      0,
707                                      out signatureSize,
708                                      paddingMode);
709             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
710                 throw new CryptographicException((int)error);
711             }
712
713             // Sign the hash
714             byte[] signature = new byte[signatureSize];
715             error = signer(key,
716                            ref paddingInfo,
717                            hash,
718                            hash.Length,
719                            signature,
720                            signature.Length,
721                            out signatureSize,
722                            paddingMode);
723             if (error != ErrorCode.Success) {
724                 throw new CryptographicException((int)error);
725             }
726             return signature;
727         }
728
729         /// <summary>
730         ///     Sign a hash, using PKCS1 padding
731         /// </summary>
732         [SecuritySafeCritical]
733         internal static byte[] SignHashPkcs1(SafeNCryptKeyHandle key,
734                                              byte[] hash,
735                                              string hashAlgorithm) {
736             Debug.Assert(key != null, "key != null");
737             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
738             Debug.Assert(hash != null, "hash != null");
739             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
740
741             BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
742             pkcs1Info.pszAlgId = hashAlgorithm;
743
744             return SignHash(key,
745                             hash,
746                             ref pkcs1Info,
747                             AsymmetricPaddingMode.Pkcs1,
748                             UnsafeNativeMethods.NCryptSignHash);
749         }
750
751         /// <summary>
752         ///     Sign a hash, using PSS padding
753         /// </summary>
754         [SecuritySafeCritical]
755         internal static byte[] SignHashPss(SafeNCryptKeyHandle key,
756                                            byte[] hash,
757                                            string hashAlgorithm,
758                                            int saltBytes) {
759             Debug.Assert(key != null, "key != null");
760             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
761             Debug.Assert(hash != null, "hash != null");
762             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
763             Debug.Assert(saltBytes >= 0, "saltBytes >= 0");
764
765             BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
766             pssInfo.pszAlgId = hashAlgorithm;
767             pssInfo.cbSalt = saltBytes;
768
769             return SignHash(key,
770                             hash,
771                             ref pssInfo,
772                             AsymmetricPaddingMode.Pss,
773                             UnsafeNativeMethods.NCryptSignHash);
774         }
775
776         /// <summary>
777         ///     Generic signature verification method, wrapped by verification calls for specific padding modes
778         /// </summary>        
779         [SecuritySafeCritical]
780         private static bool VerifySignature<T>(SafeNCryptKeyHandle key,
781                                                byte[] hash,
782                                                byte[] signature,
783                                                ref T paddingInfo,
784                                                AsymmetricPaddingMode paddingMode,
785                                                NCryptSignatureVerifier<T> verifier) where T : struct {
786             Debug.Assert(key != null, "key != null");
787             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
788             Debug.Assert(hash != null, "hash != null");
789             Debug.Assert(signature != null, "signature != null");
790             Debug.Assert(verifier != null, "verifier != null");
791
792             ErrorCode error = verifier(key,
793                                        ref paddingInfo,
794                                        hash,
795                                        hash.Length,
796                                        signature,
797                                        signature.Length,
798                                        paddingMode);
799             if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
800                 throw new CryptographicException((int)error);
801             }
802
803             return error == ErrorCode.Success;
804         }
805
806         /// <summary>
807         ///     Verify the signature of a hash using PKCS #1 padding
808         /// </summary>        
809         [SecuritySafeCritical]
810         internal static bool VerifySignaturePkcs1(SafeNCryptKeyHandle key,
811                                                   byte[] hash,
812                                                   string hashAlgorithm,
813                                                   byte[] signature) {
814             Debug.Assert(key != null, "key != null");
815             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
816             Debug.Assert(hash != null, "hash != null");
817             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
818             Debug.Assert(signature != null, "signature != null");
819
820             BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
821             pkcs1Info.pszAlgId = hashAlgorithm;
822
823             return VerifySignature(key,
824                                    hash,
825                                    signature,
826                                    ref pkcs1Info,
827                                    AsymmetricPaddingMode.Pkcs1,
828                                    UnsafeNativeMethods.NCryptVerifySignature);
829         }
830
831         /// <summary>
832         ///     Verify the signature of a hash using PSS padding
833         /// </summary>        
834         [SecuritySafeCritical]
835         internal static bool VerifySignaturePss(SafeNCryptKeyHandle key,
836                                                 byte[] hash,
837                                                 string hashAlgorithm,
838                                                 int saltBytes,
839                                                 byte[] signature) {
840             Debug.Assert(key != null, "key != null");
841             Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
842             Debug.Assert(hash != null, "hash != null");
843             Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
844             Debug.Assert(signature != null, "signature != null");
845
846             BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
847             pssInfo.pszAlgId = hashAlgorithm;
848             pssInfo.cbSalt = saltBytes;
849
850             return VerifySignature(key,
851                                    hash,
852                                    signature,
853                                    ref pssInfo,
854                                    AsymmetricPaddingMode.Pss,
855                                    UnsafeNativeMethods.NCryptVerifySignature);
856         }
857
858         /// <summary>
859         ///     Determine if NCrypt is supported on the current machine
860         /// </summary>
861         internal static bool NCryptSupported {
862             [SecuritySafeCritical]
863             [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
864             get {
865                 if (!s_haveNcryptSupported)
866                 {
867                     // Attempt to load ncrypt.dll to see if the NCrypt CNG APIs are available on the machine
868                     using (SafeLibraryHandle ncrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("ncrypt", IntPtr.Zero, 0)) {
869                         s_ncryptSupported = !ncrypt.IsInvalid;
870                         s_haveNcryptSupported = true;
871                     }
872                 }
873
874                 return s_ncryptSupported;
875             }
876         }
877
878         /// <summary>
879         ///     Build an ECC public key blob to represent the given parameters
880         /// </summary>
881         internal static byte[] BuildEccPublicBlob(string algorithm, BigInteger x, BigInteger y) {
882             Contract.Requires(!String.IsNullOrEmpty(algorithm));
883             Contract.Ensures(Contract.Result<byte[]>() != null);
884
885             //
886             // #ECCPublicBlobFormat
887             // The ECC public key blob format is as follows:
888             //
889             // DWORD dwMagic
890             // DWORD cbKey
891             // X parameter (cbKey bytes long, byte-reversed)
892             // Y parameter (cbKey bytes long, byte-reversed)
893             //
894
895             // First map the algorithm name to its magic number and key size
896             BCryptNative.KeyBlobMagicNumber algorithmMagic;
897             int keySize;
898             BCryptNative.MapAlgorithmIdToMagic(algorithm, out algorithmMagic, out keySize);
899
900             // Next generate the public key parameters
901             byte[] xBytes = ReverseBytes(FillKeyParameter(x.ToByteArray(), keySize));
902             byte[] yBytes = ReverseBytes(FillKeyParameter(y.ToByteArray(), keySize));
903
904             // Finally, lay out the structure itself
905             byte[] blob = new byte[2 * sizeof(int) + xBytes.Length + yBytes.Length];
906             Buffer.BlockCopy(BitConverter.GetBytes((int)algorithmMagic), 0, blob, 0, sizeof(int));
907             Buffer.BlockCopy(BitConverter.GetBytes(xBytes.Length), 0, blob, sizeof(int), sizeof(int));
908             Buffer.BlockCopy(xBytes, 0, blob, 2 * sizeof(int), xBytes.Length);
909             Buffer.BlockCopy(yBytes, 0, blob, 2 * sizeof(int) + xBytes.Length, yBytes.Length);
910
911             return blob;
912         }
913
914         /// <summary>
915         ///     Create a random CNG key
916         /// </summary>
917         [System.Security.SecurityCritical]
918         internal static SafeNCryptKeyHandle CreatePersistedKey(SafeNCryptProviderHandle provider,
919                                                                string algorithm,
920                                                                string name,
921                                                                CngKeyCreationOptions options) {
922             Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed);
923             Contract.Requires(!String.IsNullOrEmpty(algorithm));
924             Contract.Ensures(Contract.Result<SafeNCryptKeyHandle>() != null &&
925                              !Contract.Result<SafeNCryptKeyHandle>().IsInvalid &&
926                              !Contract.Result<SafeNCryptKeyHandle>().IsClosed);
927
928             SafeNCryptKeyHandle keyHandle = null;
929             ErrorCode error = UnsafeNativeMethods.NCryptCreatePersistedKey(provider,
930                                                                            out keyHandle,
931                                                                            algorithm,
932                                                                            name,
933                                                                            0,
934                                                                            options);
935             if (error != ErrorCode.Success) {
936                 throw new CryptographicException((int)error);
937             }
938
939             return keyHandle;
940         }
941
942         /// <summary>
943         ///     Delete a key
944         /// </summary>
945         [System.Security.SecurityCritical]
946         internal static void DeleteKey(SafeNCryptKeyHandle key) {
947             Contract.Requires(key != null);
948
949             ErrorCode error = UnsafeNativeMethods.NCryptDeleteKey(key, 0);
950             if (error != ErrorCode.Success) {
951                 throw new CryptographicException((int)error);
952             }
953             key.SetHandleAsInvalid();
954         }
955
956         /// <summary>
957         ///     Derive key material from a hash or HMAC KDF
958         /// </summary>
959         /// <returns></returns>
960         [System.Security.SecurityCritical]
961         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
962         private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
963                                                 string kdf,
964                                                 string hashAlgorithm,
965                                                 byte[] hmacKey,
966                                                 byte[] secretPrepend,
967                                                 byte[] secretAppend,
968                                                 SecretAgreementFlags flags) {
969             Contract.Requires(secretAgreement != null);
970             Contract.Requires(!String.IsNullOrEmpty(kdf));
971             Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
972             Contract.Requires(hmacKey == null || kdf == BCryptNative.KeyDerivationFunction.Hmac);
973             Contract.Ensures(Contract.Result<byte[]>() != null);
974
975             List<NCryptBuffer> parameters = new List<NCryptBuffer>();
976
977             // First marshal the hash algoritm
978             IntPtr hashAlgorithmString = IntPtr.Zero;
979
980             // Run in a CER so that we know we'll free the memory for the marshaled string
981             RuntimeHelpers.PrepareConstrainedRegions();
982             try {
983                 // Assign in a CER so we don't fail between allocating the memory and assigning the result
984                 // back to the string variable.
985                 RuntimeHelpers.PrepareConstrainedRegions();
986                 try { }
987                 finally {
988                     hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm);
989                 }
990
991                 // We always need to marshal the hashing function
992                 NCryptBuffer hashAlgorithmBuffer = new NCryptBuffer();
993                 hashAlgorithmBuffer.cbBuffer = (hashAlgorithm.Length + 1) * sizeof(char);
994                 hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm;
995                 hashAlgorithmBuffer.pvBuffer = hashAlgorithmString;
996                 parameters.Add(hashAlgorithmBuffer);
997
998                 unsafe {
999                     fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend) {
1000                         //
1001                         // Now marshal the other parameters
1002                         //
1003
1004                         if (pHmacKey != null) {
1005                             NCryptBuffer hmacKeyBuffer = new NCryptBuffer();
1006                             hmacKeyBuffer.cbBuffer = hmacKey.Length;
1007                             hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
1008                             hmacKeyBuffer.pvBuffer = new IntPtr(pHmacKey);
1009                             parameters.Add(hmacKeyBuffer);
1010                         }
1011
1012                         if (pSecretPrepend != null) {
1013                             NCryptBuffer secretPrependBuffer = new NCryptBuffer();
1014                             secretPrependBuffer.cbBuffer = secretPrepend.Length;
1015                             secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend;
1016                             secretPrependBuffer.pvBuffer = new IntPtr(pSecretPrepend);
1017                             parameters.Add(secretPrependBuffer);
1018                         }
1019
1020                         if (pSecretAppend != null) {
1021                             NCryptBuffer secretAppendBuffer = new NCryptBuffer();
1022                             secretAppendBuffer.cbBuffer = secretAppend.Length;
1023                             secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
1024                             secretAppendBuffer.pvBuffer = new IntPtr(pSecretAppend);
1025                             parameters.Add(secretAppendBuffer);
1026                         }
1027
1028                         return DeriveKeyMaterial(secretAgreement,
1029                                                  kdf,
1030                                                  parameters.ToArray(),
1031                                                  flags);
1032                     }
1033                 }
1034             }
1035             finally {
1036                 if (hashAlgorithmString != IntPtr.Zero) {
1037                     Marshal.FreeCoTaskMem(hashAlgorithmString);
1038                 }
1039             }
1040         }
1041
1042         /// <summary>
1043         ///     Derive key material using a given KDF and secret agreement
1044         /// </summary>
1045         [System.Security.SecurityCritical]
1046         private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
1047                                                 string kdf,
1048                                                 NCryptBuffer[] parameters,
1049                                                 SecretAgreementFlags flags) {
1050             Contract.Requires(secretAgreement != null);
1051             Contract.Requires(!String.IsNullOrEmpty(kdf));
1052             Contract.Requires(parameters != null);
1053             Contract.Ensures(Contract.Result<byte[]>() != null);
1054
1055             unsafe {
1056                 fixed (NCryptBuffer* pParameters = parameters) {
1057                     NCryptBufferDesc parameterDesc = new NCryptBufferDesc();
1058                     parameterDesc.ulVersion = 0;
1059                     parameterDesc.cBuffers = parameters.Length;
1060                     parameterDesc.pBuffers = new IntPtr(pParameters);
1061
1062                     // Figure out how big the key material is
1063                     int keySize = 0;
1064                     ErrorCode error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1065                                                                           kdf,
1066                                                                           ref parameterDesc,
1067                                                                           null,
1068                                                                           0,
1069                                                                           out keySize,
1070                                                                           flags);
1071                     if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1072                         throw new CryptographicException((int)error);
1073                     }
1074
1075                     // Allocate memory for the key material and generate it
1076                     byte[] keyMaterial = new byte[keySize];
1077                     error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1078                                                                 kdf,
1079                                                                 ref parameterDesc,
1080                                                                 keyMaterial,
1081                                                                 keyMaterial.Length,
1082                                                                 out keySize,
1083                                                                 flags);
1084
1085                     if (error != ErrorCode.Success) {
1086                         throw new CryptographicException((int)error);
1087                     }
1088
1089                     return keyMaterial;
1090                 }
1091             }
1092         }
1093
1094         /// <summary>
1095         ///     Derive key material from a secret agreement using a hash KDF
1096         /// </summary>
1097         [System.Security.SecurityCritical]
1098         internal static byte[] DeriveKeyMaterialHash(SafeNCryptSecretHandle secretAgreement,
1099                                                      string hashAlgorithm,
1100                                                      byte[] secretPrepend,
1101                                                      byte[] secretAppend,
1102                                                      SecretAgreementFlags flags) {
1103             Contract.Requires(secretAgreement != null);
1104             Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
1105             Contract.Ensures(Contract.Result<byte[]>() != null);
1106
1107             return DeriveKeyMaterial(secretAgreement,
1108                                      BCryptNative.KeyDerivationFunction.Hash,
1109                                      hashAlgorithm,
1110                                      null,
1111                                      secretPrepend,
1112                                      secretAppend,
1113                                      flags);
1114         }
1115
1116         /// <summary>
1117         ///     Derive key material from a secret agreement using a HMAC KDF
1118         /// </summary>
1119         [System.Security.SecurityCritical]
1120         internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement,
1121                                                      string hashAlgorithm,
1122                                                      byte[] hmacKey,
1123                                                      byte[] secretPrepend,
1124                                                      byte[] secretAppend,
1125                                                      SecretAgreementFlags flags) {
1126             Contract.Requires(secretAgreement != null);
1127             Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
1128             Contract.Ensures(Contract.Result<byte[]>() != null);
1129
1130             return DeriveKeyMaterial(secretAgreement,
1131                                      BCryptNative.KeyDerivationFunction.Hmac,
1132                                      hashAlgorithm,
1133                                      hmacKey,
1134                                      secretPrepend,
1135                                      secretAppend,
1136                                      flags);
1137         }
1138
1139         /// <summary>
1140         ///     Derive key material from a secret agreeement using the TLS KDF
1141         /// </summary>
1142         [System.Security.SecurityCritical]
1143         internal static byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement,
1144                                                     byte[] label,
1145                                                     byte[] seed,
1146                                                     SecretAgreementFlags flags) {
1147             Contract.Requires(secretAgreement != null);
1148             Contract.Requires(label != null && seed != null);
1149             Contract.Ensures(Contract.Result<byte[]>() != null);
1150
1151             NCryptBuffer[] buffers = new NCryptBuffer[2];
1152
1153             unsafe {
1154                 fixed (byte* pLabel = label, pSeed = seed) {
1155                     NCryptBuffer labelBuffer = new NCryptBuffer();
1156                     labelBuffer.cbBuffer = label.Length;
1157                     labelBuffer.BufferType = BufferType.KdfTlsLabel;
1158                     labelBuffer.pvBuffer = new IntPtr(pLabel);
1159                     buffers[0] = labelBuffer;
1160
1161                     NCryptBuffer seedBuffer = new NCryptBuffer();
1162                     seedBuffer.cbBuffer = seed.Length;
1163                     seedBuffer.BufferType = BufferType.KdfTlsSeed;
1164                     seedBuffer.pvBuffer = new IntPtr(pSeed);
1165                     buffers[1] = seedBuffer;
1166
1167                     return DeriveKeyMaterial(secretAgreement,
1168                                              BCryptNative.KeyDerivationFunction.Tls,
1169                                              buffers,
1170                                              flags);
1171                 }
1172             }
1173         }
1174
1175         /// <summary>
1176         ///     Generate a secret agreement value for between two parties
1177         /// </summary>
1178         [System.Security.SecurityCritical]
1179         internal static SafeNCryptSecretHandle DeriveSecretAgreement(SafeNCryptKeyHandle privateKey,
1180                                                                      SafeNCryptKeyHandle otherPartyPublicKey) {
1181             Contract.Requires(privateKey != null);
1182             Contract.Requires(otherPartyPublicKey != null);
1183             Contract.Ensures(Contract.Result<SafeNCryptSecretHandle>() != null &&
1184                              !Contract.Result<SafeNCryptSecretHandle>().IsClosed &&
1185                              !Contract.Result<SafeNCryptSecretHandle>().IsInvalid);
1186
1187             SafeNCryptSecretHandle secretAgreement;
1188             ErrorCode error = UnsafeNativeMethods.NCryptSecretAgreement(privateKey,
1189                                                                         otherPartyPublicKey,
1190                                                                         out secretAgreement,
1191                                                                         0);
1192
1193             if (error != ErrorCode.Success) {
1194                 throw new CryptographicException((int)error);
1195             }
1196
1197             return secretAgreement;
1198         }
1199
1200         /// <summary>
1201         ///     Export a key from the KSP
1202         /// </summary>
1203         [System.Security.SecurityCritical]
1204         internal static byte[] ExportKey(SafeNCryptKeyHandle key, string format) {
1205             Contract.Requires(key != null);
1206             Contract.Requires(!String.IsNullOrEmpty(format));
1207             Contract.Ensures(Contract.Result<byte[]>() != null);
1208
1209             // Figure out how big of a buffer we need to export into
1210             int bufferSize = 0;
1211             ErrorCode error = UnsafeNativeMethods.NCryptExportKey(key,
1212                                                                   IntPtr.Zero,
1213                                                                   format,
1214                                                                   IntPtr.Zero,
1215                                                                   null,
1216                                                                   0,
1217                                                                   out bufferSize,
1218                                                                   0);
1219
1220             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1221                 throw new CryptographicException((int)error);
1222             }
1223
1224             // Export the key
1225             Debug.Assert(bufferSize > 0, "bufferSize > 0");
1226             byte[] keyBlob = new byte[bufferSize];
1227             error = UnsafeNativeMethods.NCryptExportKey(key,
1228                                                         IntPtr.Zero,
1229                                                         format,
1230                                                         IntPtr.Zero,
1231                                                         keyBlob,
1232                                                         keyBlob.Length,
1233                                                         out bufferSize,
1234                                                         0);
1235
1236             if (error != ErrorCode.Success) {
1237                 throw new CryptographicException((int)error);
1238             }
1239
1240             return keyBlob;
1241         }
1242
1243         /// <summary>
1244         ///     Make sure that a key is padded out to be its full size
1245         /// </summary>
1246         private static byte[] FillKeyParameter(byte[] key, int keySize) {
1247             Contract.Requires(key != null);
1248             Contract.Requires(keySize > 0);
1249             Contract.Ensures(Contract.Result<byte[]>() != null && Contract.Result<byte[]>().Length >= keySize / 8);
1250
1251             int bytesRequired = (keySize / 8) + (keySize % 8 == 0 ? 0 : 1);
1252             if (key.Length == bytesRequired) {
1253                 return key;
1254             }
1255
1256 #if DEBUG
1257             // If the key is longer than required, it should have been padded out with zeros
1258             if (key.Length > bytesRequired) {
1259                 for (int i = bytesRequired; i < key.Length; i++) {
1260                     Debug.Assert(key[i] == 0, "key[i] == 0");
1261                 }
1262             }
1263 #endif
1264             byte[] fullKey = new byte[bytesRequired];
1265             Buffer.BlockCopy(key, 0, fullKey, 0, Math.Min(key.Length, fullKey.Length));
1266             return fullKey;
1267         }
1268
1269         /// <summary>
1270         ///     Finalize a key and prepare it for use
1271         /// </summary>
1272         [System.Security.SecurityCritical]
1273         internal static void FinalizeKey(SafeNCryptKeyHandle key) {
1274             Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
1275
1276             ErrorCode error = UnsafeNativeMethods.NCryptFinalizeKey(key, 0);
1277             if (error != ErrorCode.Success) {
1278                 throw new CryptographicException((int)error);
1279             }
1280         }
1281
1282         /// <summary>
1283         ///     Get the value of an NCrypt property
1284         /// </summary>
1285         [System.Security.SecurityCritical]
1286         internal static byte[] GetProperty(SafeNCryptHandle ncryptObject,
1287                                            string propertyName,
1288                                            CngPropertyOptions propertyOptions,
1289                                            out bool foundProperty) {
1290             Contract.Requires(ncryptObject != null);
1291             Contract.Requires(propertyName != null);
1292
1293             // Find out how big of a buffer we need to store the property in
1294             int bufferSize = 0;
1295             ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1296                                                                     propertyName,
1297                                                                     null,
1298                                                                     0,
1299                                                                     out bufferSize,
1300                                                                     propertyOptions);
1301
1302             //
1303             // NTE_NOT_FOUND means this property does not exist, any other error besides NTE_BUFFER_TOO_SMALL
1304             // indicates a real problem.
1305             //
1306
1307             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall && error != ErrorCode.NotFound) {
1308                     throw new CryptographicException((int)error);
1309             }
1310
1311             foundProperty = error != ErrorCode.NotFound;
1312
1313             // Pull back the property value
1314             byte[] value = null;
1315             if (error != ErrorCode.NotFound && bufferSize > 0) {
1316                 value = new byte[bufferSize];
1317                 error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1318                                                               propertyName,
1319                                                               value,
1320                                                               value.Length,
1321                                                               out bufferSize,
1322                                                               propertyOptions);
1323                 if (error != ErrorCode.Success) {
1324                     throw new CryptographicException((int)error);
1325                 }
1326
1327                 foundProperty = true;
1328             }
1329
1330             return value;
1331         }
1332
1333         /// <summary>
1334         ///     Get the value of a DWORD NCrypt property
1335         /// </summary>
1336         [System.Security.SecurityCritical]
1337         internal static int GetPropertyAsDWord(SafeNCryptHandle ncryptObject,
1338                                                string propertyName,
1339                                                CngPropertyOptions propertyOptions) {
1340             Contract.Requires(ncryptObject != null);
1341             Contract.Requires(propertyName != null);
1342
1343             bool foundProperty;
1344             byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1345
1346             if (!foundProperty || valueBytes == null) {
1347                 return 0;
1348             }
1349             else {
1350                 return BitConverter.ToInt32(valueBytes, 0);
1351             }
1352         }
1353
1354         /// <summary>
1355         ///     Get the value of a pointer NCrypt property
1356         /// </summary>
1357         [System.Security.SecurityCritical]
1358         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
1359         internal static IntPtr GetPropertyAsIntPtr(SafeNCryptHandle ncryptObject,
1360                                                    string propertyName,
1361                                                    CngPropertyOptions propertyOptions) {
1362             Contract.Requires(ncryptObject != null);
1363             Contract.Requires(propertyName != null);
1364
1365             // Find out how big of a buffer we need to store the property in
1366             int bufferSize = IntPtr.Size;
1367             IntPtr value = IntPtr.Zero;
1368             ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1369                                                                     propertyName,
1370                                                                     out value,
1371                                                                     IntPtr.Size,
1372                                                                     out bufferSize,
1373                                                                     propertyOptions);
1374
1375             // NTE_NOT_FOUND means this property was not set, so return a NULL pointer
1376             if (error == ErrorCode.NotFound) {
1377                 return IntPtr.Zero;
1378             }
1379
1380             if (error != ErrorCode.Success) {
1381                 throw new CryptographicException((int)error);
1382             }
1383
1384             return value;
1385         }
1386
1387         /// <summary>
1388         ///     Get the value of a string NCrypt property
1389         /// </summary>
1390         [System.Security.SecurityCritical]
1391         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
1392         internal static string GetPropertyAsString(SafeNCryptHandle ncryptObject,
1393                                                    string propertyName,
1394                                                    CngPropertyOptions propertyOptions) {
1395             Contract.Requires(ncryptObject != null);
1396             Contract.Requires(propertyName != null);
1397
1398             bool foundProperty;
1399             byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1400
1401             if (!foundProperty || valueBytes == null) {
1402                 return null;
1403             }
1404             else if (valueBytes.Length == 0) {
1405                 return String.Empty;
1406             }
1407             else {
1408                 unsafe {
1409                     fixed (byte* pValueBytes = valueBytes) {
1410                         return Marshal.PtrToStringUni(new IntPtr(pValueBytes));
1411                     }
1412                 }
1413             }
1414         }
1415
1416         /// <summary>
1417         ///     Get the value of an NCrypt structure property -- this will return an empty structure if the
1418         ///     property does not exist.
1419         /// </summary>
1420         [System.Security.SecurityCritical]
1421         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
1422         internal static T GetPropertyAsStruct<T>(SafeNCryptHandle ncryptObject,
1423                                                  string propertyName,
1424                                                  CngPropertyOptions propertyOptions) where T : struct {
1425             Contract.Requires(ncryptObject != null);
1426             Contract.Requires(propertyName != null);
1427
1428             bool foundProperty;
1429             byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1430
1431             if (!foundProperty || valueBytes == null) {
1432                 return new T();
1433             }
1434
1435             unsafe {
1436                 fixed (byte *pValue = valueBytes) {
1437                     return (T)Marshal.PtrToStructure(new IntPtr(pValue), typeof(T));
1438                 }
1439             }
1440         }
1441
1442         /// <summary>
1443         ///     Import a key into the KSP
1444         /// </summary>
1445         [System.Security.SecurityCritical]
1446         internal static SafeNCryptKeyHandle ImportKey(SafeNCryptProviderHandle provider,
1447                                                       byte[] keyBlob,
1448                                                       string format) {
1449             Contract.Requires(provider != null);
1450             Contract.Requires(keyBlob != null);
1451             Contract.Requires(!String.IsNullOrEmpty(format));
1452             Contract.Ensures(Contract.Result<SafeNCryptKeyHandle>() != null &&
1453                              !Contract.Result<SafeNCryptKeyHandle>().IsInvalid &&
1454                              !Contract.Result<SafeNCryptKeyHandle>().IsClosed);
1455
1456             SafeNCryptKeyHandle keyHandle = null;
1457             ErrorCode error = UnsafeNativeMethods.NCryptImportKey(provider,
1458                                                                   IntPtr.Zero,
1459                                                                   format,
1460                                                                   IntPtr.Zero,
1461                                                                   out keyHandle,
1462                                                                   keyBlob,
1463                                                                   keyBlob.Length,
1464                                                                   0);
1465
1466             if (error != ErrorCode.Success) {
1467                 throw new CryptographicException((int)error);
1468             }
1469
1470             return keyHandle;
1471         }
1472
1473         /// <summary>
1474         ///     Open an existing key
1475         /// </summary>
1476         [System.Security.SecurityCritical]
1477         internal static SafeNCryptKeyHandle OpenKey(SafeNCryptProviderHandle provider,
1478                                                     string name,
1479                                                     CngKeyOpenOptions options) {
1480             Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed);
1481             Contract.Requires(name != null);
1482
1483             SafeNCryptKeyHandle key = null;
1484             ErrorCode error = UnsafeNativeMethods.NCryptOpenKey(provider, out key, name, 0, options);
1485
1486             if (error != ErrorCode.Success) {
1487                 throw new CryptographicException((int)error);
1488             }
1489
1490             return key;
1491         }
1492
1493         /// <summary>
1494         ///     Open the specified key storage provider
1495         /// </summary>
1496         [System.Security.SecurityCritical]
1497         internal static SafeNCryptProviderHandle OpenStorageProvider(string providerName) {
1498             Contract.Requires(!String.IsNullOrEmpty(providerName));
1499             Contract.Ensures(Contract.Result<SafeNCryptProviderHandle>() != null &&
1500                              !Contract.Result<SafeNCryptProviderHandle>().IsInvalid &&
1501                              !Contract.Result<SafeNCryptProviderHandle>().IsClosed);
1502
1503             SafeNCryptProviderHandle providerHandle = null;
1504             ErrorCode error = UnsafeNativeMethods.NCryptOpenStorageProvider(out providerHandle,
1505                                                                             providerName,
1506                                                                             0);
1507
1508             if (error != ErrorCode.Success) {
1509                 throw new CryptographicException((int)error);
1510             }
1511
1512             return providerHandle;
1513         }
1514
1515         /// <summary>
1516         ///     Reverse the bytes in a buffer
1517         /// </summary>
1518         private static byte[] ReverseBytes(byte[] buffer) {
1519             Contract.Requires(buffer != null);
1520             Contract.Ensures(Contract.Result<byte[]>() != null && Contract.Result<byte[]>().Length == buffer.Length);
1521             return ReverseBytes(buffer, 0, buffer.Length, false);
1522         }
1523
1524         /// <summary>
1525         ///     Reverse a section of bytes within a buffer
1526         /// </summary>
1527         private static byte[] ReverseBytes(byte[] buffer, int offset, int count) {
1528             return ReverseBytes(buffer, offset, count, false);
1529         }
1530         
1531         private static byte[] ReverseBytes(byte[] buffer, int offset, int count, bool padWithZeroByte) {
1532             Contract.Requires(buffer != null);
1533             Contract.Requires(offset >= 0 && offset < buffer.Length);
1534             Contract.Requires(count >= 0 && buffer.Length - count >= offset);
1535             Contract.Ensures(Contract.Result<byte[]>() != null);
1536             Contract.Ensures(Contract.Result<byte[]>().Length == (padWithZeroByte ? count + 1 : count));
1537             Contract.Ensures(padWithZeroByte ? Contract.Result<byte[]>()[count] == 0 : true);
1538
1539             byte[] reversed;
1540             if(padWithZeroByte)
1541             {
1542                 reversed = new byte[count+1]; // the last (most-significant) byte will be left as 0x00
1543             }
1544             else
1545             {
1546                 reversed = new byte[count];
1547             }
1548
1549             int lastByte = offset + count - 1;
1550             for (int i = 0; i < count; i++) {
1551                 reversed[i] = buffer[lastByte - i];
1552             }
1553
1554             return reversed;
1555         }
1556
1557         /// <summary>
1558         ///     Set a DWORD property on an NCrypt object
1559         /// </summary>
1560         [System.Security.SecurityCritical]
1561         internal static void SetProperty(SafeNCryptHandle ncryptObject,
1562                                          string propertyName,
1563                                          int value,
1564                                          CngPropertyOptions propertyOptions) {
1565             Contract.Requires(ncryptObject != null);
1566             Contract.Requires(propertyName != null);
1567
1568             SetProperty(ncryptObject, propertyName, BitConverter.GetBytes(value), propertyOptions);
1569         }
1570
1571         /// <summary>
1572         ///     Set a string property
1573         /// </summary>
1574         [System.Security.SecurityCritical]
1575         internal static void SetProperty(SafeNCryptHandle ncryptObject,
1576                                          string propertyName,
1577                                          string value,
1578                                          CngPropertyOptions propertyOptions) {
1579             Contract.Requires(ncryptObject != null);
1580             Contract.Requires(propertyName != null);
1581
1582             ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1583                                                                     propertyName,
1584                                                                     value,
1585                                                                     (value.Length + 1) * sizeof(char),
1586                                                                     propertyOptions);
1587
1588             if (error != ErrorCode.Success) {
1589                 throw new CryptographicException((int)error);
1590             }
1591         }
1592
1593         /// <summary>
1594         ///     Set a structure property
1595         /// </summary>
1596         [System.Security.SecurityCritical]
1597         internal static void SetProperty<T>(SafeNCryptHandle ncryptObject,
1598                                             string propertyName,
1599                                             T value,
1600                                             CngPropertyOptions propertyOptions) where T : struct {
1601             Contract.Requires(ncryptObject != null);
1602             Contract.Requires(propertyName != null);
1603
1604             byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
1605            
1606             unsafe {
1607                 fixed (byte *pBuffer = buffer) {
1608
1609                     bool marshaledStructure = false;
1610                     RuntimeHelpers.PrepareConstrainedRegions();
1611                     try {
1612                         // If we successfully marshal into the buffer, make sure to destroy the buffer when we're done
1613                         RuntimeHelpers.PrepareConstrainedRegions();
1614                         try { }
1615                         finally {
1616                             Marshal.StructureToPtr(value, new IntPtr(pBuffer), false);
1617                             marshaledStructure = true;
1618                         }
1619
1620                         SetProperty(ncryptObject, propertyName, buffer, propertyOptions);
1621                     }
1622                     finally {
1623                         if (marshaledStructure) {
1624                             Marshal.DestroyStructure(new IntPtr(pBuffer), typeof(T));
1625                         }
1626                     }
1627                 }
1628             }
1629         }
1630
1631         /// <summary>
1632         ///     Set a property on an NCrypt object
1633         /// </summary>
1634         [System.Security.SecurityCritical]
1635         internal static void SetProperty(SafeNCryptHandle ncryptObject,
1636                                          string propertyName,
1637                                          byte[] value,
1638                                          CngPropertyOptions propertyOptions) {
1639             Contract.Requires(ncryptObject != null);
1640             Contract.Requires(propertyName != null);
1641
1642             ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1643                                                                     propertyName,
1644                                                                     value,
1645                                                                     value != null ? value.Length : 0,
1646                                                                     propertyOptions);
1647
1648             if (error != ErrorCode.Success) {
1649                 throw new CryptographicException((int)error);
1650             }
1651         }
1652
1653         /// <summary>
1654         ///     Sign a hash using no padding
1655         /// </summary>
1656         [System.Security.SecurityCritical]
1657         internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash) {
1658             Contract.Requires(key != null);
1659             Contract.Requires(hash != null);
1660             Contract.Ensures(Contract.Result<byte[]>() != null);
1661
1662             // Figure out how big the signature is
1663             int signatureSize = 0;
1664             ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
1665                                                                  IntPtr.Zero,
1666                                                                  hash,
1667                                                                  hash.Length,
1668                                                                  null,
1669                                                                  0,
1670                                                                  out signatureSize,
1671                                                                  0);
1672
1673             if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1674                 throw new CryptographicException((int)error);
1675             }
1676
1677             // Sign the data
1678             Debug.Assert(signatureSize > 0, "signatureSize > 0");
1679             byte[] signature = new byte[signatureSize];
1680
1681             error = UnsafeNativeMethods.NCryptSignHash(key,
1682                                                        IntPtr.Zero,
1683                                                        hash,
1684                                                        hash.Length,
1685                                                        signature,
1686                                                        signature.Length,
1687                                                        out signatureSize,
1688                                                        0);
1689
1690             if (error != ErrorCode.Success) {
1691                 throw new CryptographicException((int)error);
1692             }
1693
1694             return signature;
1695         }
1696
1697         /// <summary>
1698         ///     Unpack a key blob in ECC public blob format into its X and Y parameters
1699         /// 
1700         ///     This method expects that the blob be in the correct format -- blobs accepted from partially
1701         ///     trusted code need to be validated before being unpacked.
1702         /// </summary>
1703         internal static void UnpackEccPublicBlob(byte[] blob, out BigInteger x, out BigInteger y) {
1704             Contract.Requires(blob != null && blob.Length > 2 * sizeof(int));
1705
1706             //
1707             // See code:System.Security.Cryptography.NCryptNative#ECCPublicBlobFormat  for details about the
1708             // format of the ECC public key blob.
1709             //
1710
1711             // read the size of each parameter
1712             int parameterSize = BitConverter.ToInt32(blob, sizeof(int));
1713             Debug.Assert(parameterSize > 0, "parameterSize > 0");
1714             Debug.Assert(blob.Length >= 2 * sizeof(int) + 2 * parameterSize, "blob.Length >= 2 * sizeof(int) + 2 * parameterSize");
1715
1716             // read out the X and Y parameters, in memory reversed form
1717             // add 0x00 padding to force BigInteger to interpret these as positive numbers
1718             x = new BigInteger(ReverseBytes(blob, 2 * sizeof(int), parameterSize, true));
1719             y = new BigInteger(ReverseBytes(blob, 2 * sizeof(int) + parameterSize, parameterSize, true));
1720         }
1721
1722         /// <summary>
1723         ///     Verify a signature created with no padding
1724         /// </summary>
1725         [System.Security.SecurityCritical]
1726         internal static bool VerifySignature(SafeNCryptKeyHandle key, byte[] hash, byte[] signature) {
1727             Contract.Requires(key != null);
1728             Contract.Requires(hash != null);
1729             Contract.Requires(signature != null);
1730
1731             ErrorCode error = UnsafeNativeMethods.NCryptVerifySignature(key,
1732                                                                         IntPtr.Zero,
1733                                                                         hash,
1734                                                                         hash.Length,
1735                                                                         signature,
1736                                                                         signature.Length,
1737                                                                         0);
1738
1739             if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
1740                 throw new CryptographicException((int)error);
1741             }
1742
1743             return error == ErrorCode.Success;
1744         }
1745     }
1746 #endif
1747 }