Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Security / Cryptography / CapiNative.cs / 1305376 / CapiNative.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
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,
0,
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,
0,
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.
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
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,
0,
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,
0,
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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UidPropertyAttribute.cs
- TabRenderer.cs
- ConfigXmlComment.cs
- RpcCryptoContext.cs
- DataView.cs
- SmtpLoginAuthenticationModule.cs
- AssemblyBuilder.cs
- CodeValidator.cs
- ObjectComplexPropertyMapping.cs
- GridViewRow.cs
- EpmContentDeSerializerBase.cs
- OperatorExpressions.cs
- CompositeActivityValidator.cs
- AudioLevelUpdatedEventArgs.cs
- PaperSource.cs
- EpmTargetTree.cs
- HijriCalendar.cs
- SoapCodeExporter.cs
- CopyOnWriteList.cs
- DataGridHeadersVisibilityToVisibilityConverter.cs
- loginstatus.cs
- EdmItemCollection.OcAssemblyCache.cs
- PageParserFilter.cs
- MultiDataTrigger.cs
- SpellerInterop.cs
- CharConverter.cs
- PartialCachingAttribute.cs
- SimpleWorkerRequest.cs
- FtpRequestCacheValidator.cs
- ListViewDeleteEventArgs.cs
- CharacterMetricsDictionary.cs
- DbMetaDataCollectionNames.cs
- XmlSchemaComplexType.cs
- StyleSheet.cs
- DrawingDrawingContext.cs
- CngAlgorithm.cs
- PropertyCollection.cs
- CompilationUnit.cs
- MailMessageEventArgs.cs
- DbCommandTree.cs
- Aggregates.cs
- DateTimeFormatInfoScanner.cs
- EntityModelSchemaGenerator.cs
- UInt16Storage.cs
- XmlNamedNodeMap.cs
- SchemaContext.cs
- DataGridItemEventArgs.cs
- FragmentNavigationEventArgs.cs
- CheckBoxFlatAdapter.cs
- DataGridViewCell.cs
- FormsAuthenticationCredentials.cs
- SimpleTypeResolver.cs
- ToggleButton.cs
- ClientOptions.cs
- ModelItemCollectionImpl.cs
- CollectionViewGroup.cs
- SocketAddress.cs
- EntityModelBuildProvider.cs
- NotificationContext.cs
- SymbolPair.cs
- UInt16Converter.cs
- BindingList.cs
- GeneralTransform3DGroup.cs
- AppSettingsReader.cs
- PublishLicense.cs
- HtmlTextArea.cs
- SmiConnection.cs
- Object.cs
- SecurityTokenProvider.cs
- ProfilePropertySettingsCollection.cs
- PageAsyncTask.cs
- WizardPanelChangingEventArgs.cs
- MemoryFailPoint.cs
- StrokeNodeData.cs
- OrderedEnumerableRowCollection.cs
- BooleanAnimationBase.cs
- StyleCollection.cs
- ClientSettingsStore.cs
- mda.cs
- PiiTraceSource.cs
- StatusBarPanel.cs
- RoutedCommand.cs
- TraceInternal.cs
- ValidationHelper.cs
- PageSettings.cs
- WebConvert.cs
- PartialArray.cs
- FindCriteriaElement.cs
- MarshalByValueComponent.cs
- WebPageTraceListener.cs
- DataGridViewCellStateChangedEventArgs.cs
- KeyboardEventArgs.cs
- Action.cs
- DbResourceAllocator.cs
- FileDataSourceCache.cs
- DictionaryBase.cs
- QueryStack.cs
- WebConfigurationHostFileChange.cs
- SHA256Managed.cs
- XmlSchemaIdentityConstraint.cs