添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Security / Cryptography / CapiNative.cs / 1305376 / CapiNative.cs // ==++== // ==--== using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security; using System.Diagnostics.Contracts; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography { /// Native interop with CAPI. Native definitions can be found in wincrypt.h or msaxlapi.h internal static class CapiNative { internal enum AlgorithmClass { DataEncryption = (3 << 13), // ALG_CLASS_DATA_ENCRYPT Hash = (4 << 13) // ALG_CLASS_HASH internal enum AlgorithmType { Any = (0 << 9), // ALG_TYPE_ANY Block = (3 << 9) // ALG_TYPE_BLOCK internal enum AlgorithmSubId { MD5 = 3, // ALG_SID_MD5 Sha1 = 4, // ALG_SID_SHA1 Sha256 = 12, // ALG_SID_SHA_256 Sha384 = 13, // ALG_SID_SHA_384 Sha512 = 14, // ALG_SID_SHA_512 Aes128 = 14, // ALG_SID_AES_128 Aes192 = 15, // ALG_SID_AES_192 Aes256 = 16 // ALG_SID_AES_256 internal enum AlgorithmId { None = 0, Aes128 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes128), // CALG_AES_128 Aes192 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes192), // CALG_AES_192 Aes256 = (AlgorithmClass.DataEncryption | AlgorithmType.Block | AlgorithmSubId.Aes256), // CALG_AES_256 MD5 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.MD5), // CALG_MD5 Sha1 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha1), // CALG_SHA1 Sha256 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha256), // CALG_SHA_256 Sha384 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha384), // CALG_SHA_384 Sha512 = (AlgorithmClass.Hash | AlgorithmType.Any | AlgorithmSubId.Sha512) // CALG_SHA_512 /// Flags for the CryptAcquireContext API [Flags] internal enum CryptAcquireContextFlags { None = 0x00000000, VerifyContext = unchecked((int)0xF0000000) // CRYPT_VERIFYCONTEXT /// Error codes returned from CAPI internal enum ErrorCode { Success = 0x00000000, // ERROR_SUCCESS MoreData = 0x00000ea, // ERROR_MORE_DATA NoMoreItems = 0x00000103, // ERROR_NO_MORE_ITEMS BadData = unchecked((int)0x80090005), // NTE_BAD_DATA BadAlgorithmId = unchecked((int)0x80090008), // NTE_BAD_ALGID ProviderTypeNotDefined = unchecked((int)0x80090017), // NTE_PROV_TYPE_NOT_DEF KeysetNotDefined = unchecked((int)0x80090019) // NTE_KEYSET_NOT_DEF /// Parameters that GetHashParam can query internal enum HashParameter { None = 0x0000, AlgorithmId = 0x0001, // HP_ALGID HashValue = 0x0002, // HP_HASHVAL HashSize = 0x0004 // HP_HASHSIZE /// Formats of blobs that keys can appear in internal enum KeyBlobType : byte { PlainText = 0x8 // PLAINTEXTKEYBLOB /// Flags for CryptGenKey and CryptImportKey [Flags] internal enum KeyFlags { None = 0x0000, Exportable = 0x0001 // CRYPT_EXPORTABLE /// Parameters of a cryptographic key used by SetKeyParameter internal enum KeyParameter { None = 0, IV = 1, // KP_IV Mode = 4, // KP_MODE ModeBits = 5 // KP_MODE_BITS /// Well-known names of crypto service providers internal static class ProviderNames { // MS_ENH_RSA_AES_PROV public const string MicrosoftEnhancedRsaAes = "Microsoft Enhanced RSA and AES Cryptographic Provider"; public const string MicrosoftEnhancedRsaAesPrototype = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"; /// Parameters exposed by a CSP internal enum ProviderParameter { None = 0, EnumerateAlgorithms = 1 // PP_ENUMALGS /// Flags controlling information retrieved about a provider parameter [Flags] internal enum ProviderParameterFlags { None = 0x00000000, RestartEnumeration = 0x00000001 // CRYPT_FIRST /// Provider type accessed in a crypto service provider. These provide the set of algorithms /// available to use for an application. internal enum ProviderType { None = 0, RsaAes = 24 // PROV_RSA_AES [StructLayout(LayoutKind.Sequential)] internal struct BLOBHEADER { public KeyBlobType bType; public byte bVersion; public short reserved; public AlgorithmId aiKeyAlg; [StructLayout(LayoutKind.Sequential)] internal struct CRYPTOAPI_BLOB { public int cbData; public IntPtr pbData; [StructLayout(LayoutKind.Sequential)] internal unsafe struct PROV_ENUMALGS { public AlgorithmId aiAlgId; public int dwBitLen; public int dwNameLen; public fixed byte szName[20]; #pragma warning disable 618 // Have not migrated to v4 transparency yet [SecurityCritical(SecurityCriticalScope.Everything)] #pragma warning restore 618 [SuppressUnmanagedCodeSecurity] internal static class UnsafeNativeMethods { /// Calculate the public key token for a given public key [DllImport("clr")] public static extern int _AxlPublicKeyBlobToPublicKeyToken(ref CRYPTOAPI_BLOB pCspPublicKeyBlob, [Out] out SafeAxlBufferHandle ppwszPublicKeyToken); /// Open a crypto service provider, if a key container is specified KeyContainerPermission /// should be demanded. [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptAcquireContext([Out] out SafeCspHandle phProv, string pszContainer, string pszProvider, ProviderType dwProvType, CryptAcquireContextFlags dwFlags); /// Prepare a new hash algorithm for use [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptCreateHash(SafeCspHandle hProv, AlgorithmId Algid, SafeCapiKeyHandle hKey, int dwFlags, [Out] out SafeCapiHashHandle phHash); /// Decrypt a block of data [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptDecrypt(SafeCapiKeyHandle hKey, SafeCapiHashHandle hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, int dwFlags, IntPtr pbData, // BYTE * [In, Out] ref int pdwDataLen); /// Duplicate a key handle [DllImport("advapi32")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptDuplicateKey(SafeCapiKeyHandle hKey, IntPtr pdwReserved, int dwFlags, [Out] out SafeCapiKeyHandle phKey); /// Encrypt a block of data [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptEncrypt(SafeCapiKeyHandle hKey, SafeCapiHashHandle hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, int dwFlags, IntPtr pbData, // BYTE * [In, Out] ref int pdwDataLen, int dwBufLen); /// Export a key into a byte array [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptExportKey(SafeCapiKeyHandle hKey, SafeCapiKeyHandle hExpKey, int dwBlobType, // (int)KeyBlobType int dwExportFlags, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbData, [In, Out] ref int pdwDataLen); /// Generate a random key [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptGenKey(SafeCspHandle hProv, AlgorithmId Algid, KeyFlags dwFlags, [Out] out SafeCapiKeyHandle phKey); /// Fill a buffer with cryptographically random bytes [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptGenRandom(SafeCspHandle hProv, int dwLen, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbBuffer); /// Get information about a hash algorithm, including the current value [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptGetHashParam(SafeCapiHashHandle hHash, HashParameter dwParam, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbData, [In, Out] ref int pdwDataLen, int dwFlags); /// Get information about a CSP [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptGetProvParam(SafeCspHandle hProv, ProviderParameter dwParam, IntPtr pbData, [In, Out] ref int pdwDataLen, ProviderParameterFlags dwFlags); /// Add a block of data to a hash [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptHashData(SafeCapiHashHandle hHash, [MarshalAs(UnmanagedType.LPArray)] byte[] pbData, int dwDataLen, int dwFlags); /// Import a key into a CSP [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptImportKey(SafeCspHandle hProv, [MarshalAs(UnmanagedType.LPArray)] byte[] pbData, int dwDataLen, SafeCapiKeyHandle hPubKey, KeyFlags dwFlags, [Out] out SafeCapiKeyHandle phKey); /// Set a property of a key [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptSetKeyParam(SafeCapiKeyHandle hKey, KeyParameter dwParam, [MarshalAs(UnmanagedType.LPArray)] byte[] pbData, int dwFlags); // Utility and wrapper functions /// Acquire a crypto service provider [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] internal static SafeCspHandle AcquireCsp(string keyContainer, string providerName, ProviderType providerType, CryptAcquireContextFlags flags, bool throwPlatformException) { Contract.Ensures(Contract.Result () != null && !Contract.Result ().IsInvalid && !Contract.Result ().IsClosed); SafeCspHandle cspHandle = null; if (!UnsafeNativeMethods.CryptAcquireContext(out cspHandle, keyContainer, providerName, providerType, flags)) { // If the platform doesn't have the specified CSP, we'll either get a ProviderTypeNotDefined // or a KeysetNotDefined error depending on the CAPI version. int error = Marshal.GetLastWin32Error(); if (throwPlatformException && (error == (int)CapiNative.ErrorCode.ProviderTypeNotDefined || error == (int)CapiNative.ErrorCode.KeysetNotDefined)) { throw new PlatformNotSupportedException(SR.GetString(SR.Cryptography_PlatformNotSupported)); else { throw new CryptographicException(error); return cspHandle; /// Export a symmetric algorithm key into a byte array [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] internal static byte[] ExportSymmetricKey(SafeCapiKeyHandle key) { Contract.Requires(key != null); Contract.Ensures(Contract.Result () != null && Contract.Result ().Length > 0); // Figure out how big the key blob is, and export it int keySize = 0; if (!UnsafeNativeMethods.CryptExportKey(key, SafeCapiKeyHandle.InvalidHandle, (int)KeyBlobType.PlainText, null, ref keySize)) { int error = Marshal.GetLastWin32Error(); if (error != (int)ErrorCode.MoreData) { throw new CryptographicException(error); byte[] keyBlob = new byte[keySize]; if (!UnsafeNativeMethods.CryptExportKey(key, SafeCapiKeyHandle.InvalidHandle, (int)KeyBlobType.PlainText, keyBlob, ref keySize)) { throw new CryptographicException(Marshal.GetLastWin32Error()); // Strip the headers from the key to access the raw data // A PLAINTEXTBLOB is laid out as follows: // BLOBHEADER hdr // DWORD cbKeySize // BYTE rbgKeyData[] int keyDataOffset = Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int)); Debug.Assert(keyBlob.Length > keyDataOffset, "Key blob is in an unexpected format."); int keyLength = BitConverter.ToInt32(keyBlob, Marshal.SizeOf(typeof(BLOBHEADER))); Debug.Assert(keyLength > 0, "Unexpected key length."); Debug.Assert(keyBlob.Length >= keyDataOffset + keyLength, "Key blob is in an unexpected format."); byte[] keyData = new byte[keyLength]; Buffer.BlockCopy(keyBlob, keyDataOffset, keyData, 0, keyData.Length); return keyData; /// Map an algorithm ID to a string name internal static string GetAlgorithmName(AlgorithmId algorithm) { Contract.Ensures(!String.IsNullOrEmpty(Contract.Result ())); return algorithm.ToString().ToUpper(CultureInfo.InvariantCulture); /// Get the value of a specific hash parameter [System.Security.SecurityCritical] internal static byte[] GetHashParameter(SafeCapiHashHandle hashHandle, CapiNative.HashParameter parameter) { Contract.Requires(hashHandle != null); Contract.Requires(CapiNative.HashParameter.AlgorithmId <= parameter && parameter <= CapiNative.HashParameter.HashSize); Contract.Ensures(Contract.Result () != null); // Determine the maximum size of the parameter and retrieve it int parameterSize = 0; if (!CapiNative.UnsafeNativeMethods.CryptGetHashParam(hashHandle, parameter, null, ref parameterSize, 0)) { throw new CryptographicException(Marshal.GetLastWin32Error()); Debug.Assert(0 < parameterSize, "Invalid parameter size returned"); byte[] parameterValue = new byte[parameterSize]; if (!CapiNative.UnsafeNativeMethods.CryptGetHashParam(hashHandle, parameter, parameterValue, ref parameterSize, 0)) { throw new CryptographicException(Marshal.GetLastWin32Error()); // CAPI may have asked for a larger buffer than it used, so only copy the used bytes if (parameterSize != parameterValue.Length) { byte[] realValue = new byte[parameterSize]; Buffer.BlockCopy(parameterValue, 0, realValue, 0, parameterSize); parameterValue = realValue; return parameterValue; /// Get information about a CSP. This should only be used for calls where the returned information /// is in the form of a structure. [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] internal static T GetProviderParameterStruct (SafeCspHandle provider, ProviderParameter parameter, ProviderParameterFlags flags) where T : struct { Contract.Requires(provider != null); Contract.Requires(parameter == ProviderParameter.EnumerateAlgorithms); // Figure out how big the parameter is int bufferSize = 0; IntPtr buffer = IntPtr.Zero; if (!UnsafeNativeMethods.CryptGetProvParam(provider, parameter, buffer, ref bufferSize, flags)) { int errorCode = Marshal.GetLastWin32Error(); // NoMoreItems means that we've finished the enumeration we're currently working on, this is // not a real error, so return an empty structure to mark the end. if (errorCode == (int)ErrorCode.NoMoreItems) { return new T(); else if (errorCode != (int)ErrorCode.MoreData) { throw new CryptographicException(errorCode); Debug.Assert(Marshal.SizeOf(typeof(T)) <= bufferSize, "Buffer size does not match structure size"); // Pull the parameter back and marshal it into the return structure RuntimeHelpers.PrepareConstrainedRegions(); try { // Allocate in a CER because we could fail between the alloc and the assignment RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { buffer = Marshal.AllocCoTaskMem(bufferSize); if (!UnsafeNativeMethods.CryptGetProvParam(provider, parameter, buffer, ref bufferSize, flags)) { throw new CryptographicException(Marshal.GetLastWin32Error()); return (T)Marshal.PtrToStructure(buffer, typeof(T)); finally { if (buffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(buffer); /// Map a verification result to a matching HRESULT internal static int HResultForVerificationResult(SignatureVerificationResult verificationResult) { switch (verificationResult) { case SignatureVerificationResult.AssemblyIdentityMismatch: case SignatureVerificationResult.PublicKeyTokenMismatch: case SignatureVerificationResult.PublisherMismatch: return (int)SignatureVerificationResult.BadSignatureFormat; case SignatureVerificationResult.ContainingSignatureInvalid: return (int)SignatureVerificationResult.BadDigest; default: return (int)verificationResult; /// Import a symmetric key into a CSP [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] internal static SafeCapiKeyHandle ImportSymmetricKey(SafeCspHandle provider, AlgorithmId algorithm, byte[] key) { Contract.Requires(provider != null); Contract.Requires(((int)algorithm & (int)AlgorithmClass.DataEncryption) == (int)AlgorithmClass.DataEncryption); Contract.Requires(key != null); Contract.Ensures(Contract.Result () != null && !Contract.Result ().IsInvalid && !Contract.Result ().IsClosed); // Setup a PLAINTEXTKEYBLOB (v2) which has the following format: // BLOBHEADER hdr // DWORD cbKeySize // BYTE rbgKeyData[] int blobSize = Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int)) + key.Length; byte[] keyBlob = new byte[blobSize]; unsafe { fixed (byte *pBlob = keyBlob) { BLOBHEADER* pHeader = (BLOBHEADER*)pBlob; pHeader->bType = KeyBlobType.PlainText; pHeader->bVersion = 2; pHeader->reserved = 0; pHeader->aiKeyAlg = algorithm; int* pSize = (int *)(pBlob + Marshal.SizeOf(*pHeader)); *pSize = key.Length; Buffer.BlockCopy(key, 0, keyBlob, Marshal.SizeOf(typeof(BLOBHEADER)) + Marshal.SizeOf(typeof(int)), key.Length); // Import the PLAINTEXTKEYBLOB into the CSP SafeCapiKeyHandle importedKey = null; if (!UnsafeNativeMethods.CryptImportKey(provider, keyBlob, keyBlob.Length, SafeCapiKeyHandle.InvalidHandle, KeyFlags.Exportable, out importedKey)) { throw new CryptographicException(Marshal.GetLastWin32Error()); return importedKey; /// Set a DWORD key parameter (KP_MODE and KP_MODE_BITS) [System.Security.SecurityCritical] internal static void SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, int value) { Contract.Requires(key != null); Contract.Requires(parameter == KeyParameter.Mode || parameter == KeyParameter.ModeBits); SetKeyParameter(key, parameter, BitConverter.GetBytes(value)); /// Set the value of one of a key's parameters [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] internal static void SetKeyParameter(SafeCapiKeyHandle key, KeyParameter parameter, byte[] value) { Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed); Contract.Requires(value != null); if (!UnsafeNativeMethods.CryptSetKeyParam(key, parameter, value, 0)) { throw new CryptographicException(Marshal.GetLastWin32Error()); // File provided for Reference Use Only by Microsoft Corporation (c) 2007.