3 // Copyright (c) Microsoft Corporation. All rights reserved.
11 using System.Diagnostics;
12 using System.Diagnostics.CodeAnalysis;
13 using System.Diagnostics.Contracts;
14 using System.Globalization;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.ConstrainedExecution;
17 using System.Runtime.InteropServices;
18 using System.Runtime.Versioning;
19 using System.Security;
21 using Microsoft.Win32.SafeHandles;
23 namespace System.Security.Cryptography {
25 /// Native interop with CAPI. Native definitions can be found in wincrypt.h or msaxlapi.h
27 internal static class CapiNative {
28 internal enum AlgorithmClass {
29 DataEncryption = (3 << 13), // ALG_CLASS_DATA_ENCRYPT
30 Hash = (4 << 13) // ALG_CLASS_HASH
33 internal enum AlgorithmType {
34 Any = (0 << 9), // ALG_TYPE_ANY
35 Block = (3 << 9) // ALG_TYPE_BLOCK
38 internal enum AlgorithmSubId {
39 MD5 = 3, // ALG_SID_MD5
40 Sha1 = 4, // ALG_SID_SHA1
41 Sha256 = 12, // ALG_SID_SHA_256
42 Sha384 = 13, // ALG_SID_SHA_384
43 Sha512 = 14, // ALG_SID_SHA_512
45 Aes128 = 14, // ALG_SID_AES_128
46 Aes192 = 15, // ALG_SID_AES_192
47 Aes256 = 16 // ALG_SID_AES_256
50 internal enum AlgorithmId {
53 Aes128 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes128), // CALG_AES_128
54 Aes192 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes192), // CALG_AES_192
55 Aes256 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes256), // CALG_AES_256
57 MD5 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.MD5), // CALG_MD5
58 Sha1 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha1), // CALG_SHA1
59 Sha256 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha256), // CALG_SHA_256
60 Sha384 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha384), // CALG_SHA_384
61 Sha512 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha512) // CALG_SHA_512
65 /// Flags for the CryptAcquireContext API
68 internal enum CryptAcquireContextFlags {
70 VerifyContext = unchecked((int)0xF0000000) // CRYPT_VERIFYCONTEXT
74 /// Error codes returned from CAPI
76 internal enum ErrorCode {
77 Success = 0x00000000, // ERROR_SUCCESS
78 MoreData = 0x00000ea, // ERROR_MORE_DATA
79 NoMoreItems = 0x00000103, // ERROR_NO_MORE_ITEMS
80 BadData = unchecked((int)0x80090005), // NTE_BAD_DATA
81 BadAlgorithmId = unchecked((int)0x80090008), // NTE_BAD_ALGID
82 ProviderTypeNotDefined = unchecked((int)0x80090017), // NTE_PROV_TYPE_NOT_DEF
83 KeysetNotDefined = unchecked((int)0x80090019) // NTE_KEYSET_NOT_DEF
87 /// Parameters that GetHashParam can query
89 internal enum HashParameter {
91 AlgorithmId = 0x0001, // HP_ALGID
92 HashValue = 0x0002, // HP_HASHVAL
93 HashSize = 0x0004 // HP_HASHSIZE
97 /// Formats of blobs that keys can appear in
99 internal enum KeyBlobType : byte {
100 PlainText = 0x8 // PLAINTEXTKEYBLOB
104 /// Flags for CryptGenKey and CryptImportKey
107 internal enum KeyFlags {
109 Exportable = 0x0001 // CRYPT_EXPORTABLE
113 /// Parameters of a cryptographic key used by SetKeyParameter
115 internal enum KeyParameter {
119 ModeBits = 5 // KP_MODE_BITS
123 /// Well-known names of crypto service providers
125 internal static class ProviderNames {
126 // MS_ENH_RSA_AES_PROV
127 public const string MicrosoftEnhancedRsaAes = "Microsoft Enhanced RSA and AES Cryptographic Provider";
128 public const string MicrosoftEnhancedRsaAesPrototype = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)";
132 /// Parameters exposed by a CSP
134 internal enum ProviderParameter {
136 EnumerateAlgorithms = 1 // PP_ENUMALGS
140 /// Flags controlling information retrieved about a provider parameter
143 internal enum ProviderParameterFlags {
145 RestartEnumeration = 0x00000001 // CRYPT_FIRST
149 /// Provider type accessed in a crypto service provider. These provide the set of algorithms
150 /// available to use for an application.
152 internal enum ProviderType {
154 RsaAes = 24 // PROV_RSA_AES
157 [StructLayout(LayoutKind.Sequential)]
158 internal struct BLOBHEADER {
159 public KeyBlobType bType;
160 public byte bVersion;
161 public short reserved;
162 public AlgorithmId aiKeyAlg;
165 [StructLayout(LayoutKind.Sequential)]
166 internal struct CRYPTOAPI_BLOB {
168 public IntPtr pbData;
171 [StructLayout(LayoutKind.Sequential)]
172 internal unsafe struct PROV_ENUMALGS {
173 public AlgorithmId aiAlgId;
175 public int dwNameLen;
176 public fixed byte szName[20];
179 internal const uint ALG_CLASS_SIGNATURE = (1 << 13);
180 internal const uint ALG_TYPE_RSA = (2 << 9);
181 internal const uint ALG_SID_RSA_ANY = 0;
182 internal const uint ALG_SID_DSS_ANY = 0;
183 internal const uint ALG_TYPE_DSS = (1 << 9);
184 internal const uint ALG_CLASS_KEY_EXCHANGE = (5 << 13);
186 internal const uint CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY);
187 internal const uint CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY);
188 internal const uint CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY);
189 internal const uint CNG_RSA_PUBLIC_KEY_BLOB = 72;
191 internal const uint X509_ASN_ENCODING = 0x00000001;
192 internal const uint PKCS_7_ASN_ENCODING = 0x00010000;
194 internal const uint CRYPT_OID_INFO_OID_KEY = 1;
196 internal const uint LMEM_FIXED = 0x0000;
197 internal const uint LMEM_ZEROINIT = 0x0040;
199 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
200 internal struct CRYPT_OID_INFO {
201 internal CRYPT_OID_INFO(int size) {
207 ExtraInfo = new CRYPTOAPI_BLOB();
209 internal uint cbSize;
210 [MarshalAs(UnmanagedType.LPStr)]
211 internal string pszOID;
212 internal string pwszName;
213 internal uint dwGroupId;
215 internal CRYPTOAPI_BLOB ExtraInfo;
219 #if FEATURE_CORESYSTEM
222 #pragma warning disable 618 // Have not migrated to v4 transparency yet
223 [SecurityCritical(SecurityCriticalScope.Everything)]
224 #pragma warning restore 618
226 [SuppressUnmanagedCodeSecurity]
227 internal static class UnsafeNativeMethods {
229 /// Calculate the public key token for a given public key
232 #if FEATURE_CORESYSTEM
235 public static extern int _AxlPublicKeyBlobToPublicKeyToken(ref CRYPTOAPI_BLOB pCspPublicKeyBlob,
236 [Out] out SafeAxlBufferHandle ppwszPublicKeyToken);
239 /// Open a crypto service provider, if a key container is specified KeyContainerPermission
240 /// should be demanded.
242 [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
243 [return: MarshalAs(UnmanagedType.Bool)]
244 #if FEATURE_CORESYSTEM
247 public static extern bool CryptAcquireContext([Out] out SafeCspHandle phProv,
250 ProviderType dwProvType,
251 CryptAcquireContextFlags dwFlags);
254 /// Prepare a new hash algorithm for use
256 [DllImport("advapi32", SetLastError = true)]
257 [return: MarshalAs(UnmanagedType.Bool)]
258 #if FEATURE_CORESYSTEM
261 public static extern bool CryptCreateHash(SafeCspHandle hProv,
263 SafeCapiKeyHandle hKey,
265 [Out] out SafeCapiHashHandle phHash);
268 /// Decrypt a block of data
270 [DllImport("advapi32", SetLastError = true)]
271 [return: MarshalAs(UnmanagedType.Bool)]
272 #if FEATURE_CORESYSTEM
275 public static extern bool CryptDecrypt(SafeCapiKeyHandle hKey,
276 SafeCapiHashHandle hHash,
277 [MarshalAs(UnmanagedType.Bool)] bool Final,
279 IntPtr pbData, // BYTE *
280 [In, Out] ref int pdwDataLen);
283 /// Duplicate a key handle
285 [DllImport("advapi32")]
286 #if !FEATURE_CORESYSTEM
287 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
289 [SuppressUnmanagedCodeSecurity]
290 [return: MarshalAs(UnmanagedType.Bool)]
291 #if FEATURE_CORESYSTEM
294 public static extern bool CryptDuplicateKey(SafeCapiKeyHandle hKey,
297 [Out] out SafeCapiKeyHandle phKey);
300 /// Encrypt a block of data
302 [DllImport("advapi32", SetLastError = true)]
303 [return: MarshalAs(UnmanagedType.Bool)]
304 #if FEATURE_CORESYSTEM
307 public static extern bool CryptEncrypt(SafeCapiKeyHandle hKey,
308 SafeCapiHashHandle hHash,
309 [MarshalAs(UnmanagedType.Bool)] bool Final,
311 IntPtr pbData, // BYTE *
312 [In, Out] ref int pdwDataLen,
316 /// Export a key into a byte array
318 [DllImport("advapi32", SetLastError = true)]
319 [return: MarshalAs(UnmanagedType.Bool)]
320 #if FEATURE_CORESYSTEM
323 public static extern bool CryptExportKey(SafeCapiKeyHandle hKey,
324 SafeCapiKeyHandle hExpKey,
325 int dwBlobType, // (int)KeyBlobType
327 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
328 [In, Out] ref int pdwDataLen);
330 /// Generate a random key
332 [DllImport("advapi32", SetLastError = true)]
333 [return: MarshalAs(UnmanagedType.Bool)]
334 #if FEATURE_CORESYSTEM
337 public static extern bool CryptGenKey(SafeCspHandle hProv,
340 [Out] out SafeCapiKeyHandle phKey);
343 /// Fill a buffer with cryptographically random bytes
345 [DllImport("advapi32", SetLastError = true)]
346 [return: MarshalAs(UnmanagedType.Bool)]
347 #if FEATURE_CORESYSTEM
350 public static extern bool CryptGenRandom(SafeCspHandle hProv,
352 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbBuffer);
355 /// Get information about a hash algorithm, including the current value
357 [DllImport("advapi32", SetLastError = true)]
358 [return: MarshalAs(UnmanagedType.Bool)]
359 #if FEATURE_CORESYSTEM
362 public static extern bool CryptGetHashParam(SafeCapiHashHandle hHash,
363 HashParameter dwParam,
364 [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
365 [In, Out] ref int pdwDataLen,
369 /// Get information about a CSP
371 [DllImport("advapi32", SetLastError = true)]
372 [return: MarshalAs(UnmanagedType.Bool)]
373 #if FEATURE_CORESYSTEM
376 public static extern bool CryptGetProvParam(SafeCspHandle hProv,
377 ProviderParameter dwParam,
379 [In, Out] ref int pdwDataLen,
380 ProviderParameterFlags dwFlags);
383 /// Add a block of data to a hash
385 [DllImport("advapi32", SetLastError = true)]
386 [return: MarshalAs(UnmanagedType.Bool)]
387 #if FEATURE_CORESYSTEM
390 public static extern bool CryptHashData(SafeCapiHashHandle hHash,
391 [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
396 /// Import a key into a CSP
398 [DllImport("advapi32", SetLastError = true)]
399 [return: MarshalAs(UnmanagedType.Bool)]
400 #if FEATURE_CORESYSTEM
403 public static extern bool CryptImportKey(SafeCspHandle hProv,
404 [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
406 SafeCapiKeyHandle hPubKey,
408 [Out] out SafeCapiKeyHandle phKey);
411 /// Set a property of a key
413 [DllImport("advapi32", SetLastError = true)]
414 [return: MarshalAs(UnmanagedType.Bool)]
415 #if FEATURE_CORESYSTEM
418 public static extern bool CryptSetKeyParam(SafeCapiKeyHandle hKey,
419 KeyParameter dwParam,
420 [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
423 //Added for X509Certificate extension support
424 #if FEATURE_CORESYSTEM
427 [DllImport("CRYPT32.dll", CharSet = CharSet.Auto, SetLastError = true)]
428 [ResourceExposure(ResourceScope.None)]
429 internal extern static
430 IntPtr CryptFindOIDInfo(
433 [In] OidGroup dwGroupId);
435 #if FEATURE_CORESYSTEM
438 [DllImport("CRYPT32.dll", CharSet = CharSet.Auto, SetLastError = true)]
439 [ResourceExposure(ResourceScope.None)]
440 internal extern static
441 IntPtr CryptFindOIDInfo(
443 [In] SafeLocalAllocHandle pvKey,
444 [In] OidGroup dwGroupId);
447 #if FEATURE_CORESYSTEM
450 [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
451 [ResourceExposure(ResourceScope.None)]
452 internal static extern
453 bool CryptDecodeObject(
454 [In] uint dwCertEncodingType,
455 [In] IntPtr lpszStructType,
456 [In] IntPtr pbEncoded,
459 [In, Out] SafeLocalAllocHandle pvStructInfo,
460 [In, Out] IntPtr pcbStructInfo);
462 #if FEATURE_CORESYSTEM
465 [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
466 [ResourceExposure(ResourceScope.None)]
467 internal static extern
468 bool CryptDecodeObject(
469 [In] uint dwCertEncodingType,
470 [In] IntPtr lpszStructType,
471 [In] byte[] pbEncoded,
474 [In, Out] SafeLocalAllocHandle pvStructInfo,
475 [In, Out] IntPtr pcbStructInfo);
476 #if FEATURE_CORESYSTEM
479 [DllImport("KERNEL32.dll", CharSet = CharSet.Auto, SetLastError = true)]
480 [ResourceExposure(ResourceScope.None)]
481 internal static extern
482 SafeLocalAllocHandle LocalAlloc(
484 [In] IntPtr sizetdwBytes);
488 // Utility and wrapper functions
492 /// Acquire a crypto service provider
494 [System.Security.SecurityCritical]
495 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
496 internal static SafeCspHandle AcquireCsp(string keyContainer,
498 ProviderType providerType,
499 CryptAcquireContextFlags flags,
500 bool throwPlatformException) {
501 Contract.Ensures(Contract.Result<SafeCspHandle>() != null &&
502 !Contract.Result<SafeCspHandle>().IsInvalid &&
503 !Contract.Result<SafeCspHandle>().IsClosed);
505 SafeCspHandle cspHandle = null;
506 if (!UnsafeNativeMethods.CryptAcquireContext(out cspHandle,
511 // If the platform doesn't have the specified CSP, we'll either get a ProviderTypeNotDefined
512 // or a KeysetNotDefined error depending on the CAPI version.
513 int error = Marshal.GetLastWin32Error();
514 if (throwPlatformException && (error == (int)CapiNative.ErrorCode.ProviderTypeNotDefined ||
515 error == (int)CapiNative.ErrorCode.KeysetNotDefined)) {
516 throw new PlatformNotSupportedException(SR.GetString(SR.Cryptography_PlatformNotSupported));
519 throw new CryptographicException(error);
527 /// Export a symmetric algorithm key into a byte array
529 [System.Security.SecurityCritical]
530 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
531 internal static byte[] ExportSymmetricKey(SafeCapiKeyHandle key) {
532 Contract.Requires(key != null);
533 Contract.Ensures(Contract.Result<byte[]>() != null && Contract.Result<byte[]>().Length > 0);
536 // Figure out how big the key blob is, and export it
540 if (!UnsafeNativeMethods.CryptExportKey(key,
541 SafeCapiKeyHandle.InvalidHandle,
542 (int)KeyBlobType.PlainText,
546 int error = Marshal.GetLastWin32Error();
548 if (error != (int)ErrorCode.MoreData) {
549 throw new CryptographicException(error);
553 byte[] keyBlob = new byte[keySize];
554 if (!UnsafeNativeMethods.CryptExportKey(key,
555 SafeCapiKeyHandle.InvalidHandle,
556 (int)KeyBlobType.PlainText,
560 throw new CryptographicException(Marshal.GetLastWin32Error());
564 // Strip the headers from the key to access the raw data
566 // A PLAINTEXTBLOB is laid out as follows:
572 int keyDataOffset = Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int));
573 Debug.Assert(keyBlob.Length > keyDataOffset, "Key blob is in an unexpected format.");
575 int keyLength = BitConverter.ToInt32(keyBlob, Marshal.SizeOf(typeof(BLOBHEADER)));
576 Debug.Assert(keyLength > 0, "Unexpected key length.");
577 Debug.Assert(keyBlob.Length >= keyDataOffset + keyLength, "Key blob is in an unexpected format.");
579 byte[] keyData = new byte[keyLength];
580 Buffer.BlockCopy(keyBlob, keyDataOffset, keyData, 0, keyData.Length);
585 /// Map an algorithm ID to a string name
587 internal static string GetAlgorithmName(AlgorithmId algorithm) {
588 Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
590 return algorithm.ToString().ToUpper(CultureInfo.InvariantCulture);
594 /// Get the value of a specific hash parameter
596 [System.Security.SecurityCritical]
597 internal static byte[] GetHashParameter(SafeCapiHashHandle hashHandle, CapiNative.HashParameter parameter) {
598 Contract.Requires(hashHandle != null);
599 Contract.Requires(CapiNative.HashParameter.AlgorithmId <= parameter && parameter <= CapiNative.HashParameter.HashSize);
600 Contract.Ensures(Contract.Result<byte[]>() != null);
603 // Determine the maximum size of the parameter and retrieve it
606 int parameterSize = 0;
607 if (!CapiNative.UnsafeNativeMethods.CryptGetHashParam(hashHandle, parameter, null, ref parameterSize, 0)) {
608 throw new CryptographicException(Marshal.GetLastWin32Error());
611 Debug.Assert(0 < parameterSize, "Invalid parameter size returned");
612 byte[] parameterValue = new byte[parameterSize];
613 if (!CapiNative.UnsafeNativeMethods.CryptGetHashParam(hashHandle, parameter, parameterValue, ref parameterSize, 0)) {
614 throw new CryptographicException(Marshal.GetLastWin32Error());
617 // CAPI may have asked for a larger buffer than it used, so only copy the used bytes
618 if (parameterSize != parameterValue.Length) {
619 byte[] realValue = new byte[parameterSize];
620 Buffer.BlockCopy(parameterValue, 0, realValue, 0, parameterSize);
621 parameterValue = realValue;
624 return parameterValue;
628 /// Get information about a CSP. This should only be used for calls where the returned information
629 /// is in the form of a structure.
631 [System.Security.SecurityCritical]
632 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
633 internal static T GetProviderParameterStruct<T>(SafeCspHandle provider,
634 ProviderParameter parameter,
635 ProviderParameterFlags flags) where T : struct {
636 Contract.Requires(provider != null);
637 Contract.Requires(parameter == ProviderParameter.EnumerateAlgorithms);
639 // Figure out how big the parameter is
641 IntPtr buffer = IntPtr.Zero;
643 if (!UnsafeNativeMethods.CryptGetProvParam(provider, parameter, buffer, ref bufferSize, flags)) {
644 int errorCode = Marshal.GetLastWin32Error();
646 // NoMoreItems means that we've finished the enumeration we're currently working on, this is
647 // not a real error, so return an empty structure to mark the end.
648 if (errorCode == (int)ErrorCode.NoMoreItems) {
651 else if (errorCode != (int)ErrorCode.MoreData) {
652 throw new CryptographicException(errorCode);
656 Debug.Assert(Marshal.SizeOf(typeof(T)) <= bufferSize, "Buffer size does not match structure size");
659 // Pull the parameter back and marshal it into the return structure
662 RuntimeHelpers.PrepareConstrainedRegions();
664 // Allocate in a CER because we could fail between the alloc and the assignment
665 RuntimeHelpers.PrepareConstrainedRegions();
668 buffer = Marshal.AllocCoTaskMem(bufferSize);
671 if (!UnsafeNativeMethods.CryptGetProvParam(provider, parameter, buffer, ref bufferSize, flags)) {
672 throw new CryptographicException(Marshal.GetLastWin32Error());
675 return (T)Marshal.PtrToStructure(buffer, typeof(T));
678 if (buffer != IntPtr.Zero) {
679 Marshal.FreeCoTaskMem(buffer);
685 /// Map a verification result to a matching HRESULT
687 internal static int HResultForVerificationResult(SignatureVerificationResult verificationResult) {
688 switch (verificationResult) {
689 case SignatureVerificationResult.AssemblyIdentityMismatch:
690 case SignatureVerificationResult.PublicKeyTokenMismatch:
691 case SignatureVerificationResult.PublisherMismatch:
692 return (int)SignatureVerificationResult.BadSignatureFormat;
694 case SignatureVerificationResult.ContainingSignatureInvalid:
695 return (int)SignatureVerificationResult.BadDigest;
698 return (int)verificationResult;
703 /// Import a symmetric key into a CSP
705 [System.Security.SecurityCritical]
706 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
707 internal static SafeCapiKeyHandle ImportSymmetricKey(SafeCspHandle provider, AlgorithmId algorithm, byte[] key) {
708 Contract.Requires(provider != null);
709 Contract.Requires(((int)algorithm & (int)AlgorithmClass.DataEncryption) == (int)AlgorithmClass.DataEncryption);
710 Contract.Requires(key != null);
711 Contract.Ensures(Contract.Result<SafeCapiKeyHandle>() != null &&
712 !Contract.Result<SafeCapiKeyHandle>().IsInvalid &&
713 !Contract.Result<SafeCapiKeyHandle>().IsClosed);
716 // Setup a PLAINTEXTKEYBLOB (v2) which has the following format:
722 int blobSize = Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int)) + key.Length;
723 byte[] keyBlob = new byte[blobSize];
726 fixed (byte *pBlob = keyBlob) {
727 BLOBHEADER* pHeader = (BLOBHEADER*)pBlob;
728 pHeader->bType = KeyBlobType.PlainText;
729 pHeader->bVersion = 2;
730 pHeader->reserved = 0;
731 pHeader->aiKeyAlg = algorithm;
733 int* pSize = (int *)(pBlob + Marshal.SizeOf(*pHeader));
738 Buffer.BlockCopy(key, 0, keyBlob, Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int)), key.Length);
740 // Import the PLAINTEXTKEYBLOB into the CSP
741 SafeCapiKeyHandle importedKey = null;
743 RuntimeHelpers.PrepareConstrainedRegions();
745 if (!UnsafeNativeMethods.CryptImportKey(provider,
748 SafeCapiKeyHandle.InvalidHandle,
751 throw new CryptographicException(Marshal.GetLastWin32Error());
755 if (importedKey != null && !importedKey.IsInvalid) {
756 importedKey.SetParentCsp(provider);
763 /// Set a DWORD key parameter (KP_MODE and KP_MODE_BITS)
765 [System.Security.SecurityCritical]
766 internal static void SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, int value) {
767 Contract.Requires(key != null);
768 Contract.Requires(parameter == KeyParameter.Mode || parameter == KeyParameter.ModeBits);
770 SetKeyParameter(key, parameter, BitConverter.GetBytes(value));
774 /// Set the value of one of a key's parameters
776 [System.Security.SecurityCritical]
777 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
778 internal static void SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, byte[] value) {
779 Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
780 Contract.Requires(value != null);
782 if (!UnsafeNativeMethods.CryptSetKeyParam(key, parameter, value, 0)) {
783 throw new CryptographicException(Marshal.GetLastWin32Error());
787 //Wrapper methods for certificate extensions
790 /// Local alloc wrapper.
792 /// <param name="uFlags"></param>
793 /// <param name="sizetdwBytes"></param>
794 /// <returns></returns>
795 [SecuritySafeCritical]
796 internal static SafeLocalAllocHandle LocalAlloc(uint uFlags, IntPtr sizetdwBytes) {
797 SafeLocalAllocHandle safeLocalAllocHandle = UnsafeNativeMethods.LocalAlloc(uFlags, sizetdwBytes);
798 if (safeLocalAllocHandle == null || safeLocalAllocHandle.IsInvalid) {
799 throw new OutOfMemoryException();
801 return safeLocalAllocHandle;
807 /// <param name="pszStructType"></param>
808 /// <param name="pbEncoded"></param>
809 /// <param name="cbEncoded"></param>
810 /// <param name="decodedValue"></param>
811 /// <param name="cbDecodedValue"></param>
812 /// <returns></returns>
813 [SecuritySafeCritical]
814 internal static unsafe bool DecodeObject(IntPtr pszStructType,
817 out SafeLocalAllocHandle decodedValue,
818 out uint cbDecodedValue)
820 // Initialize out parameters
821 decodedValue = SafeLocalAllocHandle.InvalidHandle;
826 SafeLocalAllocHandle ptr = SafeLocalAllocHandle.InvalidHandle;
827 if (!UnsafeNativeMethods.CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
833 new IntPtr(&cbDecoded))) {
836 ptr = LocalAlloc(LMEM_FIXED, new IntPtr(cbDecoded));
838 if (!UnsafeNativeMethods.CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
844 new IntPtr(&cbDecoded))) {
847 // Return decoded values
849 cbDecodedValue = cbDecoded;
857 /// <param name="pszStructType"></param>
858 /// <param name="pbEncoded"></param>
859 /// <param name="decodedValue"></param>
860 /// <param name="cbDecodedValue"></param>
861 /// <returns></returns>
862 [SecuritySafeCritical]
863 internal static unsafe bool DecodeObject(IntPtr pszStructType,
865 out SafeLocalAllocHandle decodedValue,
866 out uint cbDecodedValue)
868 // Initialize out parameters
869 decodedValue = SafeLocalAllocHandle.InvalidHandle;
874 SafeLocalAllocHandle pbDecoded = SafeLocalAllocHandle.InvalidHandle;
876 if (!UnsafeNativeMethods.CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
879 (uint)pbEncoded.Length,
882 new IntPtr(&cbDecoded))) {
885 pbDecoded = LocalAlloc(LMEM_FIXED, new IntPtr(cbDecoded));
886 if (!UnsafeNativeMethods.CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
889 (uint)pbEncoded.Length,
892 new IntPtr(&cbDecoded))) {
895 // Return decoded values
896 decodedValue = pbDecoded;
897 cbDecodedValue = cbDecoded;
905 /// <param name="dwKeyType"></param>
906 /// <param name="pvKey"></param>
907 /// <param name="dwGroupId"></param>
908 /// <returns></returns>
909 [SecuritySafeCritical]
910 internal static CRYPT_OID_INFO CryptFindOIDInfo(
913 [In] OidGroup dwGroupId) {
915 if (pvKey == IntPtr.Zero) {
916 throw new ArgumentNullException("pvKey");
918 CRYPT_OID_INFO pOIDInfo = new CRYPT_OID_INFO(Marshal.SizeOf(typeof(CRYPT_OID_INFO)));
919 IntPtr pv = UnsafeNativeMethods.CryptFindOIDInfo(dwKeyType,
923 if (pv != IntPtr.Zero) {
924 pOIDInfo = (CRYPT_OID_INFO)Marshal.PtrToStructure(pv, typeof(CRYPT_OID_INFO));
932 /// <param name="dwKeyType"></param>
933 /// <param name="pvKey"></param>
934 /// <param name="dwGroupId"></param>
935 /// <returns></returns>
936 [SecuritySafeCritical]
937 internal static CRYPT_OID_INFO CryptFindOIDInfo(
939 [In] SafeLocalAllocHandle pvKey,
940 [In] OidGroup dwGroupId) {
943 throw new ArgumentNullException("pvKey");
945 if (pvKey.IsInvalid) {
946 throw new CryptographicException("SR.GetString(SR.Cryptography_InvalidHandle)", "pvKey");
948 CRYPT_OID_INFO pOIDInfo = new CRYPT_OID_INFO(Marshal.SizeOf(typeof(CRYPT_OID_INFO)));
949 IntPtr pv = UnsafeNativeMethods.CryptFindOIDInfo(dwKeyType,
953 if (pv != IntPtr.Zero) {
954 pOIDInfo = (CRYPT_OID_INFO)Marshal.PtrToStructure(pv, typeof(CRYPT_OID_INFO));
961 /// Safe local handle class
963 internal sealed class SafeLocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid {
964 [SecuritySafeCritical]
965 private SafeLocalAllocHandle()
969 [DllImport("kernel32.dll")]
970 private static extern IntPtr LocalFree(IntPtr hMem);
972 [SecuritySafeCritical]
973 internal T Read<T>(int offset) where T : struct {
974 bool addedRef = false;
975 RuntimeHelpers.PrepareConstrainedRegions();
977 DangerousAddRef(ref addedRef);
979 IntPtr pBase = new IntPtr((byte*)handle.ToPointer() + offset);
980 return (T)Marshal.PtrToStructure(pBase, typeof(T));
990 [SecuritySafeCritical]
991 protected override bool ReleaseHandle() {
992 return LocalFree(handle) == IntPtr.Zero;
995 [SecuritySafeCritical]
996 internal SafeLocalAllocHandle(IntPtr handle)
1001 internal static SafeLocalAllocHandle InvalidHandle {
1002 [SecuritySafeCritical]
1003 get { return new SafeLocalAllocHandle(IntPtr.Zero); }
1010 internal class X509Utils {
1012 [SecuritySafeCritical]
1013 internal static SafeLocalAllocHandle StringToAnsiPtr(string s) {
1014 byte[] arr = new byte[s.Length + 1];
1015 Encoding.ASCII.GetBytes(s, 0, s.Length, arr, 0);
1016 SafeLocalAllocHandle pb = CapiNative.LocalAlloc(CapiNative.LMEM_FIXED, new IntPtr(arr.Length));
1017 Marshal.Copy(arr, 0, pb.DangerousGetHandle(), arr.Length);