3 // Copyright (c) Microsoft Corporation. All rights reserved.
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;
17 using System.Diagnostics.Contracts;
18 using Microsoft.Win32;
19 using Microsoft.Win32.SafeHandles;
21 namespace System.Security.Cryptography {
24 // Public facing enumerations
28 /// Flags to control how often and in which format a key is allowed to be exported
31 public enum CngExportPolicies {
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
40 /// Flags controlling how the key is created
43 public enum CngKeyCreationOptions {
45 MachineKey = 0x00000020, // NCRYPT_MACHINE_KEY_FLAG
46 OverwriteExistingKey = 0x00000080 // NCRYPT_OVERWRITE_KEY_FLAG
50 /// Flags controlling how a key is opened
53 [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Approved API exception to have an easy way to express user keys")]
54 public enum CngKeyOpenOptions {
57 MachineKey = 0x00000020, // NCRYPT_MACHINE_KEY_FLAG
58 Silent = 0x00000040 // NCRYPT_SILENT_FLAG
62 /// Flags indicating the type of key
65 internal enum CngKeyTypes {
67 MachineKey = 0x00000020 // NCRYPT_MACHINE_KEY_FLAG
71 /// Bits defining what operations are valid to use a key with
74 [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
75 public enum CngKeyUsages {
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
84 /// Options affecting how a property is interpreted by CNG
87 [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
88 public enum CngPropertyOptions {
90 CustomProperty = 0x40000000, // NCRYPT_PERSIST_ONLY_FLAG
91 Persist = unchecked((int)0x80000000) // NCRYPT_PERSIST_FLAG
95 /// Levels of UI protection available for a key
98 public enum CngUIProtectionLevels {
100 ProtectKey = 0x00000001, // NCRYPT_UI_PROTECT_KEY_FLAG
101 ForceHighProtection = 0x00000002 // NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG
105 /// Native interop with CNG's NCrypt layer. Native definitions are in ncrypt.h
107 internal static class NCryptNative {
113 /// Types of NCryptBuffers
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
125 /// Result codes from NCrypt APIs
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
137 /// Well known names of key properties
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
154 // Properties defined by the CLR
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.
161 internal const string ClrIsEphemeral = "CLR IsEphemeral";
165 /// Well known names of provider properties
167 internal static class ProviderPropertyName {
168 internal const string Name = "Name"; // NCRYPT_NAME_PROPERTY
172 /// Flags for code:System.Security.Cryptography.NCryptNative.UnsafeNativeMethods.NCryptSecretAgreement
175 internal enum SecretAgreementFlags {
177 UseSecretAsHmacKey = 0x00000001 // KDF_USE_SECRET_AS_HMAC_KEY_FLAG
184 [StructLayout(LayoutKind.Sequential)]
185 internal struct NCRYPT_UI_POLICY {
186 public int dwVersion;
187 public CngUIProtectionLevels dwFlags;
189 [MarshalAs(UnmanagedType.LPWStr)]
190 public string pszCreationTitle;
192 [MarshalAs(UnmanagedType.LPWStr)]
193 public string pszFriendlyName;
195 [MarshalAs(UnmanagedType.LPWStr)]
196 public string pszDescription;
199 [StructLayout(LayoutKind.Sequential)]
200 internal struct NCryptBuffer {
202 public BufferType BufferType;
203 public IntPtr pvBuffer;
206 [StructLayout(LayoutKind.Sequential)]
207 internal struct NCryptBufferDesc {
208 public int ulVersion;
210 public IntPtr pBuffers; // NCryptBuffer[cBuffers]
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 {
219 /// Create an NCrypt key
221 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
222 internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider,
223 [Out] out SafeNCryptKeyHandle phKey,
227 CngKeyCreationOptions dwFlags);
232 [DllImport("ncrypt.dll")]
233 internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int flags);
236 /// Generate a key from a secret agreement
238 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
239 internal static extern ErrorCode NCryptDeriveKey(SafeNCryptSecretHandle hSharedSecret,
241 [In] ref NCryptBufferDesc pParameterList,
242 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbDerivedKey,
244 [Out] out int pcbResult,
245 SecretAgreementFlags dwFlags);
248 /// Export a key from the KSP
250 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
251 internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey,
252 IntPtr hExportKey, // NCRYPT_KEY_HANDLE
254 IntPtr pParameterList, // NCryptBufferDesc *
255 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
257 [Out] out int pcbResult,
261 /// Finalize a key to prepare it for use
263 [DllImport("ncrypt.dll")]
264 internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags);
267 /// Get the value of a property of an NCrypt object
269 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
270 internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
272 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
274 [Out] out int pcbResult,
275 CngPropertyOptions dwFlags);
278 /// Get the value of a pointer property of an NCrypt object
280 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
281 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
282 internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
284 [Out] out IntPtr pbOutput,
286 [Out] out int pcbResult,
287 CngPropertyOptions dwFlags);
290 /// Import a key into the KSP
292 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
293 internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider,
294 IntPtr hImportKey, // NCRYPT_KEY_HANDLE
296 IntPtr pParameterList, // NCryptBufferDesc *
297 [Out] out SafeNCryptKeyHandle phKey,
298 [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
303 /// Open an existing key
305 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
306 internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider,
307 [Out] out SafeNCryptKeyHandle phKey,
310 CngKeyOpenOptions dwFlags);
313 /// Acquire a handle to a key storage provider
315 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
316 internal static extern ErrorCode NCryptOpenStorageProvider([Out] out SafeNCryptProviderHandle phProvider,
317 string pszProviderName,
321 /// Generate a secret agreement for generating shared key material
323 [DllImport("ncrypt.dll")]
324 internal static extern ErrorCode NCryptSecretAgreement(SafeNCryptKeyHandle hPrivKey,
325 SafeNCryptKeyHandle hPubKey,
326 [Out] out SafeNCryptSecretHandle phSecret,
330 /// Set a property value on an NCrypt object
332 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
333 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
335 [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
337 CngPropertyOptions dwFlags);
340 /// Set a string property value on an NCrypt object
342 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
343 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
347 CngPropertyOptions dwFlags);
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.
353 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
354 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
358 CngPropertyOptions dwFlags);
361 /// Create a signature for a hash value
363 [DllImport("ncrypt.dll")]
364 internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
366 [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
368 [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
370 [Out] out int pcbResult,
374 /// Verify a signature over a hash value
376 [DllImport("ncrypt.dll")]
377 internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
379 [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
381 [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
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,
390 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
392 [Out] out int pcbResult,
393 AsymmetricPaddingMode dwFlags);
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,
400 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
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,
409 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
411 AsymmetricPaddingMode dwFlags);
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,
418 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
420 AsymmetricPaddingMode dwFlags);
422 [DllImport("ncrypt.dll")]
423 internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
424 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
426 [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
427 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
429 [Out] out int pcbResult,
430 AsymmetricPaddingMode dwFlags);
432 [DllImport("ncrypt.dll")]
433 internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
434 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
436 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
437 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
439 [Out] out int pcbResult,
440 AsymmetricPaddingMode dwFlags);
442 [DllImport("ncrypt.dll")]
443 internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
444 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
446 [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
447 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
449 [Out] out int pcbResult,
450 AsymmetricPaddingMode dwFlags);
452 [DllImport("ncrypt.dll")]
453 internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
454 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
456 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
457 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
459 [Out] out int pcbResult,
460 AsymmetricPaddingMode dwFlags);
465 /// Adapter to wrap specific NCryptDecrypt P/Invokes with specific padding info
467 [SecuritySafeCritical]
468 private delegate ErrorCode NCryptDecryptor<T>(SafeNCryptKeyHandle hKey,
475 AsymmetricPaddingMode dwFlags);
478 /// Adapter to wrap specific NCryptEncrypt P/Invokes with specific padding info
480 [SecuritySafeCritical]
481 private delegate ErrorCode NCryptEncryptor<T>(SafeNCryptKeyHandle hKey,
488 AsymmetricPaddingMode dwFlags);
491 /// Adapter to wrap specific NCryptSignHash P/Invokes with a specific padding info
493 [SecuritySafeCritical]
494 private delegate ErrorCode NCryptHashSigner<T>(SafeNCryptKeyHandle hKey,
501 AsymmetricPaddingMode dwFlags);
504 /// Adapter to wrap specific NCryptVerifySignature P/Invokes with a specific padding info
506 [SecuritySafeCritical]
507 private delegate ErrorCode NCryptSignatureVerifier<T>(SafeNCryptKeyHandle hKey,
513 AsymmetricPaddingMode dwFlags) where T : struct;
516 // Utility and wrapper functions
519 private static volatile bool s_haveNcryptSupported;
520 private static volatile bool s_ncryptSupported;
524 /// Generic decryption method, wrapped by decryption calls for specific padding modes
526 [SecuritySafeCritical]
527 private static byte[] DecryptData<T>(SafeNCryptKeyHandle key,
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");
537 // Figure out how big of a buffer is needed to store the decrypted data
538 int decryptedSize = 0;
539 ErrorCode error = decryptor(key,
547 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
548 throw new CryptographicException((int)error);
552 byte[] decrypted = new byte[decryptedSize];
553 error = decryptor(key,
561 if (error != ErrorCode.Success) {
562 throw new CryptographicException((int)error);
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);
573 /// Decrypt data using PKCS1 padding
575 [SecuritySafeCritical]
576 internal static byte[] DecryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
577 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
579 return DecryptData(key,
582 AsymmetricPaddingMode.Pkcs1,
583 UnsafeNativeMethods.NCryptDecrypt);
587 /// Decrypt data using OAEP padding
589 [SecuritySafeCritical]
590 internal static byte[] DecryptDataOaep(SafeNCryptKeyHandle key,
592 string hashAlgorithm) {
593 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
595 BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
596 oaepInfo.pszAlgId = hashAlgorithm;
598 return DecryptData(key,
601 AsymmetricPaddingMode.Oaep,
602 UnsafeNativeMethods.NCryptDecrypt);
606 /// Generic encryption method, wrapped by decryption calls for specific padding modes
608 [SecuritySafeCritical]
609 private static byte[] EncryptData<T>(SafeNCryptKeyHandle key,
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");
619 // Figure out how big of a buffer is to encrypt the data
620 int encryptedSize = 0;
621 ErrorCode error = encryptor(key,
629 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
630 throw new CryptographicException((int)error);
634 byte[] encrypted = new byte[encryptedSize];
635 error = encryptor(key,
643 if (error != ErrorCode.Success) {
644 throw new CryptographicException((int)error);
651 /// Encrypt data using OAEP padding
653 [SecuritySafeCritical]
654 internal static byte[] EncryptDataOaep(SafeNCryptKeyHandle key,
656 string hashAlgorithm) {
657 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
659 BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
660 oaepInfo.pszAlgId = hashAlgorithm;
662 return EncryptData(key,
665 AsymmetricPaddingMode.Oaep,
666 UnsafeNativeMethods.NCryptEncrypt);
670 /// Encrypt data using PKCS1 padding
672 [SecuritySafeCritical]
673 internal static byte[] EncryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
674 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
676 return EncryptData(key,
679 AsymmetricPaddingMode.Pkcs1,
680 UnsafeNativeMethods.NCryptEncrypt);
684 /// Generic signature method, wrapped by signature calls for specific padding modes
686 [SecuritySafeCritical]
687 private static byte[] SignHash<T>(SafeNCryptKeyHandle key,
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");
697 // Figure out how big the signature is
698 int signatureSize = 0;
699 ErrorCode error = signer(key,
707 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
708 throw new CryptographicException((int)error);
712 byte[] signature = new byte[signatureSize];
721 if (error != ErrorCode.Success) {
722 throw new CryptographicException((int)error);
728 /// Sign a hash, using PKCS1 padding
730 [SecuritySafeCritical]
731 internal static byte[] SignHashPkcs1(SafeNCryptKeyHandle key,
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)");
739 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
740 pkcs1Info.pszAlgId = hashAlgorithm;
745 AsymmetricPaddingMode.Pkcs1,
746 UnsafeNativeMethods.NCryptSignHash);
750 /// Sign a hash, using PSS padding
752 [SecuritySafeCritical]
753 internal static byte[] SignHashPss(SafeNCryptKeyHandle key,
755 string hashAlgorithm,
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");
763 BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
764 pssInfo.pszAlgId = hashAlgorithm;
765 pssInfo.cbSalt = saltBytes;
770 AsymmetricPaddingMode.Pss,
771 UnsafeNativeMethods.NCryptSignHash);
775 /// Generic signature verification method, wrapped by verification calls for specific padding modes
777 [SecuritySafeCritical]
778 private static bool VerifySignature<T>(SafeNCryptKeyHandle key,
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");
790 ErrorCode error = verifier(key,
797 if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
798 throw new CryptographicException((int)error);
801 return error == ErrorCode.Success;
805 /// Verify the signature of a hash using PKCS #1 padding
807 [SecuritySafeCritical]
808 internal static bool VerifySignaturePkcs1(SafeNCryptKeyHandle key,
810 string hashAlgorithm,
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");
818 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
819 pkcs1Info.pszAlgId = hashAlgorithm;
821 return VerifySignature(key,
825 AsymmetricPaddingMode.Pkcs1,
826 UnsafeNativeMethods.NCryptVerifySignature);
830 /// Verify the signature of a hash using PSS padding
832 [SecuritySafeCritical]
833 internal static bool VerifySignaturePss(SafeNCryptKeyHandle key,
835 string hashAlgorithm,
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");
844 BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
845 pssInfo.pszAlgId = hashAlgorithm;
846 pssInfo.cbSalt = saltBytes;
848 return VerifySignature(key,
852 AsymmetricPaddingMode.Pss,
853 UnsafeNativeMethods.NCryptVerifySignature);
857 /// Determine if NCrypt is supported on the current machine
859 internal static bool NCryptSupported {
860 [SecuritySafeCritical]
861 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
863 if (!s_haveNcryptSupported)
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;
872 return s_ncryptSupported;
877 /// Build an ECC public key blob to represent the given parameters
879 internal static byte[] BuildEccPublicBlob(string algorithm, BigInteger x, BigInteger y) {
880 Contract.Requires(!String.IsNullOrEmpty(algorithm));
881 Contract.Ensures(Contract.Result<byte[]>() != null);
884 // #ECCPublicBlobFormat
885 // The ECC public key blob format is as follows:
889 // X parameter (cbKey bytes long, byte-reversed)
890 // Y parameter (cbKey bytes long, byte-reversed)
893 // First map the algorithm name to its magic number and key size
894 BCryptNative.KeyBlobMagicNumber algorithmMagic;
896 BCryptNative.MapAlgorithmIdToMagic(algorithm, out algorithmMagic, out keySize);
898 // Next generate the public key parameters
899 byte[] xBytes = ReverseBytes(FillKeyParameter(x.ToByteArray(), keySize));
900 byte[] yBytes = ReverseBytes(FillKeyParameter(y.ToByteArray(), keySize));
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);
913 /// Create a random CNG key
915 [System.Security.SecurityCritical]
916 internal static SafeNCryptKeyHandle CreatePersistedKey(SafeNCryptProviderHandle provider,
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);
926 SafeNCryptKeyHandle keyHandle = null;
927 ErrorCode error = UnsafeNativeMethods.NCryptCreatePersistedKey(provider,
933 if (error != ErrorCode.Success) {
934 throw new CryptographicException((int)error);
943 [System.Security.SecurityCritical]
944 internal static void DeleteKey(SafeNCryptKeyHandle key) {
945 Contract.Requires(key != null);
947 ErrorCode error = UnsafeNativeMethods.NCryptDeleteKey(key, 0);
948 if (error != ErrorCode.Success) {
949 throw new CryptographicException((int)error);
951 key.SetHandleAsInvalid();
955 /// Derive key material from a hash or HMAC KDF
957 /// <returns></returns>
958 [System.Security.SecurityCritical]
959 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
960 private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
962 string hashAlgorithm,
964 byte[] secretPrepend,
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);
973 List<NCryptBuffer> parameters = new List<NCryptBuffer>();
975 // First marshal the hash algoritm
976 IntPtr hashAlgorithmString = IntPtr.Zero;
978 // Run in a CER so that we know we'll free the memory for the marshaled string
979 RuntimeHelpers.PrepareConstrainedRegions();
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();
986 hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm);
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);
997 fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend) {
999 // Now marshal the other parameters
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);
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);
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);
1026 return DeriveKeyMaterial(secretAgreement,
1028 parameters.ToArray(),
1034 if (hashAlgorithmString != IntPtr.Zero) {
1035 Marshal.FreeCoTaskMem(hashAlgorithmString);
1041 /// Derive key material using a given KDF and secret agreement
1043 [System.Security.SecurityCritical]
1044 private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
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);
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);
1060 // Figure out how big the key material is
1062 ErrorCode error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1069 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1070 throw new CryptographicException((int)error);
1073 // Allocate memory for the key material and generate it
1074 byte[] keyMaterial = new byte[keySize];
1075 error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1083 if (error != ErrorCode.Success) {
1084 throw new CryptographicException((int)error);
1093 /// Derive key material from a secret agreement using a hash KDF
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);
1105 return DeriveKeyMaterial(secretAgreement,
1106 BCryptNative.KeyDerivationFunction.Hash,
1115 /// Derive key material from a secret agreement using a HMAC KDF
1117 [System.Security.SecurityCritical]
1118 internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement,
1119 string hashAlgorithm,
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);
1128 return DeriveKeyMaterial(secretAgreement,
1129 BCryptNative.KeyDerivationFunction.Hmac,
1138 /// Derive key material from a secret agreeement using the TLS KDF
1140 [System.Security.SecurityCritical]
1141 internal static byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement,
1144 SecretAgreementFlags flags) {
1145 Contract.Requires(secretAgreement != null);
1146 Contract.Requires(label != null && seed != null);
1147 Contract.Ensures(Contract.Result<byte[]>() != null);
1149 NCryptBuffer[] buffers = new NCryptBuffer[2];
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;
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;
1165 return DeriveKeyMaterial(secretAgreement,
1166 BCryptNative.KeyDerivationFunction.Tls,
1174 /// Generate a secret agreement value for between two parties
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);
1185 SafeNCryptSecretHandle secretAgreement;
1186 ErrorCode error = UnsafeNativeMethods.NCryptSecretAgreement(privateKey,
1187 otherPartyPublicKey,
1188 out secretAgreement,
1191 if (error != ErrorCode.Success) {
1192 throw new CryptographicException((int)error);
1195 return secretAgreement;
1199 /// Export a key from the KSP
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);
1207 // Figure out how big of a buffer we need to export into
1209 ErrorCode error = UnsafeNativeMethods.NCryptExportKey(key,
1218 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1219 throw new CryptographicException((int)error);
1223 Debug.Assert(bufferSize > 0, "bufferSize > 0");
1224 byte[] keyBlob = new byte[bufferSize];
1225 error = UnsafeNativeMethods.NCryptExportKey(key,
1234 if (error != ErrorCode.Success) {
1235 throw new CryptographicException((int)error);
1242 /// Make sure that a key is padded out to be its full size
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);
1249 int bytesRequired = (keySize / 8) + (keySize % 8 == 0 ? 0 : 1);
1250 if (key.Length == bytesRequired) {
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");
1262 byte[] fullKey = new byte[bytesRequired];
1263 Buffer.BlockCopy(key, 0, fullKey, 0, Math.Min(key.Length, fullKey.Length));
1268 /// Finalize a key and prepare it for use
1270 [System.Security.SecurityCritical]
1271 internal static void FinalizeKey(SafeNCryptKeyHandle key) {
1272 Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
1274 ErrorCode error = UnsafeNativeMethods.NCryptFinalizeKey(key, 0);
1275 if (error != ErrorCode.Success) {
1276 throw new CryptographicException((int)error);
1281 /// Get the value of an NCrypt property
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);
1291 // Find out how big of a buffer we need to store the property in
1293 ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1301 // NTE_NOT_FOUND means this property does not exist, any other error besides NTE_BUFFER_TOO_SMALL
1302 // indicates a real problem.
1305 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall && error != ErrorCode.NotFound) {
1306 throw new CryptographicException((int)error);
1309 foundProperty = error != ErrorCode.NotFound;
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,
1321 if (error != ErrorCode.Success) {
1322 throw new CryptographicException((int)error);
1325 foundProperty = true;
1332 /// Get the value of a DWORD NCrypt property
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);
1342 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1344 if (!foundProperty || valueBytes == null) {
1348 return BitConverter.ToInt32(valueBytes, 0);
1353 /// Get the value of a pointer NCrypt property
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);
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,
1373 // NTE_NOT_FOUND means this property was not set, so return a NULL pointer
1374 if (error == ErrorCode.NotFound) {
1378 if (error != ErrorCode.Success) {
1379 throw new CryptographicException((int)error);
1386 /// Get the value of a string NCrypt property
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);
1397 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1399 if (!foundProperty || valueBytes == null) {
1402 else if (valueBytes.Length == 0) {
1403 return String.Empty;
1407 fixed (byte* pValueBytes = valueBytes) {
1408 return Marshal.PtrToStringUni(new IntPtr(pValueBytes));
1415 /// Get the value of an NCrypt structure property -- this will return an empty structure if the
1416 /// property does not exist.
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);
1427 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1429 if (!foundProperty || valueBytes == null) {
1434 fixed (byte *pValue = valueBytes) {
1435 return (T)Marshal.PtrToStructure(new IntPtr(pValue), typeof(T));
1441 /// Import a key into the KSP
1443 [System.Security.SecurityCritical]
1444 internal static SafeNCryptKeyHandle ImportKey(SafeNCryptProviderHandle provider,
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);
1454 SafeNCryptKeyHandle keyHandle = null;
1455 ErrorCode error = UnsafeNativeMethods.NCryptImportKey(provider,
1464 if (error != ErrorCode.Success) {
1465 throw new CryptographicException((int)error);
1472 /// Open an existing key
1474 [System.Security.SecurityCritical]
1475 internal static SafeNCryptKeyHandle OpenKey(SafeNCryptProviderHandle provider,
1477 CngKeyOpenOptions options) {
1478 Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed);
1479 Contract.Requires(name != null);
1481 SafeNCryptKeyHandle key = null;
1482 ErrorCode error = UnsafeNativeMethods.NCryptOpenKey(provider, out key, name, 0, options);
1484 if (error != ErrorCode.Success) {
1485 throw new CryptographicException((int)error);
1492 /// Open the specified key storage provider
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);
1501 SafeNCryptProviderHandle providerHandle = null;
1502 ErrorCode error = UnsafeNativeMethods.NCryptOpenStorageProvider(out providerHandle,
1506 if (error != ErrorCode.Success) {
1507 throw new CryptographicException((int)error);
1510 return providerHandle;
1514 /// Reverse the bytes in a buffer
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);
1523 /// Reverse a section of bytes within a buffer
1525 private static byte[] ReverseBytes(byte[] buffer, int offset, int count) {
1526 return ReverseBytes(buffer, offset, count, false);
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);
1540 reversed = new byte[count+1]; // the last (most-significant) byte will be left as 0x00
1544 reversed = new byte[count];
1547 int lastByte = offset + count - 1;
1548 for (int i = 0; i < count; i++) {
1549 reversed[i] = buffer[lastByte - i];
1556 /// Set a DWORD property on an NCrypt object
1558 [System.Security.SecurityCritical]
1559 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1560 string propertyName,
1562 CngPropertyOptions propertyOptions) {
1563 Contract.Requires(ncryptObject != null);
1564 Contract.Requires(propertyName != null);
1566 SetProperty(ncryptObject, propertyName, BitConverter.GetBytes(value), propertyOptions);
1570 /// Set a string property
1572 [System.Security.SecurityCritical]
1573 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1574 string propertyName,
1576 CngPropertyOptions propertyOptions) {
1577 Contract.Requires(ncryptObject != null);
1578 Contract.Requires(propertyName != null);
1580 ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1583 (value.Length + 1) * sizeof(char),
1586 if (error != ErrorCode.Success) {
1587 throw new CryptographicException((int)error);
1592 /// Set a structure property
1594 [System.Security.SecurityCritical]
1595 internal static void SetProperty<T>(SafeNCryptHandle ncryptObject,
1596 string propertyName,
1598 CngPropertyOptions propertyOptions) where T : struct {
1599 Contract.Requires(ncryptObject != null);
1600 Contract.Requires(propertyName != null);
1602 byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
1605 fixed (byte *pBuffer = buffer) {
1607 bool marshaledStructure = false;
1608 RuntimeHelpers.PrepareConstrainedRegions();
1610 // If we successfully marshal into the buffer, make sure to destroy the buffer when we're done
1611 RuntimeHelpers.PrepareConstrainedRegions();
1614 Marshal.StructureToPtr(value, new IntPtr(pBuffer), false);
1615 marshaledStructure = true;
1618 SetProperty(ncryptObject, propertyName, buffer, propertyOptions);
1621 if (marshaledStructure) {
1622 Marshal.DestroyStructure(new IntPtr(pBuffer), typeof(T));
1630 /// Set a property on an NCrypt object
1632 [System.Security.SecurityCritical]
1633 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1634 string propertyName,
1636 CngPropertyOptions propertyOptions) {
1637 Contract.Requires(ncryptObject != null);
1638 Contract.Requires(propertyName != null);
1640 ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1643 value != null ? value.Length : 0,
1646 if (error != ErrorCode.Success) {
1647 throw new CryptographicException((int)error);
1652 /// Sign a hash using no padding
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);
1660 // Figure out how big the signature is
1661 int signatureSize = 0;
1662 ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
1671 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1672 throw new CryptographicException((int)error);
1676 Debug.Assert(signatureSize > 0, "signatureSize > 0");
1677 byte[] signature = new byte[signatureSize];
1679 error = UnsafeNativeMethods.NCryptSignHash(key,
1688 if (error != ErrorCode.Success) {
1689 throw new CryptographicException((int)error);
1696 /// Unpack a key blob in ECC public blob format into its X and Y parameters
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.
1701 internal static void UnpackEccPublicBlob(byte[] blob, out BigInteger x, out BigInteger y) {
1702 Contract.Requires(blob != null && blob.Length > 2 * sizeof(int));
1705 // See code:System.Security.Cryptography.NCryptNative#ECCPublicBlobFormat for details about the
1706 // format of the ECC public key blob.
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");
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));
1721 /// Verify a signature created with no padding
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);
1729 ErrorCode error = UnsafeNativeMethods.NCryptVerifySignature(key,
1737 if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
1738 throw new CryptographicException((int)error);
1741 return error == ErrorCode.Success;