3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.Diagnostics.CodeAnalysis;
12 using System.Numerics;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.ConstrainedExecution;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
19 using System.Diagnostics.Contracts;
20 using Microsoft.Win32;
21 using Microsoft.Win32.SafeHandles;
23 namespace System.Security.Cryptography {
26 // Public facing enumerations
30 /// Flags to control how often and in which format a key is allowed to be exported
33 public enum CngExportPolicies {
35 AllowExport = 0x00000001, // NCRYPT_ALLOW_EXPORT_FLAG
36 AllowPlaintextExport = 0x00000002, // NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG
37 AllowArchiving = 0x00000004, // NCRYPT_ALLOW_ARCHIVING_FLAG
38 AllowPlaintextArchiving = 0x00000008 // NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG
42 /// Flags controlling how the key is created
45 public enum CngKeyCreationOptions {
47 MachineKey = 0x00000020, // NCRYPT_MACHINE_KEY_FLAG
48 OverwriteExistingKey = 0x00000080 // NCRYPT_OVERWRITE_KEY_FLAG
52 /// Flags controlling how a key is opened
55 [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Approved API exception to have an easy way to express user keys")]
56 public enum CngKeyOpenOptions {
59 MachineKey = 0x00000020, // NCRYPT_MACHINE_KEY_FLAG
60 Silent = 0x00000040 // NCRYPT_SILENT_FLAG
64 /// Flags indicating the type of key
67 internal enum CngKeyTypes {
69 MachineKey = 0x00000020 // NCRYPT_MACHINE_KEY_FLAG
73 /// Bits defining what operations are valid to use a key with
76 [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
77 public enum CngKeyUsages {
79 Decryption = 0x00000001, // NCRYPT_ALLOW_DECRYPT_FLAG
80 Signing = 0x00000002, // NCRYPT_ALLOW_SIGNING_FLAG
81 KeyAgreement = 0x00000004, // NCRYPT_ALLOW_KEY_AGREEMENT_FLAG
82 AllUsages = 0x00ffffff // NCRYPT_ALLOW_ALL_USAGES
86 /// Options affecting how a property is interpreted by CNG
89 [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
90 public enum CngPropertyOptions {
92 CustomProperty = 0x40000000, // NCRYPT_PERSIST_ONLY_FLAG
93 Persist = unchecked((int)0x80000000) // NCRYPT_PERSIST_FLAG
97 /// Levels of UI protection available for a key
100 public enum CngUIProtectionLevels {
102 ProtectKey = 0x00000001, // NCRYPT_UI_PROTECT_KEY_FLAG
103 ForceHighProtection = 0x00000002 // NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG
107 /// Native interop with CNG's NCrypt layer. Native definitions are in ncrypt.h
109 internal static class NCryptNative {
115 /// Types of NCryptBuffers
117 internal enum BufferType {
118 KdfHashAlgorithm = 0x00000000, // KDF_HASH_ALGORITHM
119 KdfSecretPrepend = 0x00000001, // KDF_SECRET_PREPEND
120 KdfSecretAppend = 0x00000002, // KDF_SECRET_APPEND
121 KdfHmacKey = 0x00000003, // KDF_HMAC_KEY
122 KdfTlsLabel = 0x00000004, // KDF_TLS_PRF_LABEL
123 KdfTlsSeed = 0x00000005 // KDF_TLS_PRF_SEED
127 /// Result codes from NCrypt APIs
129 internal enum ErrorCode {
130 Success = 0, // ERROR_SUCCESS
131 BadSignature = unchecked((int)0x80090006), // NTE_BAD_SIGNATURE
132 NotFound = unchecked((int)0x80090011), // NTE_NOT_FOUND
133 KeyDoesNotExist = unchecked((int)0x80090016), // NTE_BAD_KEYSET
134 BufferTooSmall = unchecked((int)0x80090028), // NTE_BUFFER_TOO_SMALL
135 NoMoreItems = unchecked((int)0x8009002a) // NTE_NO_MORE_ITEMS
139 /// Well known names of key properties
141 internal static class KeyPropertyName {
142 internal const string Algorithm = "Algorithm Name"; // NCRYPT_ALGORITHM_PROPERTY
143 internal const string AlgorithmGroup = "Algorithm Group"; // NCRYPT_ALGORITHM_GROUP_PROPERTY
144 internal const string ExportPolicy = "Export Policy"; // NCRYPT_EXPORT_POLICY_PROPERTY
145 internal const string KeyType = "Key Type"; // NCRYPT_KEY_TYPE_PROPERTY
146 internal const string KeyUsage = "Key Usage"; // NCRYPT_KEY_USAGE_PROPERTY
147 internal const string Length = "Length"; // NCRYPT_LENGTH_PROPERTY
148 internal const string Name = "Name"; // NCRYPT_NAME_PROPERTY
149 internal const string ParentWindowHandle = "HWND Handle"; // NCRYPT_WINDOW_HANDLE_PROPERTY
150 internal const string ProviderHandle = "Provider Handle"; // NCRYPT_PROVIDER_HANDLE_PROPERTY
151 internal const string UIPolicy = "UI Policy"; // NCRYPT_UI_POLICY_PROPERTY
152 internal const string UniqueName = "Unique Name"; // NCRYPT_UNIQUE_NAME_PROPERTY
153 internal const string UseContext = "Use Context"; // NCRYPT_USE_CONTEXT_PROPERTY
156 // Properties defined by the CLR
160 /// Is the key a CLR created ephemeral key, it will contain a single byte with value 1 if the
161 /// key was created by the CLR as an ephemeral key.
163 internal const string ClrIsEphemeral = "CLR IsEphemeral";
167 /// Well known names of provider properties
169 internal static class ProviderPropertyName {
170 internal const string Name = "Name"; // NCRYPT_NAME_PROPERTY
174 /// Flags for code:System.Security.Cryptography.NCryptNative.UnsafeNativeMethods.NCryptSecretAgreement
177 internal enum SecretAgreementFlags {
179 UseSecretAsHmacKey = 0x00000001 // KDF_USE_SECRET_AS_HMAC_KEY_FLAG
186 [StructLayout(LayoutKind.Sequential)]
187 internal struct NCRYPT_UI_POLICY {
188 public int dwVersion;
189 public CngUIProtectionLevels dwFlags;
191 [MarshalAs(UnmanagedType.LPWStr)]
192 public string pszCreationTitle;
194 [MarshalAs(UnmanagedType.LPWStr)]
195 public string pszFriendlyName;
197 [MarshalAs(UnmanagedType.LPWStr)]
198 public string pszDescription;
201 [StructLayout(LayoutKind.Sequential)]
202 internal struct NCryptBuffer {
204 public BufferType BufferType;
205 public IntPtr pvBuffer;
208 [StructLayout(LayoutKind.Sequential)]
209 internal struct NCryptBufferDesc {
210 public int ulVersion;
212 public IntPtr pBuffers; // NCryptBuffer[cBuffers]
215 [SuppressUnmanagedCodeSecurity]
216 #pragma warning disable 618 // System.Core.dll still uses SecurityRuleSet.Level1
217 [SecurityCritical(SecurityCriticalScope.Everything)]
218 #pragma warning restore 618
219 internal static class UnsafeNativeMethods {
221 /// Create an NCrypt key
223 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
224 internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider,
225 [Out] out SafeNCryptKeyHandle phKey,
229 CngKeyCreationOptions dwFlags);
234 [DllImport("ncrypt.dll")]
235 internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int flags);
238 /// Generate a key from a secret agreement
240 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
241 internal static extern ErrorCode NCryptDeriveKey(SafeNCryptSecretHandle hSharedSecret,
243 [In] ref NCryptBufferDesc pParameterList,
244 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbDerivedKey,
246 [Out] out int pcbResult,
247 SecretAgreementFlags dwFlags);
250 /// Export a key from the KSP
252 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
253 internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey,
254 IntPtr hExportKey, // NCRYPT_KEY_HANDLE
256 IntPtr pParameterList, // NCryptBufferDesc *
257 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
259 [Out] out int pcbResult,
263 /// Finalize a key to prepare it for use
265 [DllImport("ncrypt.dll")]
266 internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags);
269 /// Get the value of a property of an NCrypt object
271 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
272 internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
274 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
276 [Out] out int pcbResult,
277 CngPropertyOptions dwFlags);
280 /// Get the value of a pointer property of an NCrypt object
282 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
283 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
284 internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject,
286 [Out] out IntPtr pbOutput,
288 [Out] out int pcbResult,
289 CngPropertyOptions dwFlags);
292 /// Import a key into the KSP
294 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
295 internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider,
296 IntPtr hImportKey, // NCRYPT_KEY_HANDLE
298 IntPtr pParameterList, // NCryptBufferDesc *
299 [Out] out SafeNCryptKeyHandle phKey,
300 [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
305 /// Open an existing key
307 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
308 internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider,
309 [Out] out SafeNCryptKeyHandle phKey,
312 CngKeyOpenOptions dwFlags);
315 /// Acquire a handle to a key storage provider
317 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
318 internal static extern ErrorCode NCryptOpenStorageProvider([Out] out SafeNCryptProviderHandle phProvider,
319 string pszProviderName,
323 /// Generate a secret agreement for generating shared key material
325 [DllImport("ncrypt.dll")]
326 internal static extern ErrorCode NCryptSecretAgreement(SafeNCryptKeyHandle hPrivKey,
327 SafeNCryptKeyHandle hPubKey,
328 [Out] out SafeNCryptSecretHandle phSecret,
332 /// Set a property value on an NCrypt object
334 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
335 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
337 [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
339 CngPropertyOptions dwFlags);
342 /// Set a string property value on an NCrypt object
344 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
345 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
349 CngPropertyOptions dwFlags);
352 /// Set a property value on an NCrypt object when a pointer to the buffer already exists in
353 /// managed code. To set a pointer valued property, use the ref IntPtr overload.
355 [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
356 internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
360 CngPropertyOptions dwFlags);
363 /// Create a signature for a hash value
365 [DllImport("ncrypt.dll")]
366 internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
368 [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
370 [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
372 [Out] out int pcbResult,
376 /// Verify a signature over a hash value
378 [DllImport("ncrypt.dll")]
379 internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
381 [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
383 [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
387 [DllImport("ncrypt.dll")]
388 internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
389 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
390 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
392 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
394 [Out] out int pcbResult,
395 AsymmetricPaddingMode dwFlags);
397 [DllImport("ncrypt.dll")]
398 internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
399 [In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
400 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
402 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
404 [Out] out int pcbResult,
405 AsymmetricPaddingMode dwFlags);
406 [DllImport("ncrypt.dll")]
407 internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
408 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pPaddingInfo,
409 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
411 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
413 AsymmetricPaddingMode dwFlags);
415 [DllImport("ncrypt.dll")]
416 internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
417 [In] ref BCryptNative.BCRYPT_PSS_PADDING_INFO pPaddingInfo,
418 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
420 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
422 AsymmetricPaddingMode dwFlags);
424 [DllImport("ncrypt.dll")]
425 internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
426 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
428 [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
429 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
431 [Out] out int pcbResult,
432 AsymmetricPaddingMode dwFlags);
434 [DllImport("ncrypt.dll")]
435 internal static extern ErrorCode NCryptDecrypt(SafeNCryptKeyHandle hKey,
436 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
438 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
439 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
441 [Out] out int pcbResult,
442 AsymmetricPaddingMode dwFlags);
444 [DllImport("ncrypt.dll")]
445 internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
446 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
448 [In] ref BCryptNative.BCRYPT_OAEP_PADDING_INFO pvPadding,
449 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
451 [Out] out int pcbResult,
452 AsymmetricPaddingMode dwFlags);
454 [DllImport("ncrypt.dll")]
455 internal static extern ErrorCode NCryptEncrypt(SafeNCryptKeyHandle hKey,
456 [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
458 [In] ref BCryptNative.BCRYPT_PKCS1_PADDING_INFO pvPadding,
459 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput,
461 [Out] out int pcbResult,
462 AsymmetricPaddingMode dwFlags);
467 /// Adapter to wrap specific NCryptDecrypt P/Invokes with specific padding info
469 [SecuritySafeCritical]
470 private delegate ErrorCode NCryptDecryptor<T>(SafeNCryptKeyHandle hKey,
477 AsymmetricPaddingMode dwFlags);
480 /// Adapter to wrap specific NCryptEncrypt P/Invokes with specific padding info
482 [SecuritySafeCritical]
483 private delegate ErrorCode NCryptEncryptor<T>(SafeNCryptKeyHandle hKey,
490 AsymmetricPaddingMode dwFlags);
493 /// Adapter to wrap specific NCryptSignHash P/Invokes with a specific padding info
495 [SecuritySafeCritical]
496 private delegate ErrorCode NCryptHashSigner<T>(SafeNCryptKeyHandle hKey,
503 AsymmetricPaddingMode dwFlags);
506 /// Adapter to wrap specific NCryptVerifySignature P/Invokes with a specific padding info
508 [SecuritySafeCritical]
509 private delegate ErrorCode NCryptSignatureVerifier<T>(SafeNCryptKeyHandle hKey,
515 AsymmetricPaddingMode dwFlags) where T : struct;
518 // Utility and wrapper functions
521 private static volatile bool s_haveNcryptSupported;
522 private static volatile bool s_ncryptSupported;
526 /// Generic decryption method, wrapped by decryption calls for specific padding modes
528 [SecuritySafeCritical]
529 private static byte[] DecryptData<T>(SafeNCryptKeyHandle key,
532 AsymmetricPaddingMode paddingMode,
533 NCryptDecryptor<T> decryptor) where T : struct {
534 Debug.Assert(key != null, "key != null");
535 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
536 Debug.Assert(data != null, "data != null");
537 Debug.Assert(decryptor != null, "decryptor != null");
539 // Figure out how big of a buffer is needed to store the decrypted data
540 int decryptedSize = 0;
541 ErrorCode error = decryptor(key,
549 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
550 throw new CryptographicException((int)error);
554 byte[] decrypted = new byte[decryptedSize];
555 error = decryptor(key,
563 if (error != ErrorCode.Success) {
564 throw new CryptographicException((int)error);
567 // Sometimes decryptedSize can be less than the allocated buffer size
568 // So resize the array to the actual returned plaintext
569 Array.Resize(ref decrypted, decryptedSize);
575 /// Decrypt data using PKCS1 padding
577 [SecuritySafeCritical]
578 internal static byte[] DecryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
579 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
581 return DecryptData(key,
584 AsymmetricPaddingMode.Pkcs1,
585 UnsafeNativeMethods.NCryptDecrypt);
589 /// Decrypt data using OAEP padding
591 [SecuritySafeCritical]
592 internal static byte[] DecryptDataOaep(SafeNCryptKeyHandle key,
594 string hashAlgorithm) {
595 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
597 BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
598 oaepInfo.pszAlgId = hashAlgorithm;
600 return DecryptData(key,
603 AsymmetricPaddingMode.Oaep,
604 UnsafeNativeMethods.NCryptDecrypt);
608 /// Generic encryption method, wrapped by decryption calls for specific padding modes
610 [SecuritySafeCritical]
611 private static byte[] EncryptData<T>(SafeNCryptKeyHandle key,
614 AsymmetricPaddingMode paddingMode,
615 NCryptEncryptor<T> encryptor) where T : struct {
616 Debug.Assert(key != null, "key != null");
617 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
618 Debug.Assert(data != null, "data != null");
619 Debug.Assert(encryptor != null, "encryptor != null");
621 // Figure out how big of a buffer is to encrypt the data
622 int encryptedSize = 0;
623 ErrorCode error = encryptor(key,
631 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
632 throw new CryptographicException((int)error);
636 byte[] encrypted = new byte[encryptedSize];
637 error = encryptor(key,
645 if (error != ErrorCode.Success) {
646 throw new CryptographicException((int)error);
653 /// Encrypt data using OAEP padding
655 [SecuritySafeCritical]
656 internal static byte[] EncryptDataOaep(SafeNCryptKeyHandle key,
658 string hashAlgorithm) {
659 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
661 BCryptNative.BCRYPT_OAEP_PADDING_INFO oaepInfo = new BCryptNative.BCRYPT_OAEP_PADDING_INFO();
662 oaepInfo.pszAlgId = hashAlgorithm;
664 return EncryptData(key,
667 AsymmetricPaddingMode.Oaep,
668 UnsafeNativeMethods.NCryptEncrypt);
672 /// Encrypt data using PKCS1 padding
674 [SecuritySafeCritical]
675 internal static byte[] EncryptDataPkcs1(SafeNCryptKeyHandle key, byte[] data) {
676 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
678 return EncryptData(key,
681 AsymmetricPaddingMode.Pkcs1,
682 UnsafeNativeMethods.NCryptEncrypt);
686 /// Generic signature method, wrapped by signature calls for specific padding modes
688 [SecuritySafeCritical]
689 private static byte[] SignHash<T>(SafeNCryptKeyHandle key,
692 AsymmetricPaddingMode paddingMode,
693 NCryptHashSigner<T> signer) where T : struct {
694 Debug.Assert(key != null, "key != null");
695 Debug.Assert(!key.IsInvalid && !key.IsClosed, "!key.IsInvalid && !key.IsClosed");
696 Debug.Assert(hash != null, "hash != null");
697 Debug.Assert(signer != null, "signer != null");
699 // Figure out how big the signature is
700 int signatureSize = 0;
701 ErrorCode error = signer(key,
709 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
710 throw new CryptographicException((int)error);
714 byte[] signature = new byte[signatureSize];
723 if (error != ErrorCode.Success) {
724 throw new CryptographicException((int)error);
730 /// Sign a hash, using PKCS1 padding
732 [SecuritySafeCritical]
733 internal static byte[] SignHashPkcs1(SafeNCryptKeyHandle key,
735 string hashAlgorithm) {
736 Debug.Assert(key != null, "key != null");
737 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
738 Debug.Assert(hash != null, "hash != null");
739 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
741 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
742 pkcs1Info.pszAlgId = hashAlgorithm;
747 AsymmetricPaddingMode.Pkcs1,
748 UnsafeNativeMethods.NCryptSignHash);
752 /// Sign a hash, using PSS padding
754 [SecuritySafeCritical]
755 internal static byte[] SignHashPss(SafeNCryptKeyHandle key,
757 string hashAlgorithm,
759 Debug.Assert(key != null, "key != null");
760 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
761 Debug.Assert(hash != null, "hash != null");
762 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
763 Debug.Assert(saltBytes >= 0, "saltBytes >= 0");
765 BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
766 pssInfo.pszAlgId = hashAlgorithm;
767 pssInfo.cbSalt = saltBytes;
772 AsymmetricPaddingMode.Pss,
773 UnsafeNativeMethods.NCryptSignHash);
777 /// Generic signature verification method, wrapped by verification calls for specific padding modes
779 [SecuritySafeCritical]
780 private static bool VerifySignature<T>(SafeNCryptKeyHandle key,
784 AsymmetricPaddingMode paddingMode,
785 NCryptSignatureVerifier<T> verifier) where T : struct {
786 Debug.Assert(key != null, "key != null");
787 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
788 Debug.Assert(hash != null, "hash != null");
789 Debug.Assert(signature != null, "signature != null");
790 Debug.Assert(verifier != null, "verifier != null");
792 ErrorCode error = verifier(key,
799 if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
800 throw new CryptographicException((int)error);
803 return error == ErrorCode.Success;
807 /// Verify the signature of a hash using PKCS #1 padding
809 [SecuritySafeCritical]
810 internal static bool VerifySignaturePkcs1(SafeNCryptKeyHandle key,
812 string hashAlgorithm,
814 Debug.Assert(key != null, "key != null");
815 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
816 Debug.Assert(hash != null, "hash != null");
817 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
818 Debug.Assert(signature != null, "signature != null");
820 BCryptNative.BCRYPT_PKCS1_PADDING_INFO pkcs1Info = new BCryptNative.BCRYPT_PKCS1_PADDING_INFO();
821 pkcs1Info.pszAlgId = hashAlgorithm;
823 return VerifySignature(key,
827 AsymmetricPaddingMode.Pkcs1,
828 UnsafeNativeMethods.NCryptVerifySignature);
832 /// Verify the signature of a hash using PSS padding
834 [SecuritySafeCritical]
835 internal static bool VerifySignaturePss(SafeNCryptKeyHandle key,
837 string hashAlgorithm,
840 Debug.Assert(key != null, "key != null");
841 Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid");
842 Debug.Assert(hash != null, "hash != null");
843 Debug.Assert(!String.IsNullOrEmpty(hashAlgorithm), "!String.IsNullOrEmpty(hashAlgorithm)");
844 Debug.Assert(signature != null, "signature != null");
846 BCryptNative.BCRYPT_PSS_PADDING_INFO pssInfo = new BCryptNative.BCRYPT_PSS_PADDING_INFO();
847 pssInfo.pszAlgId = hashAlgorithm;
848 pssInfo.cbSalt = saltBytes;
850 return VerifySignature(key,
854 AsymmetricPaddingMode.Pss,
855 UnsafeNativeMethods.NCryptVerifySignature);
859 /// Determine if NCrypt is supported on the current machine
861 internal static bool NCryptSupported {
862 [SecuritySafeCritical]
863 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
865 if (!s_haveNcryptSupported)
867 // Attempt to load ncrypt.dll to see if the NCrypt CNG APIs are available on the machine
868 using (SafeLibraryHandle ncrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("ncrypt", IntPtr.Zero, 0)) {
869 s_ncryptSupported = !ncrypt.IsInvalid;
870 s_haveNcryptSupported = true;
874 return s_ncryptSupported;
879 /// Build an ECC public key blob to represent the given parameters
881 internal static byte[] BuildEccPublicBlob(string algorithm, BigInteger x, BigInteger y) {
882 Contract.Requires(!String.IsNullOrEmpty(algorithm));
883 Contract.Ensures(Contract.Result<byte[]>() != null);
886 // #ECCPublicBlobFormat
887 // The ECC public key blob format is as follows:
891 // X parameter (cbKey bytes long, byte-reversed)
892 // Y parameter (cbKey bytes long, byte-reversed)
895 // First map the algorithm name to its magic number and key size
896 BCryptNative.KeyBlobMagicNumber algorithmMagic;
898 BCryptNative.MapAlgorithmIdToMagic(algorithm, out algorithmMagic, out keySize);
900 // Next generate the public key parameters
901 byte[] xBytes = ReverseBytes(FillKeyParameter(x.ToByteArray(), keySize));
902 byte[] yBytes = ReverseBytes(FillKeyParameter(y.ToByteArray(), keySize));
904 // Finally, lay out the structure itself
905 byte[] blob = new byte[2 * sizeof(int) + xBytes.Length + yBytes.Length];
906 Buffer.BlockCopy(BitConverter.GetBytes((int)algorithmMagic), 0, blob, 0, sizeof(int));
907 Buffer.BlockCopy(BitConverter.GetBytes(xBytes.Length), 0, blob, sizeof(int), sizeof(int));
908 Buffer.BlockCopy(xBytes, 0, blob, 2 * sizeof(int), xBytes.Length);
909 Buffer.BlockCopy(yBytes, 0, blob, 2 * sizeof(int) + xBytes.Length, yBytes.Length);
915 /// Create a random CNG key
917 [System.Security.SecurityCritical]
918 internal static SafeNCryptKeyHandle CreatePersistedKey(SafeNCryptProviderHandle provider,
921 CngKeyCreationOptions options) {
922 Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed);
923 Contract.Requires(!String.IsNullOrEmpty(algorithm));
924 Contract.Ensures(Contract.Result<SafeNCryptKeyHandle>() != null &&
925 !Contract.Result<SafeNCryptKeyHandle>().IsInvalid &&
926 !Contract.Result<SafeNCryptKeyHandle>().IsClosed);
928 SafeNCryptKeyHandle keyHandle = null;
929 ErrorCode error = UnsafeNativeMethods.NCryptCreatePersistedKey(provider,
935 if (error != ErrorCode.Success) {
936 throw new CryptographicException((int)error);
945 [System.Security.SecurityCritical]
946 internal static void DeleteKey(SafeNCryptKeyHandle key) {
947 Contract.Requires(key != null);
949 ErrorCode error = UnsafeNativeMethods.NCryptDeleteKey(key, 0);
950 if (error != ErrorCode.Success) {
951 throw new CryptographicException((int)error);
953 key.SetHandleAsInvalid();
957 /// Derive key material from a hash or HMAC KDF
959 /// <returns></returns>
960 [System.Security.SecurityCritical]
961 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
962 private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
964 string hashAlgorithm,
966 byte[] secretPrepend,
968 SecretAgreementFlags flags) {
969 Contract.Requires(secretAgreement != null);
970 Contract.Requires(!String.IsNullOrEmpty(kdf));
971 Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
972 Contract.Requires(hmacKey == null || kdf == BCryptNative.KeyDerivationFunction.Hmac);
973 Contract.Ensures(Contract.Result<byte[]>() != null);
975 List<NCryptBuffer> parameters = new List<NCryptBuffer>();
977 // First marshal the hash algoritm
978 IntPtr hashAlgorithmString = IntPtr.Zero;
980 // Run in a CER so that we know we'll free the memory for the marshaled string
981 RuntimeHelpers.PrepareConstrainedRegions();
983 // Assign in a CER so we don't fail between allocating the memory and assigning the result
984 // back to the string variable.
985 RuntimeHelpers.PrepareConstrainedRegions();
988 hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm);
991 // We always need to marshal the hashing function
992 NCryptBuffer hashAlgorithmBuffer = new NCryptBuffer();
993 hashAlgorithmBuffer.cbBuffer = (hashAlgorithm.Length + 1) * sizeof(char);
994 hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm;
995 hashAlgorithmBuffer.pvBuffer = hashAlgorithmString;
996 parameters.Add(hashAlgorithmBuffer);
999 fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend) {
1001 // Now marshal the other parameters
1004 if (pHmacKey != null) {
1005 NCryptBuffer hmacKeyBuffer = new NCryptBuffer();
1006 hmacKeyBuffer.cbBuffer = hmacKey.Length;
1007 hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
1008 hmacKeyBuffer.pvBuffer = new IntPtr(pHmacKey);
1009 parameters.Add(hmacKeyBuffer);
1012 if (pSecretPrepend != null) {
1013 NCryptBuffer secretPrependBuffer = new NCryptBuffer();
1014 secretPrependBuffer.cbBuffer = secretPrepend.Length;
1015 secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend;
1016 secretPrependBuffer.pvBuffer = new IntPtr(pSecretPrepend);
1017 parameters.Add(secretPrependBuffer);
1020 if (pSecretAppend != null) {
1021 NCryptBuffer secretAppendBuffer = new NCryptBuffer();
1022 secretAppendBuffer.cbBuffer = secretAppend.Length;
1023 secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
1024 secretAppendBuffer.pvBuffer = new IntPtr(pSecretAppend);
1025 parameters.Add(secretAppendBuffer);
1028 return DeriveKeyMaterial(secretAgreement,
1030 parameters.ToArray(),
1036 if (hashAlgorithmString != IntPtr.Zero) {
1037 Marshal.FreeCoTaskMem(hashAlgorithmString);
1043 /// Derive key material using a given KDF and secret agreement
1045 [System.Security.SecurityCritical]
1046 private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
1048 NCryptBuffer[] parameters,
1049 SecretAgreementFlags flags) {
1050 Contract.Requires(secretAgreement != null);
1051 Contract.Requires(!String.IsNullOrEmpty(kdf));
1052 Contract.Requires(parameters != null);
1053 Contract.Ensures(Contract.Result<byte[]>() != null);
1056 fixed (NCryptBuffer* pParameters = parameters) {
1057 NCryptBufferDesc parameterDesc = new NCryptBufferDesc();
1058 parameterDesc.ulVersion = 0;
1059 parameterDesc.cBuffers = parameters.Length;
1060 parameterDesc.pBuffers = new IntPtr(pParameters);
1062 // Figure out how big the key material is
1064 ErrorCode error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1071 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1072 throw new CryptographicException((int)error);
1075 // Allocate memory for the key material and generate it
1076 byte[] keyMaterial = new byte[keySize];
1077 error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
1085 if (error != ErrorCode.Success) {
1086 throw new CryptographicException((int)error);
1095 /// Derive key material from a secret agreement using a hash KDF
1097 [System.Security.SecurityCritical]
1098 internal static byte[] DeriveKeyMaterialHash(SafeNCryptSecretHandle secretAgreement,
1099 string hashAlgorithm,
1100 byte[] secretPrepend,
1101 byte[] secretAppend,
1102 SecretAgreementFlags flags) {
1103 Contract.Requires(secretAgreement != null);
1104 Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
1105 Contract.Ensures(Contract.Result<byte[]>() != null);
1107 return DeriveKeyMaterial(secretAgreement,
1108 BCryptNative.KeyDerivationFunction.Hash,
1117 /// Derive key material from a secret agreement using a HMAC KDF
1119 [System.Security.SecurityCritical]
1120 internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement,
1121 string hashAlgorithm,
1123 byte[] secretPrepend,
1124 byte[] secretAppend,
1125 SecretAgreementFlags flags) {
1126 Contract.Requires(secretAgreement != null);
1127 Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
1128 Contract.Ensures(Contract.Result<byte[]>() != null);
1130 return DeriveKeyMaterial(secretAgreement,
1131 BCryptNative.KeyDerivationFunction.Hmac,
1140 /// Derive key material from a secret agreeement using the TLS KDF
1142 [System.Security.SecurityCritical]
1143 internal static byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement,
1146 SecretAgreementFlags flags) {
1147 Contract.Requires(secretAgreement != null);
1148 Contract.Requires(label != null && seed != null);
1149 Contract.Ensures(Contract.Result<byte[]>() != null);
1151 NCryptBuffer[] buffers = new NCryptBuffer[2];
1154 fixed (byte* pLabel = label, pSeed = seed) {
1155 NCryptBuffer labelBuffer = new NCryptBuffer();
1156 labelBuffer.cbBuffer = label.Length;
1157 labelBuffer.BufferType = BufferType.KdfTlsLabel;
1158 labelBuffer.pvBuffer = new IntPtr(pLabel);
1159 buffers[0] = labelBuffer;
1161 NCryptBuffer seedBuffer = new NCryptBuffer();
1162 seedBuffer.cbBuffer = seed.Length;
1163 seedBuffer.BufferType = BufferType.KdfTlsSeed;
1164 seedBuffer.pvBuffer = new IntPtr(pSeed);
1165 buffers[1] = seedBuffer;
1167 return DeriveKeyMaterial(secretAgreement,
1168 BCryptNative.KeyDerivationFunction.Tls,
1176 /// Generate a secret agreement value for between two parties
1178 [System.Security.SecurityCritical]
1179 internal static SafeNCryptSecretHandle DeriveSecretAgreement(SafeNCryptKeyHandle privateKey,
1180 SafeNCryptKeyHandle otherPartyPublicKey) {
1181 Contract.Requires(privateKey != null);
1182 Contract.Requires(otherPartyPublicKey != null);
1183 Contract.Ensures(Contract.Result<SafeNCryptSecretHandle>() != null &&
1184 !Contract.Result<SafeNCryptSecretHandle>().IsClosed &&
1185 !Contract.Result<SafeNCryptSecretHandle>().IsInvalid);
1187 SafeNCryptSecretHandle secretAgreement;
1188 ErrorCode error = UnsafeNativeMethods.NCryptSecretAgreement(privateKey,
1189 otherPartyPublicKey,
1190 out secretAgreement,
1193 if (error != ErrorCode.Success) {
1194 throw new CryptographicException((int)error);
1197 return secretAgreement;
1201 /// Export a key from the KSP
1203 [System.Security.SecurityCritical]
1204 internal static byte[] ExportKey(SafeNCryptKeyHandle key, string format) {
1205 Contract.Requires(key != null);
1206 Contract.Requires(!String.IsNullOrEmpty(format));
1207 Contract.Ensures(Contract.Result<byte[]>() != null);
1209 // Figure out how big of a buffer we need to export into
1211 ErrorCode error = UnsafeNativeMethods.NCryptExportKey(key,
1220 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1221 throw new CryptographicException((int)error);
1225 Debug.Assert(bufferSize > 0, "bufferSize > 0");
1226 byte[] keyBlob = new byte[bufferSize];
1227 error = UnsafeNativeMethods.NCryptExportKey(key,
1236 if (error != ErrorCode.Success) {
1237 throw new CryptographicException((int)error);
1244 /// Make sure that a key is padded out to be its full size
1246 private static byte[] FillKeyParameter(byte[] key, int keySize) {
1247 Contract.Requires(key != null);
1248 Contract.Requires(keySize > 0);
1249 Contract.Ensures(Contract.Result<byte[]>() != null && Contract.Result<byte[]>().Length >= keySize / 8);
1251 int bytesRequired = (keySize / 8) + (keySize % 8 == 0 ? 0 : 1);
1252 if (key.Length == bytesRequired) {
1257 // If the key is longer than required, it should have been padded out with zeros
1258 if (key.Length > bytesRequired) {
1259 for (int i = bytesRequired; i < key.Length; i++) {
1260 Debug.Assert(key[i] == 0, "key[i] == 0");
1264 byte[] fullKey = new byte[bytesRequired];
1265 Buffer.BlockCopy(key, 0, fullKey, 0, Math.Min(key.Length, fullKey.Length));
1270 /// Finalize a key and prepare it for use
1272 [System.Security.SecurityCritical]
1273 internal static void FinalizeKey(SafeNCryptKeyHandle key) {
1274 Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
1276 ErrorCode error = UnsafeNativeMethods.NCryptFinalizeKey(key, 0);
1277 if (error != ErrorCode.Success) {
1278 throw new CryptographicException((int)error);
1283 /// Get the value of an NCrypt property
1285 [System.Security.SecurityCritical]
1286 internal static byte[] GetProperty(SafeNCryptHandle ncryptObject,
1287 string propertyName,
1288 CngPropertyOptions propertyOptions,
1289 out bool foundProperty) {
1290 Contract.Requires(ncryptObject != null);
1291 Contract.Requires(propertyName != null);
1293 // Find out how big of a buffer we need to store the property in
1295 ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1303 // NTE_NOT_FOUND means this property does not exist, any other error besides NTE_BUFFER_TOO_SMALL
1304 // indicates a real problem.
1307 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall && error != ErrorCode.NotFound) {
1308 throw new CryptographicException((int)error);
1311 foundProperty = error != ErrorCode.NotFound;
1313 // Pull back the property value
1314 byte[] value = null;
1315 if (error != ErrorCode.NotFound && bufferSize > 0) {
1316 value = new byte[bufferSize];
1317 error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1323 if (error != ErrorCode.Success) {
1324 throw new CryptographicException((int)error);
1327 foundProperty = true;
1334 /// Get the value of a DWORD NCrypt property
1336 [System.Security.SecurityCritical]
1337 internal static int GetPropertyAsDWord(SafeNCryptHandle ncryptObject,
1338 string propertyName,
1339 CngPropertyOptions propertyOptions) {
1340 Contract.Requires(ncryptObject != null);
1341 Contract.Requires(propertyName != null);
1344 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1346 if (!foundProperty || valueBytes == null) {
1350 return BitConverter.ToInt32(valueBytes, 0);
1355 /// Get the value of a pointer NCrypt property
1357 [System.Security.SecurityCritical]
1358 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
1359 internal static IntPtr GetPropertyAsIntPtr(SafeNCryptHandle ncryptObject,
1360 string propertyName,
1361 CngPropertyOptions propertyOptions) {
1362 Contract.Requires(ncryptObject != null);
1363 Contract.Requires(propertyName != null);
1365 // Find out how big of a buffer we need to store the property in
1366 int bufferSize = IntPtr.Size;
1367 IntPtr value = IntPtr.Zero;
1368 ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
1375 // NTE_NOT_FOUND means this property was not set, so return a NULL pointer
1376 if (error == ErrorCode.NotFound) {
1380 if (error != ErrorCode.Success) {
1381 throw new CryptographicException((int)error);
1388 /// Get the value of a string NCrypt property
1390 [System.Security.SecurityCritical]
1391 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
1392 internal static string GetPropertyAsString(SafeNCryptHandle ncryptObject,
1393 string propertyName,
1394 CngPropertyOptions propertyOptions) {
1395 Contract.Requires(ncryptObject != null);
1396 Contract.Requires(propertyName != null);
1399 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1401 if (!foundProperty || valueBytes == null) {
1404 else if (valueBytes.Length == 0) {
1405 return String.Empty;
1409 fixed (byte* pValueBytes = valueBytes) {
1410 return Marshal.PtrToStringUni(new IntPtr(pValueBytes));
1417 /// Get the value of an NCrypt structure property -- this will return an empty structure if the
1418 /// property does not exist.
1420 [System.Security.SecurityCritical]
1421 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
1422 internal static T GetPropertyAsStruct<T>(SafeNCryptHandle ncryptObject,
1423 string propertyName,
1424 CngPropertyOptions propertyOptions) where T : struct {
1425 Contract.Requires(ncryptObject != null);
1426 Contract.Requires(propertyName != null);
1429 byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
1431 if (!foundProperty || valueBytes == null) {
1436 fixed (byte *pValue = valueBytes) {
1437 return (T)Marshal.PtrToStructure(new IntPtr(pValue), typeof(T));
1443 /// Import a key into the KSP
1445 [System.Security.SecurityCritical]
1446 internal static SafeNCryptKeyHandle ImportKey(SafeNCryptProviderHandle provider,
1449 Contract.Requires(provider != null);
1450 Contract.Requires(keyBlob != null);
1451 Contract.Requires(!String.IsNullOrEmpty(format));
1452 Contract.Ensures(Contract.Result<SafeNCryptKeyHandle>() != null &&
1453 !Contract.Result<SafeNCryptKeyHandle>().IsInvalid &&
1454 !Contract.Result<SafeNCryptKeyHandle>().IsClosed);
1456 SafeNCryptKeyHandle keyHandle = null;
1457 ErrorCode error = UnsafeNativeMethods.NCryptImportKey(provider,
1466 if (error != ErrorCode.Success) {
1467 throw new CryptographicException((int)error);
1474 /// Open an existing key
1476 [System.Security.SecurityCritical]
1477 internal static SafeNCryptKeyHandle OpenKey(SafeNCryptProviderHandle provider,
1479 CngKeyOpenOptions options) {
1480 Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed);
1481 Contract.Requires(name != null);
1483 SafeNCryptKeyHandle key = null;
1484 ErrorCode error = UnsafeNativeMethods.NCryptOpenKey(provider, out key, name, 0, options);
1486 if (error != ErrorCode.Success) {
1487 throw new CryptographicException((int)error);
1494 /// Open the specified key storage provider
1496 [System.Security.SecurityCritical]
1497 internal static SafeNCryptProviderHandle OpenStorageProvider(string providerName) {
1498 Contract.Requires(!String.IsNullOrEmpty(providerName));
1499 Contract.Ensures(Contract.Result<SafeNCryptProviderHandle>() != null &&
1500 !Contract.Result<SafeNCryptProviderHandle>().IsInvalid &&
1501 !Contract.Result<SafeNCryptProviderHandle>().IsClosed);
1503 SafeNCryptProviderHandle providerHandle = null;
1504 ErrorCode error = UnsafeNativeMethods.NCryptOpenStorageProvider(out providerHandle,
1508 if (error != ErrorCode.Success) {
1509 throw new CryptographicException((int)error);
1512 return providerHandle;
1516 /// Reverse the bytes in a buffer
1518 private static byte[] ReverseBytes(byte[] buffer) {
1519 Contract.Requires(buffer != null);
1520 Contract.Ensures(Contract.Result<byte[]>() != null && Contract.Result<byte[]>().Length == buffer.Length);
1521 return ReverseBytes(buffer, 0, buffer.Length, false);
1525 /// Reverse a section of bytes within a buffer
1527 private static byte[] ReverseBytes(byte[] buffer, int offset, int count) {
1528 return ReverseBytes(buffer, offset, count, false);
1531 private static byte[] ReverseBytes(byte[] buffer, int offset, int count, bool padWithZeroByte) {
1532 Contract.Requires(buffer != null);
1533 Contract.Requires(offset >= 0 && offset < buffer.Length);
1534 Contract.Requires(count >= 0 && buffer.Length - count >= offset);
1535 Contract.Ensures(Contract.Result<byte[]>() != null);
1536 Contract.Ensures(Contract.Result<byte[]>().Length == (padWithZeroByte ? count + 1 : count));
1537 Contract.Ensures(padWithZeroByte ? Contract.Result<byte[]>()[count] == 0 : true);
1542 reversed = new byte[count+1]; // the last (most-significant) byte will be left as 0x00
1546 reversed = new byte[count];
1549 int lastByte = offset + count - 1;
1550 for (int i = 0; i < count; i++) {
1551 reversed[i] = buffer[lastByte - i];
1558 /// Set a DWORD property on an NCrypt object
1560 [System.Security.SecurityCritical]
1561 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1562 string propertyName,
1564 CngPropertyOptions propertyOptions) {
1565 Contract.Requires(ncryptObject != null);
1566 Contract.Requires(propertyName != null);
1568 SetProperty(ncryptObject, propertyName, BitConverter.GetBytes(value), propertyOptions);
1572 /// Set a string property
1574 [System.Security.SecurityCritical]
1575 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1576 string propertyName,
1578 CngPropertyOptions propertyOptions) {
1579 Contract.Requires(ncryptObject != null);
1580 Contract.Requires(propertyName != null);
1582 ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1585 (value.Length + 1) * sizeof(char),
1588 if (error != ErrorCode.Success) {
1589 throw new CryptographicException((int)error);
1594 /// Set a structure property
1596 [System.Security.SecurityCritical]
1597 internal static void SetProperty<T>(SafeNCryptHandle ncryptObject,
1598 string propertyName,
1600 CngPropertyOptions propertyOptions) where T : struct {
1601 Contract.Requires(ncryptObject != null);
1602 Contract.Requires(propertyName != null);
1604 byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
1607 fixed (byte *pBuffer = buffer) {
1609 bool marshaledStructure = false;
1610 RuntimeHelpers.PrepareConstrainedRegions();
1612 // If we successfully marshal into the buffer, make sure to destroy the buffer when we're done
1613 RuntimeHelpers.PrepareConstrainedRegions();
1616 Marshal.StructureToPtr(value, new IntPtr(pBuffer), false);
1617 marshaledStructure = true;
1620 SetProperty(ncryptObject, propertyName, buffer, propertyOptions);
1623 if (marshaledStructure) {
1624 Marshal.DestroyStructure(new IntPtr(pBuffer), typeof(T));
1632 /// Set a property on an NCrypt object
1634 [System.Security.SecurityCritical]
1635 internal static void SetProperty(SafeNCryptHandle ncryptObject,
1636 string propertyName,
1638 CngPropertyOptions propertyOptions) {
1639 Contract.Requires(ncryptObject != null);
1640 Contract.Requires(propertyName != null);
1642 ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
1645 value != null ? value.Length : 0,
1648 if (error != ErrorCode.Success) {
1649 throw new CryptographicException((int)error);
1654 /// Sign a hash using no padding
1656 [System.Security.SecurityCritical]
1657 internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash) {
1658 Contract.Requires(key != null);
1659 Contract.Requires(hash != null);
1660 Contract.Ensures(Contract.Result<byte[]>() != null);
1662 // Figure out how big the signature is
1663 int signatureSize = 0;
1664 ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
1673 if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
1674 throw new CryptographicException((int)error);
1678 Debug.Assert(signatureSize > 0, "signatureSize > 0");
1679 byte[] signature = new byte[signatureSize];
1681 error = UnsafeNativeMethods.NCryptSignHash(key,
1690 if (error != ErrorCode.Success) {
1691 throw new CryptographicException((int)error);
1698 /// Unpack a key blob in ECC public blob format into its X and Y parameters
1700 /// This method expects that the blob be in the correct format -- blobs accepted from partially
1701 /// trusted code need to be validated before being unpacked.
1703 internal static void UnpackEccPublicBlob(byte[] blob, out BigInteger x, out BigInteger y) {
1704 Contract.Requires(blob != null && blob.Length > 2 * sizeof(int));
1707 // See code:System.Security.Cryptography.NCryptNative#ECCPublicBlobFormat for details about the
1708 // format of the ECC public key blob.
1711 // read the size of each parameter
1712 int parameterSize = BitConverter.ToInt32(blob, sizeof(int));
1713 Debug.Assert(parameterSize > 0, "parameterSize > 0");
1714 Debug.Assert(blob.Length >= 2 * sizeof(int) + 2 * parameterSize, "blob.Length >= 2 * sizeof(int) + 2 * parameterSize");
1716 // read out the X and Y parameters, in memory reversed form
1717 // add 0x00 padding to force BigInteger to interpret these as positive numbers
1718 x = new BigInteger(ReverseBytes(blob, 2 * sizeof(int), parameterSize, true));
1719 y = new BigInteger(ReverseBytes(blob, 2 * sizeof(int) + parameterSize, parameterSize, true));
1723 /// Verify a signature created with no padding
1725 [System.Security.SecurityCritical]
1726 internal static bool VerifySignature(SafeNCryptKeyHandle key, byte[] hash, byte[] signature) {
1727 Contract.Requires(key != null);
1728 Contract.Requires(hash != null);
1729 Contract.Requires(signature != null);
1731 ErrorCode error = UnsafeNativeMethods.NCryptVerifySignature(key,
1739 if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
1740 throw new CryptographicException((int)error);
1743 return error == ErrorCode.Success;