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