using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.InteropServices;
using static Vanara.PInvoke.Crypt32;

namespace Vanara.PInvoke
{
	public static partial class AdvApi32
	{
		private delegate bool CryptGetValueMethod<THandle, TEnum>(THandle hKey, TEnum dwParam, IntPtr pbData, ref uint pdwDataLen, uint dwFlags) where THandle : struct where TEnum : Enum;

		/// <summary>Flag values for <see cref="CryptAcquireContext"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "57e13662-3189-4f8d-b90a-d1fbdc09b63c")]
		[Flags]
		public enum CryptAcquireContextFlags : uint
		{
			/// <summary>
			/// This option is intended for applications that are using ephemeral keys, or applications that do not require access to
			/// persisted private keys, such as applications that perform only hashing, encryption, and digital signature verification. Only
			/// applications that create signatures or decrypt messages need access to a private key. In most cases, this flag should be
			/// set. For file-based CSPs, when this flag is set, the pszContainer parameter must be set to NULL. The application has no
			/// access to the persisted private keys of public/private key pairs. When this flag is set, temporary public/private key pairs
			/// can be created, but they are not persisted. For hardware-based CSPs, such as a smart card CSP, if the pszContainer parameter
			/// is NULL or blank, this flag implies that no access to any keys is required, and that no UI should be presented to the user.
			/// This form is used to connect to the CSP to query its capabilities but not to actually use its keys. If the pszContainer
			/// parameter is not NULL and not blank, then this flag implies that access to only the publicly available information within
			/// the specified container is required. The CSP should not ask for a PIN. Attempts to access private information (for example,
			/// the CryptSignHash function) will fail. When CryptAcquireContext is called, many CSPs require input from the owning user
			/// before granting access to the private keys in the key container. For example, the private keys can be encrypted, requiring a
			/// password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private
			/// keys is not required and the user interface can be bypassed.
			/// </summary>
			CRYPT_VERIFYCONTEXT = 0xF0000000,

			/// <summary>
			/// Creates a new key container with the name specified by pszContainer. If pszContainer is NULL, a key container with the
			/// default name is created.
			/// </summary>
			CRYPT_NEWKEYSET = 0x00000008,

			/// <summary>
			/// Delete the key container specified by pszContainer. If pszContainer is NULL, the key container with the default name is
			/// deleted. All key pairs in the key container are also destroyed. When this flag is set, the value returned in phProv is
			/// undefined, and thus, the CryptReleaseContext function need not be called afterward.
			/// </summary>
			CRYPT_DELETEKEYSET = 0x00000010,

			/// <summary>
			/// By default, keys and key containers are stored as user keys. For Base Providers, this means that user key containers are
			/// stored in the user's profile. A key container created without this flag by an administrator can be accessed only by the user
			/// creating the key container and a user with administration privileges. Windows XP: A key container created without this flag
			/// by an administrator can be accessed only by the user creating the key container and the local system account. A key
			/// container created without this flag by a user that is not an administrator can be accessed only by the user creating the key
			/// container and the local system account. The CRYPT_MACHINE_KEYSET flag can be combined with all of the other flags to
			/// indicate that the key container of interest is a computer key container and the CSP treats it as such. For Base Providers,
			/// this means that the keys are stored locally on the computer that created the key container. If a key container is to be a
			/// computer container, the CRYPT_MACHINE_KEYSET flag must be used with all calls to CryptAcquireContext that reference the
			/// computer container. The key container created with CRYPT_MACHINE_KEYSET by an administrator can be accessed only by its
			/// creator and by a user with administrator privileges unless access rights to the container are granted using
			/// CryptSetProvParam. Windows XP: The key container created with CRYPT_MACHINE_KEYSET by an administrator can be accessed only
			/// by its creator and by the local system account unless access rights to the container are granted using CryptSetProvParam.
			/// The key container created with CRYPT_MACHINE_KEYSET by a user that is not an administrator can be accessed only by its
			/// creator and by the local system account unless access rights to the container are granted using CryptSetProvParam. The
			/// CRYPT_MACHINE_KEYSET flag is useful when the user is accessing from a service or user account that did not log on
			/// interactively. When key containers are created, most CSPs do not automatically create any public/private key pairs. These
			/// keys must be created as a separate step with the CryptGenKey function.
			/// </summary>
			CRYPT_MACHINE_KEYSET = 0x00000020,

			/// <summary>
			/// The application requests that the CSP not display any user interface (UI) for this context. If the CSP must display the UI
			/// to operate, the call fails and the NTE_SILENT_CONTEXT error code is set as the last error. In addition, if calls are made to
			/// CryptGenKey with the CRYPT_USER_PROTECTED flag with a context that has been acquired with the CRYPT_SILENT flag, the calls
			/// fail and the CSP sets NTE_SILENT_CONTEXT. CRYPT_SILENT is intended for use with applications for which the UI cannot be
			/// displayed by the CSP.
			/// </summary>
			CRYPT_SILENT = 0x00000040,

			/// <summary>
			/// Obtains a context for a smart card CSP that can be used for hashing and symmetric key operations but cannot be used for any
			/// operation that requires authentication to a smart card using a PIN. This type of context is most often used to perform
			/// operations on an empty smart card, such as setting the PIN by using CryptSetProvParam. This flag can only be used with smart
			/// card CSPs. Windows Server 2003 and Windows XP: This flag is not supported.
			/// </summary>
			CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080,
		}

		/// <summary>Flags for CryptDecrypt.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "7c3d2838-6fd1-4f6c-9586-8b94b459a31a")]
		[Flags]
		public enum CryptDecryptFlags
		{
			/// <summary>
			/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
			/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the
			/// CRYPT_DECRYPT_RSA_NO_PADDING_CHECK flag.
			/// </summary>
			CRYPT_OAEP = 0x00000040,

			/// <summary>
			/// Perform the decryption on the BLOB without checking the padding. This flag is only supported by the Microsoft Enhanced
			/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the CRYPT_OAEP flag.
			/// </summary>
			CRYPT_DECRYPT_RSA_NO_PADDING_CHECK = 0x00000020,
		}

		/// <summary>Flags for CryptEncrypt.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "697c4960-552b-4c3a-95cf-4632af56945b")]
		[Flags]
		public enum CryptEncryptFlags
		{
			/// <summary>
			/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
			/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the
			/// CRYPT_DECRYPT_RSA_NO_PADDING_CHECK flag.
			/// </summary>
			CRYPT_OAEP = 0x00000040,
		}

		/// <summary>Flags for <see cref="CryptExportKey"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "8a7c7b46-3bea-4043-b568-6d91d6335737")]
		[Flags]
		public enum CryptExportKeyFlags
		{
			/// <summary>This flag causes this function to export version 3 of a BLOB type.</summary>
			CRYPT_BLOB_VER3 = 0x00000080,

			/// <summary>This flag destroys the original key in the OPAQUEKEYBLOB. This flag is available in Schannel CSPs only.</summary>
			CRYPT_DESTROYKEY = 0x00000004,

			/// <summary>
			/// This flag causes PKCS #1 version 2 formatting to be created with the RSA encryption and decryption when exporting SIMPLEBLOBs.
			/// </summary>
			CRYPT_OAEP = 0x00000040,

			/// <summary>
			/// The first eight bytes of the RSA encryption block padding must be set to 0x03 rather than to random data. This prevents
			/// version rollback attacks and is discussed in the SSL3 specification. This flag is available for Schannel CSPs only.
			/// </summary>
			CRYPT_SSL2_FALLBACK = 0x00000002,

			/// <summary>This flag is not used.</summary>
			CRYPT_Y_ONLY = 0x00000001,

			/// <summary></summary>
			CRYPT_IPSEC_HMAC_KEY = 0x00000100,
		}

		/// <summary>Flags for <see cref="CryptDeriveKey"/> and <see cref="CryptGenKey"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "b65dd856-2dfa-4cda-9b2f-b32f3c291470")]
		[Flags]
		public enum CryptGenKeyFlags : uint
		{
			/// <summary>
			/// If this flag is set, the session key can be transferred out of the CSP into a key BLOB through the CryptExportKey function.
			/// Because keys generally must be exportable, this flag should usually be set.
			/// <para>
			/// If this flag is not set, then the session key is not exportable. This means the key is available only within the current
			/// session and only the application that created it is able to use it.
			/// </para>
			/// <para>This flag does not apply to public/private key pairs.</para>
			/// </summary>
			CRYPT_EXPORTABLE = 0x00000001,

			/// <summary>
			/// If this flag is set, the user is notified through a dialog box or another method when certain actions are attempting to use
			/// this key. The precise behavior is specified by the CSP being used. If the provider context was opened with the CRYPT_SILENT
			/// flag set, using this flag causes a failure and the last error is set to NTE_SILENT_CONTEXT.
			/// </summary>
			CRYPT_USER_PROTECTED = 0x00000002,

			/// <summary>
			/// Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value
			/// is 128 bits and the session key is 40 bits, there will be 88 bits left over.
			/// <para>
			/// If this flag is set, then the key is assigned a salt value based on the unused hash value bits. You can retrieve this salt
			/// value by using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT.
			/// </para>
			/// <para>If this flag is not set, then the key is given a salt value of zero.</para>
			/// <para>
			/// When keys with nonzero salt values are exported (by using CryptExportKey), the salt value must also be obtained and kept
			/// with the key BLOB.
			/// </para>
			/// </summary>
			CRYPT_CREATE_SALT = 0x00000004,

			/// <summary>
			/// Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called
			/// multiple times.
			/// <para>
			/// If this flag is set, a new session key is not generated.Instead, the key specified by phKey is modified.The precise behavior
			/// of this flag is dependent on the type of key being generated and on the particular CSP being used.
			/// </para>
			/// <para>Microsoft cryptographic service providers ignore this flag.</para>
			/// </summary>
			CRYPT_UPDATE_KEY = 0x00000008,

			/// <summary>
			/// This flag specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Salt Value Functionality.
			/// </summary>
			CRYPT_NO_SALT = 0x00000010,

			/// <summary>
			/// This flag specifies an initial Diffie-Hellman or DSS key generation. This flag is useful only with Diffie-Hellman and DSS
			/// CSPs. When used, a default key length will be used unless a key length is specified in the upper 16 bits of the dwFlags
			/// parameter. If parameters that involve key lengths are set on a PREGEN Diffie-Hellman or DSS key using CryptSetKeyParam, the
			/// key lengths must be compatible with the key length set here.
			/// </summary>
			CRYPT_PREGEN = 0x00000040,

			/// <summary>This flag is not used.</summary>
			CRYPT_RECIPIENT = 0x00000010,

			/// <summary>This flag is not used.</summary>
			CRYPT_INITIATOR = 0x00000040,

			/// <summary>This flag is not used.</summary>
			CRYPT_ONLINE = 0x00000080,

			/// <summary>This flag is not used.</summary>
			CRYPT_SF = 0x00000100,

			/// <summary>This flag is not used.</summary>
			CRYPT_CREATE_IV = 0x00000200,

			/// <summary>This flag is not used.</summary>
			CRYPT_KEK = 0x00000400,

			/// <summary>This flag is not used.</summary>
			CRYPT_DATA_KEY = 0x00000800,

			/// <summary>This flag is not used.</summary>
			CRYPT_VOLATILE = 0x00001000,

			/// <summary>This flag is not used.</summary>
			CRYPT_SGCKEY = 0x00002000,

			/// <summary>This flag is not used.</summary>
			CRYPT_USER_PROTECTED_STRONG = 0x00100000,

			/// <summary>
			/// If this flag is set, the key can be exported until its handle is closed by a call to CryptDestroyKey. This allows newly
			/// generated keys to be exported upon creation for archiving or key recovery. After the handle is closed, the key is no longer exportable.
			/// </summary>
			CRYPT_ARCHIVABLE = 0x00004000,

			/// <summary>
			/// <para>
			/// This flag specifies strong key protection. When this flag is set, the user is prompted to enter a password for the key when
			/// the key is created. The user will be prompted to enter the password whenever this key is used.
			/// </para>
			/// <para>
			/// This flag is only used by the CSPs that are provided by Microsoft. Third party CSPs will define their own behavior for
			/// strong key protection.
			/// </para>
			/// <para>
			/// Specifying this flag causes the same result as calling this function with the CRYPT_USER_PROTECTED flag when strong key
			/// protection is specified in the system registry.
			/// </para>
			/// <para>
			/// If this flag is specified and the provider handle in the hProv parameter was created by using the CRYPT_VERIFYCONTEXT or
			/// CRYPT_SILENT flag, this function will set the last error to NTE_SILENT_CONTEXT and return zero.
			/// </para>
			/// <para>Windows Server 2003 and Windows XP: This flag is not supported.</para>
			/// </summary>
			CRYPT_FORCE_KEY_PROTECTION_HIGH = 0x00008000,

			/// <summary>
			/// This flag is used only with Schannel providers. If this flag is set, the key to be generated is a server-write key;
			/// otherwise, it is a client-write key.
			/// </summary>
			CRYPT_SERVER = 0x400,
		}

		/// <summary>Flags for <see cref="CryptHashSessionKey"/>.</summary>
		[Flags]
		public enum CryptHashSessionKeyFlags
		{
			/// <summary>
			/// When this flag is set, the bytes of the key are hashed in little-endian form. Note that by default (when dwFlags is zero),
			/// the bytes of the key are hashed in big-endian form.
			/// </summary>
			CRYPT_LITTLE_ENDIAN = 1
		}

		/// <summary>Flags for <see cref="CryptGetDefaultProvider"/> and <see cref="CryptSetProviderEx"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "5d15641e-1ad7-441d-9423-65fd51de9812")]
		[Flags]
		public enum CryptProviderFlags
		{
			/// <summary>Returns the user-context default CSP of the specified type.</summary>
			CRYPT_USER_DEFAULT = 0x00000002,

			/// <summary>Returns the computer default CSP of the specified type.</summary>
			CRYPT_MACHINE_DEFAULT = 0x00000001,

			/// <summary>Can be used in conjunction with CRYPT_MACHINE_DEFAULT or CRYPT_USER_DEFAULT to delete the default.</summary>
			CRYPT_DELETE_DEFAULT = 0x00000004,
		}

		/// <summary>Flags for <see cref="CryptSignHash"/> and <see cref="CryptVerifySignature"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "3119eabc-90ff-42c6-b3fa-e8be625f6d1e")]
		[Flags]
		public enum CryptSignFlags
		{
			/// <summary>
			/// This flag is used with RSA providers. When verifying the signature, the hash object identifier (OID) is not expected to be
			/// present or checked. If this flag is not set, the hash OID in the default signature is verified as specified in the
			/// definition of DigestInfo in PKCS #7.
			/// </summary>
			CRYPT_NOHASHOID = 0x00000001,

			/// <summary>This flag is not used.</summary>
			CRYPT_TYPE2_FORMAT = 0x00000002,

			/// <summary>Use X.931 support for the FIPS 186-2–compliant version of RSA (rDSA).</summary>
			CRYPT_X931_FORMAT = 0x00000004,
		}

		/// <summary>Query type.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "ed008c07-1a40-4075-bdaa-eb7f7e12d9c3")]
		public enum HashParam
		{
			/// <summary>
			/// An ALG_ID that indicates the algorithm specified when the hash object was created. For a list of hash algorithms, see CryptCreateHash.
			/// </summary>
			[CorrespondingType(typeof(ALG_ID), CorrespondingAction.Get)]
			[CorrespondingType(typeof(uint))]
			HP_ALGID = 0x0001,

			/// <summary>
			/// The hash value or message hash for the hash object specified by hHash. This value is generated based on the data supplied to
			/// the hash object earlier through the CryptHashData and CryptHashSessionKey functions.
			/// <para>
			/// The CryptGetHashParam function completes the hash. After CryptGetHashParam has been called, no more data can be added to the
			/// hash. Additional calls to CryptHashData or CryptHashSessionKey fail. After the application is done with the hash,
			/// CryptDestroyHash should be called to destroy the hash object.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(byte[]))]
			[CorrespondingType(typeof(IntPtr))]
			HP_HASHVAL = 0x0002,

			/// <summary>
			/// DWORD value indicating the number of bytes in the hash value. This value will vary depending on the hash algorithm.
			/// Applications must retrieve this value just before the HP_HASHVAL value so the correct amount of memory can be allocated.
			/// </summary>
			[CorrespondingType(typeof(uint), CorrespondingAction.Get)]
			HP_HASHSIZE = 0x0004,

			/// <summary>
			/// A pointer to an HMAC_INFO structure that specifies the cryptographic hash algorithm and the inner and outer strings to be used.
			/// </summary>
			[CorrespondingType(typeof(HMAC_INFO), CorrespondingAction.Set)]
			HP_HMAC_INFO = 0x0005,

			/// <summary>
			/// Component of the function argument GOSTR3411_PRF. It takes various values ​​in client and server messages when implementing
			/// the TLS Handshake Protocol.
			/// </summary>
			[CorrespondingType(typeof(CRYPTOAPI_BLOB), CorrespondingAction.Set)]
			HP_TLS1PRF_LABEL = 0x0006,

			/// <summary>
			/// Component of the function argument GOSTR3411_PRF. It takes various values ​​in client and server messages when implementing
			/// the TLS Handshake Protocol.
			/// </summary>
			[CorrespondingType(typeof(CRYPTOAPI_BLOB), CorrespondingAction.Set)]
			HP_TLS1PRF_SEED = 0x0007,
		}

		/// <summary>Specifies the type of query being made.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "07956d74-0e22-484b-9bf1-e0184a2ff32f")]
		public enum KeyParam
		{
			/// <summary>
			/// Retrieve the initialization vector of the key. The pbData parameter is a pointer to a BYTE array that receives the
			/// initialization vector. The size of this array is the block size, in bytes. For example, if the block length is 64 bits, the
			/// initialization vector consists of 8 bytes.
			/// </summary>
			KP_IV = 1,

			/// <summary>
			/// Retrieve the salt value of the key. The pbData parameter is a pointer to a BYTE array that receives the salt value in
			/// little-endian form. The size of the salt value varies depending on the CSP and algorithm being used. Salt values do not
			/// apply to public/private key pairs.
			/// </summary>
			KP_SALT = 2,

			/// <summary>
			/// <para>
			/// Retrieve the padding mode. The pbData parameter is a pointer to a DWORD value that receives a numeric identifier that
			/// identifies the padding method used by the cipher. This can be one of the following values.
			/// </para>
			/// <para>
			/// PKCS5_PADDING <br/> Specifies the PKCS 5 (sec 6.2) padding method. <br/> RANDOM_PADDING <br/> The padding uses random
			/// numbers. This padding method is not supported by the Microsoft supplied CSPs. <br/> ZERO_PADDING <br/> The padding uses
			/// zeros. This padding method is not supported by the Microsoft supplied CSPs.
			/// </para>
			/// </summary>
			KP_PADDING = 3,

			/// <summary>
			/// <para>
			/// Retrieve the cipher mode. The pbData parameter is a pointer to a DWORD value that receives a cipher mode identifier. For
			/// more information about cipher modes, see Data Encryption and Decryption.
			/// </para>
			/// <para>The following cipher mode identifiers are currently defined.</para>
			/// <para>
			/// CRYPT_MODE_CBC <br/> The cipher mode is cipher block chaining. <br/> CRYPT_MODE_CFB <br/> The cipher mode is cipher feedback
			/// (CFB). Microsoft CSPs currently support only 8-bit feedback in cipher feedback mode. <br/> CRYPT_MODE_ECB <br/> The cipher
			/// mode is electronic codebook. <br/> CRYPT_MODE_OFB <br/> The cipher mode is Output Feedback (OFB). Microsoft CSPs currently
			/// do not support Output Feedback Mode. <br/> CRYPT_MODE_CTS <br/> The cipher mode is ciphertext stealing mode.
			/// </para>
			/// </summary>
			KP_MODE = 4,

			/// <summary>
			/// Retrieve the number of bits to feed back. The pbData parameter is a pointer to a DWORD value that receives the number of
			/// bits that are processed per cycle when the OFB or CFB cipher modes are used.
			/// </summary>
			KP_MODE_BITS = 5,

			/// <summary>
			/// <para>
			/// Retrieve the key permissions. The pbData parameter is a pointer to a DWORD value that receives the permission flags for the key.
			/// </para>
			/// <para>
			/// The following permission identifiers are currently defined. The key permissions can be zero or a combination of one or more
			/// of the following values.
			/// </para>
			/// <para>
			/// CRYPT_ARCHIVE <br/> Allow export during the lifetime of the handle of the key. This permission can be set only if it is
			/// already set in the internal permissions field of the key. Attempts to clear this permission are ignored. <br/> CRYPT_DECRYPT
			/// <br/> Allow decryption. <br/> CRYPT_ENCRYPT <br/> Allow encryption. <br/> CRYPT_EXPORT <br/> Allow the key to be exported.
			/// <br/> CRYPT_EXPORT_KEY <br/> Allow the key to be used for exporting keys. <br/> CRYPT_IMPORT_KEY <br/> Allow the key to be
			/// used for importing keys. <br/> CRYPT_MAC <br/> Allow Message Authentication Codes (MACs) to be used with key. <br/>
			/// CRYPT_READ <br/> Allow values to be read. <br/> CRYPT_WRITE <br/> Allow values to be set.
			/// </para>
			/// </summary>
			KP_PERMISSIONS = 6,

			/// <summary>
			/// Retrieve the key algorithm. The pbData parameter is a pointer to an ALG_ID value that receives the identifier of the
			/// algorithm that was specified when the key was created.
			/// <para>
			/// When AT_KEYEXCHANGE or AT_SIGNATURE is specified for the Algid parameter of the CryptGenKey function, the algorithm
			/// identifiers that are used to generate the key depend on the provider used. For more information, see ALG_ID.
			/// </para>
			/// </summary>
			KP_ALGID = 7,

			/// <summary>
			/// If a session key is specified by the hKey parameter, retrieve the block length of the key cipher. The pbData parameter is a
			/// pointer to a DWORD value that receives the block length, in bits. For stream ciphers, this value is always zero.
			/// <para>
			/// If a public/private key pair is specified by hKey, retrieve the encryption granularity of the key pair.The pbData parameter
			/// is a pointer to a DWORD value that receives the encryption granularity, in bits.For example, the Microsoft Base
			/// Cryptographic Provider generates 512-bit RSA key pairs, so a value of 512 is returned for these keys. If the public key
			/// algorithm does not support encryption, the value retrieved is undefined.
			/// </para>
			/// </summary>
			KP_BLOCKLEN = 8,

			/// <summary>
			/// Retrieve the actual length of the key. The pbData parameter is a pointer to a DWORD value that receives the key length, in
			/// bits. KP_KEYLEN can be used to get the length of any key type. Microsoft cryptographic service providers (CSPs) return a key
			/// length of 64 bits for CALG_DES, 128 bits for CALG_3DES_112, and 192 bits for CALG_3DES. These lengths are different from the
			/// lengths returned when you are enumerating algorithms with the dwParam value of the CryptGetProvParam function set to
			/// PP_ENUMALGS. The length returned by this call is the actual size of the key, including the parity bits included in the key.
			/// <para>
			/// Microsoft CSPs that support the CALG_CYLINK_MEK ALG_ID return 64 bits for that algorithm. CALG_CYLINK_MEK is a 40-bit key
			/// but has parity and zeroed key bits to make the key length 64 bits.
			/// </para>
			/// </summary>
			KP_KEYLEN = 9,

			/// <summary></summary>
			KP_SALT_EX = 10,

			/// <summary>
			/// Retrieve the modulus prime number P of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
			/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
			/// </summary>
			KP_P = 11,

			/// <summary>
			/// Retrieve the generator G of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
			/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
			/// </summary>
			KP_G = 12,

			/// <summary>
			/// Retrieve the modulus prime number Q of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
			/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
			/// </summary>
			KP_Q = 13,

			/// <summary></summary>
			KP_X = 14,

			/// <summary></summary>
			KP_Y = 15,

			/// <summary></summary>
			KP_RA = 16,

			/// <summary></summary>
			KP_RB = 17,

			/// <summary></summary>
			KP_INFO = 18,

			/// <summary>
			/// Retrieve the effective key length of an RC2 key. The pbData parameter is a pointer to a DWORD value that receives the
			/// effective key length.
			/// </summary>
			KP_EFFECTIVE_KEYLEN = 19,

			/// <summary></summary>
			KP_SCHANNEL_ALG = 20,

			/// <summary></summary>
			KP_CLIENT_RANDOM = 21,

			/// <summary></summary>
			KP_SERVER_RANDOM = 22,

			/// <summary></summary>
			KP_RP = 23,

			/// <summary></summary>
			KP_PRECOMP_MD5 = 24,

			/// <summary></summary>
			KP_PRECOMP_SHA = 25,

			/// <summary>
			/// pbData is the address of a buffer that receives the X.509 certificate that has been encoded by using Distinguished Encoding
			/// Rules (DER). The public key in the certificate must match the corresponding signature or exchange key.
			/// </summary>
			KP_CERTIFICATE = 26,

			/// <summary></summary>
			KP_CLEAR_KEY = 27,

			/// <summary></summary>
			KP_PUB_EX_LEN = 28,

			/// <summary></summary>
			KP_PUB_EX_VAL = 29,

			/// <summary>
			/// This value is not used.
			/// <para>
			/// Windows Vista, Windows Server 2003 and Windows XP: Retrieve the secret agreement value from an imported Diffie-Hellman
			/// algorithm key of type CALG_AGREEDKEY_ANY. The pbData parameter is the address of a buffer that receives the secret agreement
			/// value, in little-endian format. This buffer must be the same length as the key. The dwFlags parameter must be set to
			/// 0xF42A19B6. This property can only be retrieved by a thread running under the local system account.This property is
			/// available for use in the operating systems listed above. It may be altered or unavailable in subsequent versions.
			/// </para>
			/// </summary>
			KP_KEYVAL = 30,

			/// <summary></summary>
			KP_ADMIN_PIN = 31,

			/// <summary></summary>
			KP_KEYEXCHANGE_PIN = 32,

			/// <summary></summary>
			KP_SIGNATURE_PIN = 33,

			/// <summary></summary>
			KP_PREHASH = 34,

			/// <summary></summary>
			KP_ROUNDS = 35,

			/// <summary></summary>
			KP_OAEP_PARAMS = 36,

			/// <summary></summary>
			KP_CMS_KEY_INFO = 37,

			/// <summary></summary>
			KP_CMS_DH_KEY_INFO = 38,

			/// <summary></summary>
			KP_PUB_PARAMS = 39,

			/// <summary>
			/// Verifies the parameters of a Diffie-Hellman algorithm or DSA key. The pbData parameter is not used, and the value pointed to
			/// by pdwDataLen receives zero.
			/// <para>This function returns a nonzero value if the key parameters are valid or zero otherwise.</para>
			/// </summary>
			KP_VERIFY_PARAMS = 40,

			/// <summary></summary>
			KP_HIGHEST_VERSION = 41,

			/// <summary>This value is not used.</summary>
			KP_GET_USE_COUNT = 42,

			/// <summary></summary>
			KP_PIN_ID = 43,

			/// <summary></summary>
			KP_PIN_INFO = 44,
		}

		/// <summary>The nature of the query.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "c0b7c1c8-aa42-4d40-a7f7-99c0821c8977")]
		public enum ProvParam
		{
			/// <summary>Returns the administrator personal identification number (PIN) in the pbData parameter as a LPSTR.</summary>
			PP_ADMIN_PIN = 0x1F,

			/// <summary>This constant is not used.</summary>
			PP_APPLI_CERT = 0x12,

			/// <summary>This constant is not used.</summary>
			PP_CHANGE_PASSWORD = 0x7,

			/// <summary>
			/// Returns the certificate chain associated with the hProv handle. The returned certificate chain is X509_ASN_ENCODING encoded.
			/// </summary>
			PP_CERTCHAIN = 0x9,

			/// <summary>
			/// The name of the current key container as a null-terminated CHAR string. This string is exactly the same as the one passed in
			/// the pszContainer parameter of the CryptAcquireContext function to specify the key container to use. The pszContainer
			/// parameter can be read to determine the name of the default key container.
			/// </summary>
			PP_CONTAINER = 0x6,

			/// <summary>
			/// Not implemented by Microsoft CSPs. This behavior may be implemented by other CSPs.
			/// <para>Windows XP: This parameter is not supported.</para>
			/// </summary>
			PP_CRYPT_COUNT_KEY_USE = 0x29,

			/// <summary>
			/// A PROV_ENUMALGS structure that contains information about one algorithm supported by the CSP being queried.
			/// <para>
			/// The first time this value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to
			/// retrieve the first element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag
			/// in the dwFlags parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has
			/// been reached.
			/// </para>
			/// <para>
			/// This function is not thread safe, and all of the available algorithms might not be enumerated if this function is used in a
			/// multithreaded context.
			/// </para>
			/// </summary>
			PP_ENUMALGS = 0x1,

			/// <summary>
			/// A PROV_ENUMALGS_EX structure that contains information about one algorithm supported by the CSP being queried. The structure
			/// returned contains more information about the algorithm than the structure returned for PP_ENUMALGS.
			/// <para>
			/// The first time this value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to
			/// retrieve the first element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag
			/// in the dwFlags parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has
			/// been reached.
			/// </para>
			/// <para>
			/// This function is not thread safe and all of the available algorithms might not be enumerated if this function is used in a
			/// multithreaded context.
			/// </para>
			/// </summary>
			PP_ENUMALGS_EX = 0x16,

			/// <summary>
			/// The name of one of the key containers maintained by the CSP in the form of a null-terminated CHAR string.
			/// <para>
			/// The first time this value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to
			/// retrieve the first element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag
			/// in the dwFlags parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has
			/// been reached.
			/// </para>
			/// <para>
			/// To enumerate key containers associated with a computer, first call CryptAcquireContext using the CRYPT_MACHINE_KEYSET flag,
			/// and then use the handle returned from CryptAcquireContext as the hProv parameter in the call to CryptGetProvParam.
			/// </para>
			/// <para>
			/// This function is not thread safe and all of the available algorithms might not be enumerated if this function is used in a
			/// multithreaded context.
			/// </para>
			/// </summary>
			PP_ENUMCONTAINERS = 0x2,

			/// <summary>This constant is not used.</summary>
			PP_ENUMELECTROOTS = 0x1A,

			/// <summary>
			/// Indicates that the current CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function succeeds,
			/// the CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function fails with an NTE_BAD_TYPE error
			/// code, the CSP does not support the dwProtocols member.
			/// </summary>
			PP_ENUMEX_SIGNING_PROT = 0x28,

			/// <summary>This constant is not used.</summary>
			PP_ENUMMANDROOTS = 0x19,

			/// <summary>A DWORD value that indicates how the CSP is implemented. For a table of possible values, see Remarks.</summary>
			PP_IMPTYPE = 0x3,

			/// <summary>This query is not used.</summary>
			PP_KEY_TYPE_SUBTYPE = 0xA,

			/// <summary>
			/// Specifies that the key exchange PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.
			/// </summary>
			PP_KEYEXCHANGE_PIN = 0x20,

			/// <summary>
			/// Retrieves the security descriptor for the key storage container. The pbData parameter is the address of a
			/// SECURITY_DESCRIPTOR structure that receives the security descriptor for the key storage container. The security descriptor
			/// is returned in self-relative format.
			/// </summary>
			PP_KEYSET_SEC_DESCR = 0x8,

			/// <summary>
			/// Determines whether the hProv parameter is a computer key set. The pbData parameter must be a DWORD; the DWORD will be set to
			/// the CRYPT_MACHINE_KEYSET flag if that flag was passed to the CryptAcquireContext function.
			/// </summary>
			PP_KEYSET_TYPE = 0x1B,

			/// <summary>
			/// Returns information about the key specifier values that the CSP supports. Key specifier values are joined in a logical OR
			/// and returned in the pbData parameter of the call as a DWORD. For example, the Microsoft Base Cryptographic Provider version
			/// 1.0 returns a DWORD value of AT_SIGNATURE | AT_KEYEXCHANGE.
			/// </summary>
			PP_KEYSPEC = 0x27,

			/// <summary>Returns a DWORD value of CRYPT_SEC_DESCR.</summary>
			PP_KEYSTORAGE = 0x11,

			/// <summary>
			/// The number of bits for the increment length of AT_KEYEXCHANGE. This information is used with information returned in the
			/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_KEYX_KEYSIZE_INC, the valid key lengths
			/// for AT_KEYEXCHANGE can be determined. These key lengths can then be used with CryptGenKey. For example if a CSP enumerates
			/// CALG_RSA_KEYX (AT_KEYEXCHANGE) with a minimum key length of 512 bits and a maximum of 1024 bits, and returns the increment
			/// length as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
			/// </summary>
			PP_KEYX_KEYSIZE_INC = 0x23,

			/// <summary>
			/// The name of the CSP in the form of a null-terminated CHAR string. This string is identical to the one passed in the
			/// pszProvider parameter of the CryptAcquireContext function to specify that the current CSP be used.
			/// </summary>
			PP_NAME = 0x4,

			/// <summary>A DWORD value that indicates the provider type of the CSP.</summary>
			PP_PROVTYPE = 0x10,

			/// <summary>
			/// Obtains the root certificate store for the smart card. This certificate store contains all of the root certificates that are
			/// stored on the smart card.
			/// <para>
			/// The pbData parameter is the address of an HCERTSTORE variable that receives the handle of the certificate store. When this
			/// handle is no longer needed, the caller must close it by using the CertCloseStore function.
			/// </para>
			/// <para>Windows Server 2003 and Windows XP: This parameter is not supported.</para>
			/// </summary>
			PP_ROOT_CERTSTORE = 0x2E,

			/// <summary>The size, in bits, of the session key.</summary>
			PP_SESSION_KEYSIZE = 0x14,

			/// <summary>Used with server gated cryptography.</summary>
			PP_SGC_INFO = 0x25,

			/// <summary>
			/// The number of bits for the increment length of AT_SIGNATURE. This information is used with information returned in the
			/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_SIG_KEYSIZE_INC, the valid key lengths
			/// for AT_SIGNATURE can be determined. These key lengths can then be used with CryptGenKey.
			/// <para>
			/// For example, if a CSP enumerates CALG_RSA_SIGN (AT_SIGNATURE) with a minimum key length of 512 bits and a maximum of 1024
			/// bits, and returns the increment length as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
			/// </para>
			/// </summary>
			PP_SIG_KEYSIZE_INC = 0x22,

			/// <summary>
			/// Specifies that the key signature PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.
			/// </summary>
			PP_SIGNATURE_PIN = 0x21,

			/// <summary>
			/// Obtains the identifier of the smart card. The pbData parameter is the address of a GUID structure that receives the
			/// identifier of the smart card.
			/// <para>Windows Server 2003 and Windows XP: This parameter is not supported.</para>
			/// </summary>
			PP_SMARTCARD_GUID = 0x2D,

			/// <summary>
			/// Obtains the name of the smart card reader. The pbData parameter is the address of an ANSI character array that receives a
			/// null-terminated ANSI string that contains the name of the smart card reader. The size of this buffer, contained in the
			/// variable pointed to by the pdwDataLen parameter, must include the NULL terminator.
			/// <para>Windows Server 2003 and Windows XP: This parameter is not supported.</para>
			/// </summary>
			PP_SMARTCARD_READER = 0x2B,

			/// <summary/>
			PP_SMARTCARD_READER_ICON = 47,

			/// <summary>The size of the symmetric key.</summary>
			PP_SYM_KEYSIZE = 0x13,

			/// <summary>This query is not used.</summary>
			PP_UI_PROMPT = 0x15,

			/// <summary>
			/// The unique container name of the current key container in the form of a null-terminated CHAR string. For many CSPs, this
			/// name is the same name returned when the PP_CONTAINER value is used. The CryptAcquireContext function must work with this
			/// container name.
			/// </summary>
			PP_UNIQUE_CONTAINER = 0x24,

			/// <summary>
			/// Indicates whether a hardware random number generator (RNG) is supported. When PP_USE_HARDWARE_RNG is specified, the function
			/// succeeds and returns TRUE if a hardware RNG is supported. The function fails and returns FALSE if a hardware RNG is not
			/// supported. If a RNG is supported, PP_USE_HARDWARE_RNG can be set in CryptSetProvParam to indicate that the CSP must
			/// exclusively use the hardware RNG for this provider context. When PP_USE_HARDWARE_RNG is used, the pbData parameter must be
			/// NULL and dwFlags must be zero.
			/// <para>None of the Microsoft CSPs currently support using a hardware RNG.</para>
			/// </summary>
			PP_USE_HARDWARE_RNG = 0x26,

			/// <summary>
			/// Obtains the user certificate store for the smart card. This certificate store contains all of the user certificates that are
			/// stored on the smart card. The certificates in this store are encoded by using PKCS_7_ASN_ENCODING or X509_ASN_ENCODING
			/// encoding and should contain the CERT_KEY_PROV_INFO_PROP_ID property.
			/// <para>
			/// The pbData parameter is the address of an HCERTSTORE variable that receives the handle of an in-memory certificate store.
			/// When this handle is no longer needed, the caller must close it by using the CertCloseStore function.
			/// </para>
			/// <para>Windows Server 2003 and Windows XP: This parameter is not supported.</para>
			/// </summary>
			PP_USER_CERTSTORE = 0x2A,

			/// <summary>
			/// The version number of the CSP. The least significant byte contains the minor version number and the next most significant
			/// byte the major version number. Version 2.0 is represented as 0x00000200. To maintain backward compatibility with earlier
			/// versions of the Microsoft Base Cryptographic Provider and the Microsoft Enhanced Cryptographic Provider, the provider names
			/// retain the "v1.0" designation in later versions.
			/// </summary>
			PP_VERSION = 0x5,
		}

		/// <summary>
		/// <para>
		/// The CryptAcquireContext function is used to acquire a handle to a particular key container within a particular cryptographic
		/// service provider (CSP). This returned handle is used in calls to CryptoAPI functions that use the selected CSP.
		/// </para>
		/// <para>
		/// This function first attempts to find a CSP with the characteristics described in the dwProvType and pszProvider parameters. If
		/// the CSP is found, the function attempts to find a key container within the CSP that matches the name specified by the
		/// pszContainer parameter. To acquire the context and the key container of a private key associated with the public key of a
		/// certificate, use CryptAcquireCertificatePrivateKey.
		/// </para>
		/// <para>
		/// With the appropriate setting of dwFlags, this function can also create and destroy key containers and can provide access to a
		/// CSP with a temporary key container if access to a private key is not required.
		/// </para>
		/// </summary>
		/// <param name="phProv">
		/// A pointer to a handle of a CSP. When you have finished using the CSP, release the handle by calling the CryptReleaseContext function.
		/// </param>
		/// <param name="szContainer">
		/// <para>
		/// The key container name. This is a null-terminated string that identifies the key container to the CSP. This name is independent
		/// of the method used to store the keys. Some CSPs store their key containers internally (in hardware), some use the system
		/// registry, and others use the file system. In most cases, when dwFlags is set to CRYPT_VERIFYCONTEXT, pszContainer must be set to
		/// <c>NULL</c>. However, for hardware-based CSPs, such as a smart card CSP, can be access publically available information in the
		/// specfied container.
		/// </para>
		/// <para>For more information about the usage of the pszContainer parameter, see Remarks.</para>
		/// </param>
		/// <param name="szProvider">
		/// <para>A null-terminated string that contains the name of the CSP to be used.</para>
		/// <para>
		/// If this parameter is <c>NULL</c>, the user default provider is used. For more information, see Cryptographic Service Provider
		/// Contexts. For a list of available cryptographic providers, see Cryptographic Provider Names.
		/// </para>
		/// <para>
		/// An application can obtain the name of the CSP in use by using the CryptGetProvParam function to read the PP_NAME CSP value in
		/// the dwParam parameter.
		/// </para>
		/// <para>
		/// The default CSP can change between operating system releases. To ensure interoperability on different operating system
		/// platforms, the CSP should be explicitly set by using this parameter instead of using the default CSP.
		/// </para>
		/// </param>
		/// <param name="dwProvType">
		/// Specifies the type of provider to acquire. Defined provider types are discussed in Cryptographic Provider Types.
		/// </param>
		/// <param name="dwFlags">
		/// <para>Flag values. This parameter is usually set to zero, but some applications set one or more of the following flags.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_VERIFYCONTEXT</term>
		/// <term>
		/// This option is intended for applications that are using ephemeral keys, or applications that do not require access to persisted
		/// private keys, such as applications that perform only hashing, encryption, and digital signature verification. Only applications
		/// that create signatures or decrypt messages need access to a private key. In most cases, this flag should be set. For file-based
		/// CSPs, when this flag is set, the pszContainer parameter must be set to NULL. The application has no access to the persisted
		/// private keys of public/private key pairs. When this flag is set, temporary public/private key pairs can be created, but they are
		/// not persisted. For hardware-based CSPs, such as a smart card CSP, if the pszContainer parameter is NULL or blank, this flag
		/// implies that no access to any keys is required, and that no UI should be presented to the user. This form is used to connect to
		/// the CSP to query its capabilities but not to actually use its keys. If the pszContainer parameter is not NULL and not blank,
		/// then this flag implies that access to only the publicly available information within the specified container is required. The
		/// CSP should not ask for a PIN. Attempts to access private information (for example, the CryptSignHash function) will fail. When
		/// CryptAcquireContext is called, many CSPs require input from the owning user before granting access to the private keys in the
		/// key container. For example, the private keys can be encrypted, requiring a password from the user before they can be used.
		/// However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NEWKEYSET</term>
		/// <term>
		/// Creates a new key container with the name specified by pszContainer. If pszContainer is NULL, a key container with the default
		/// name is created.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_MACHINE_KEYSET</term>
		/// <term>
		/// By default, keys and key containers are stored as user keys. For Base Providers, this means that user key containers are stored
		/// in the user's profile. A key container created without this flag by an administrator can be accessed only by the user creating
		/// the key container and a user with administration privileges. Windows XP: A key container created without this flag by an
		/// administrator can be accessed only by the user creating the key container and the local system account. A key container created
		/// without this flag by a user that is not an administrator can be accessed only by the user creating the key container and the
		/// local system account. The CRYPT_MACHINE_KEYSET flag can be combined with all of the other flags to indicate that the key
		/// container of interest is a computer key container and the CSP treats it as such. For Base Providers, this means that the keys
		/// are stored locally on the computer that created the key container. If a key container is to be a computer container, the
		/// CRYPT_MACHINE_KEYSET flag must be used with all calls to CryptAcquireContext that reference the computer container. The key
		/// container created with CRYPT_MACHINE_KEYSET by an administrator can be accessed only by its creator and by a user with
		/// administrator privileges unless access rights to the container are granted using CryptSetProvParam. Windows XP: The key
		/// container created with CRYPT_MACHINE_KEYSET by an administrator can be accessed only by its creator and by the local system
		/// account unless access rights to the container are granted using CryptSetProvParam. The key container created with
		/// CRYPT_MACHINE_KEYSET by a user that is not an administrator can be accessed only by its creator and by the local system account
		/// unless access rights to the container are granted using CryptSetProvParam. The CRYPT_MACHINE_KEYSET flag is useful when the user
		/// is accessing from a service or user account that did not log on interactively. When key containers are created, most CSPs do not
		/// automatically create any public/private key pairs. These keys must be created as a separate step with the CryptGenKey function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DELETEKEYSET</term>
		/// <term>
		/// Delete the key container specified by pszContainer. If pszContainer is NULL, the key container with the default name is deleted.
		/// All key pairs in the key container are also destroyed. When this flag is set, the value returned in phProv is undefined, and
		/// thus, the CryptReleaseContext function need not be called afterward.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SILENT</term>
		/// <term>
		/// The application requests that the CSP not display any user interface (UI) for this context. If the CSP must display the UI to
		/// operate, the call fails and the NTE_SILENT_CONTEXT error code is set as the last error. In addition, if calls are made to
		/// CryptGenKey with the CRYPT_USER_PROTECTED flag with a context that has been acquired with the CRYPT_SILENT flag, the calls fail
		/// and the CSP sets NTE_SILENT_CONTEXT. CRYPT_SILENT is intended for use with applications for which the UI cannot be displayed by
		/// the CSP.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DEFAULT_CONTAINER_OPTIONAL</term>
		/// <term>
		/// Obtains a context for a smart card CSP that can be used for hashing and symmetric key operations but cannot be used for any
		/// operation that requires authentication to a smart card using a PIN. This type of context is most often used to perform
		/// operations on an empty smart card, such as setting the PIN by using CryptSetProvParam. This flag can only be used with smart
		/// card CSPs. Windows Server 2003 and Windows XP: This flag is not supported.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes defined in Winerror.h follow.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code/value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY 107L</term>
		/// <term>Some CSPs set this error if the CRYPT_DELETEKEYSET flag value is set and another thread or process is using this key container.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_FILE_NOT_FOUND 2L</term>
		/// <term>
		/// The profile of the user is not loaded and cannot be found. This happens when the application impersonates a user, for example,
		/// the IUSR_ComputerName account.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER 87L</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY 8L</term>
		/// <term>The operating system ran out of memory during the operation.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS 0x80090009L</term>
		/// <term>The dwFlags parameter has a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY_STATE 0x8009000BL</term>
		/// <term>The user password has changed since the private keys were encrypted.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEYSET 0x80090016L</term>
		/// <term>
		/// The key container could not be opened. A common cause of this error is that the key container does not exist. To create a key
		/// container, call CryptAcquireContext using the CRYPT_NEWKEYSET flag. This error code can also indicate that access to an existing
		/// key container is denied. Access rights to the container can be granted by the key set creator by using CryptSetProvParam.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEYSET_PARAM 0x8009001FL</term>
		/// <term>The pszContainer or pszProvider parameter is set to a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_PROV_TYPE 0x80090014L</term>
		/// <term>The value of the dwProvType parameter is out of range. All provider types must be from 1 through 999, inclusive.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_SIGNATURE 0x80090006L</term>
		/// <term>The provider DLL signature could not be verified. Either the DLL or the digital signature has been tampered with.</term>
		/// </item>
		/// <item>
		/// <term>NTE_EXISTS 0x8009000FL</term>
		/// <term>The dwFlags parameter is CRYPT_NEWKEYSET, but the key container already exists.</term>
		/// </item>
		/// <item>
		/// <term>NTE_KEYSET_ENTRY_BAD 0x8009001AL</term>
		/// <term>The pszContainer key container was found but is corrupt.</term>
		/// </item>
		/// <item>
		/// <term>NTE_KEYSET_NOT_DEF 0x80090019L</term>
		/// <term>The requested provider does not exist.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY 0x8009000EL</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// <item>
		/// <term>NTE_PROV_DLL_NOT_FOUND 0x8009001EL</term>
		/// <term>The provider DLL file does not exist or is not on the current path.</term>
		/// </item>
		/// <item>
		/// <term>NTE_PROV_TYPE_ENTRY_BAD 0x80090018L</term>
		/// <term>
		/// The provider type specified by dwProvType is corrupt. This error can relate to either the user default CSP list or the computer
		/// default CSP list.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_PROV_TYPE_NO_MATCH 0x8009001BL</term>
		/// <term>
		/// The provider type specified by dwProvType does not match the provider type found. Note that this error can only occur when
		/// pszProvider specifies an actual CSP name.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_PROV_TYPE_NOT_DEF 0x80090017L</term>
		/// <term>No entry exists for the provider type specified by dwProvType.</term>
		/// </item>
		/// <item>
		/// <term>NTE_PROVIDER_DLL_FAIL 0x8009001DL</term>
		/// <term>The provider DLL file could not be loaded or failed to initialize.</term>
		/// </item>
		/// <item>
		/// <term>NTE_SIGNATURE_FILE_BAD 0x8009001CL</term>
		/// <term>An error occurred while loading the DLL file image, prior to verifying its signature.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The pszContainer parameter specifies the name of the container that is used to hold the key. Each container can contain one key.
		/// If you specify the name of an existing container when creating keys, the new key will overwrite a previous one.
		/// </para>
		/// <para>
		/// The combination of the CSP name and the key container name uniquely identifies a single key on the system. If one application
		/// tries to modify a key container while another application is using it, unpredictable behavior may result.
		/// </para>
		/// <para>
		/// If you set the pszContainer parameter to <c>NULL</c>, the default key container name is used. When the Microsoft software CSPs
		/// are called in this manner, a new container is created each time the <c>CryptAcquireContext</c> function is called. However,
		/// different CSPs may behave differently in this regard. In particular, a CSP may have a single default container that is shared by
		/// all applications accessing the CSP. Therefore, applications must not use the default key container to store private keys.
		/// Instead, either prevent key storage by passing the <c>CRYPT_VERIFYCONTEXT</c> flag in the dwFlags parameter, or use an
		/// application-specific container that is unlikely to be used by another application.
		/// </para>
		/// <para>
		/// An application can obtain the name of the key container in use by using the CryptGetProvParam function to read the PP_CONTAINER value.
		/// </para>
		/// <para>
		/// For performance reasons, we recommend that you set the pszContainer parameter to <c>NULL</c> and the dwFlags parameter to
		/// <c>CRYPT_VERIFYCONTEXT</c> in all situations where you do not require a persisted key. In particular, consider setting the
		/// pszContainer parameter to <c>NULL</c> and the dwFlags parameter to <c>CRYPT_VERIFYCONTEXT</c> for the following scenarios:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>You are creating a hash.</term>
		/// </item>
		/// <item>
		/// <term>You are generating a symmetric key to encrypt or decrypt data.</term>
		/// </item>
		/// <item>
		/// <term>You are deriving a symmetric key from a hash to encrypt or decrypt data.</term>
		/// </item>
		/// <item>
		/// <term>
		/// You are verifying a signature. It is possible to import a public key from a PUBLICKEYBLOB or from a certificate by using
		/// CryptImportKey or CryptImportPublicKeyInfo. A context can be acquired by using the <c>CRYPT_VERIFYCONTEXT</c> flag if you only
		/// plan to import the public key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// You plan to export a symmetric key, but not import it within the crypto context's lifetime. A context can be acquired by using
		/// the <c>CRYPT_VERIFYCONTEXT</c> flag if you only plan to import the public key for the last two scenarios.
		/// </term>
		/// </item>
		/// <item>
		/// <term>You are performing private key operations, but you are not using a persisted private key that is stored in a key container.</term>
		/// </item>
		/// </list>
		/// <para>
		/// If you plan to perform private key operations, the best way to acquire a context is to try to open the container. If this
		/// attempt fails with NTE_BAD_KEYSET, then create the container by using the <c>CRYPT_NEWKEYSET</c> flag.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows acquiring a cryptographic context and access to public/private key pairs in a key container. If the
		/// requested key container does not exist, it is created.
		/// </para>
		/// <para>
		/// For an example that includes the complete context for this example, see Example C Program: Creating a Key Container and
		/// Generating Keys. For additional examples, see Example C Program: Using CryptAcquireContext.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta BOOL CryptAcquireContextA(
		// HCRYPTPROV *phProv, LPCSTR szContainer, LPCSTR szProvider, DWORD dwProvType, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "57e13662-3189-4f8d-b90a-d1fbdc09b63c")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptAcquireContext(out SafeHCRYPTPROV phProv, [Optional, MarshalAs(UnmanagedType.LPTStr)] string szContainer, [Optional, MarshalAs(UnmanagedType.LPTStr)] string szProvider, uint dwProvType, CryptAcquireContextFlags dwFlags);

		/// <summary>
		/// The CryptContextAddRef function adds one to the reference count of an HCRYPTPROV cryptographic service provider (CSP) handle.
		/// This function should be used if the CSP handle is included as a member of any structure passed to another function. The
		/// CryptReleaseContext function should be called when the CSP handle is no longer needed.
		/// </summary>
		/// <param name="hProv">
		/// HCRYPTPROV handle for which the reference count is being incremented. This handle must have already been created using CryptAcquireContext.
		/// </param>
		/// <param name="pdwReserved">Reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>
		/// If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError. One possible error
		/// code is the following.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function increases the reference count on a HCRYPTPROV handle so that multiple calls to CryptReleaseContext are required to
		/// actually release the handle.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example increments the reference count on an acquired CSP handle.</para>
		/// <para>For another example that uses this function, see Example C Program: Using CryptAcquireContext.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptcontextaddref BOOL CryptContextAddRef( HCRYPTPROV
		// hProv, DWORD *pdwReserved, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "074666a7-369c-43bc-97d9-3bcc9703976b")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptContextAddRef(HCRYPTPROV hProv, IntPtr pdwReserved = default, uint dwFlags = 0);

		/// <summary>
		/// The CryptCreateHash function initiates the hashing of a stream of data. It creates and returns to the calling application a
		/// handle to a cryptographic service provider (CSP) hash object. This handle is used in subsequent calls to CryptHashData and
		/// CryptHashSessionKey to hash session keys and other streams of data.
		/// </summary>
		/// <param name="hProv">A handle to a CSP created by a call to CryptAcquireContext.</param>
		/// <param name="Algid">
		/// <para>An ALG_ID value that identifies the hash algorithm to use.</para>
		/// <para>Valid values for this parameter vary, depending on the CSP that is used. For a list of default algorithms, see Remarks.</para>
		/// </param>
		/// <param name="hKey">
		/// <para>
		/// If the type of hash algorithm is a keyed hash, such as the Hash-Based Message Authentication Code (HMAC) or Message
		/// Authentication Code (MAC) algorithm, the key for the hash is passed in this parameter. For nonkeyed algorithms, this parameter
		/// must be set to zero.
		/// </para>
		/// <para>
		/// For keyed algorithms, the key must be to a block cipher key, such as RC2, that has a cipher mode of Cipher Block Chaining (CBC).
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following flag value is defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_SECRETDIGEST 0x00000001</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="phHash">
		/// The address to which the function copies a handle to the new hash object. When you have finished using the hash object, release
		/// the handle by calling the CryptDestroyHash function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns <c>TRUE</c>.</para>
		/// <para>If the function fails, it returns <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by NTE are generated by the particular CSP you are using. The following table shows some of the
		/// possible error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory during the operation.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The Algid parameter specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>
		/// A keyed hash algorithm, such as CALG_MAC, is specified by Algid, and the hKey parameter is either zero or it specifies a key
		/// handle that is not valid. This error code is also returned if the key is to a stream cipher or if the cipher mode is anything
		/// other than CBC.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>For a list of Microsoft service providers and the algorithms they implement, see Microsoft Cryptographic Service Providers.</para>
		/// <para>
		/// The computation of the actual hash is done with the CryptHashData and CryptHashSessionKey functions. These require a handle to
		/// the hash object. After all the data has been added to the hash object, any of the following operations can be performed:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>The hash value can be retrieved by using CryptGetHashParam.</term>
		/// </item>
		/// <item>
		/// <term>A session key can be derived by using CryptDeriveKey.</term>
		/// </item>
		/// <item>
		/// <term>The hash can be signed by using CryptSignHash.</term>
		/// </item>
		/// <item>
		/// <term>A signature can be verified by using CryptVerifySignature.</term>
		/// </item>
		/// </list>
		/// <para>After one of the functions from this list has been called, CryptHashData and CryptHashSessionKey cannot be called.</para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows initiating the hashing of a stream of data. It creates and returns to the calling application a
		/// handle to a hash object. This handle is used in subsequent calls to CryptHashData and CryptHashSessionKey to hash any stream of
		/// data. For an example that includes the complete context for this example, see Example C Program: Creating and Hashing a Session
		/// Key. For another example that uses this function, see Example C Program: Signing a Hash and Verifying the Hash Signature.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptcreatehash BOOL CryptCreateHash( HCRYPTPROV hProv,
		// ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "05e3db57-8d83-48e2-8590-68039ea27253")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, [Optional] uint dwFlags, out SafeHCRYPTHASH phHash);

		/// <summary>
		/// <para>The CryptDecrypt function decrypts data previously encrypted by using the CryptEncrypt function.</para>
		/// <para>
		/// Important changes to support Secure/Multipurpose Internet Mail Extensions (S/MIME) email interoperability have been made to
		/// CryptoAPI that affect the handling of enveloped messages. For more information, see the Remarks section of CryptMsgOpenToEncode.
		/// </para>
		/// </summary>
		/// <param name="hKey">
		/// <para>
		/// A handle to the key to use for the decryption. An application obtains this handle by using either the CryptGenKey or
		/// CryptImportKey function.
		/// </para>
		/// <para>This key specifies the decryption algorithm to be used.</para>
		/// </param>
		/// <param name="hHash">
		/// <para>
		/// A handle to a hash object. If data is to be decrypted and hashed simultaneously, a handle to a hash object is passed in this
		/// parameter. The hash value is updated with the decrypted plaintext. This option is useful when simultaneously decrypting and
		/// verifying a signature.
		/// </para>
		/// <para>
		/// Before calling <c>CryptDecrypt</c>, the application must obtain a handle to the hash object by calling the CryptCreateHash
		/// function. After the decryption is complete, the hash value can be obtained by using the CryptGetHashParam function, it can also
		/// be signed by using the CryptSignHash function, or it can be used to verify a digital signature by using the CryptVerifySignature function.
		/// </para>
		/// <para>If no hash is to be done, this parameter must be zero.</para>
		/// </param>
		/// <param name="Final">
		/// A Boolean value that specifies whether this is the last section in a series being decrypted. This value is <c>TRUE</c> if this
		/// is the last or only block. If this is not the last block, this value is <c>FALSE</c>. For more information, see Remarks.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_OAEP 0x00000040</term>
		/// <term>
		/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the CRYPT_DECRYPT_RSA_NO_PADDING_CHECK flag.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECRYPT_RSA_NO_PADDING_CHECK 0x00000020</term>
		/// <term>
		/// Perform the decryption on the BLOB without checking the padding. This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the CRYPT_OAEP flag.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer that contains the data to be decrypted. After the decryption has been performed, the plaintext is placed
		/// back into this same buffer.
		/// </para>
		/// <para>The number of encrypted bytes in this buffer is specified by pdwDataLen.</para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that indicates the length of the pbData buffer. Before calling this function, the calling
		/// application sets the <c>DWORD</c> value to the number of bytes to be decrypted. Upon return, the <c>DWORD</c> value contains the
		/// number of bytes of the decrypted plaintext.
		/// </para>
		/// <para>
		/// When a block cipher is used, this data length must be a multiple of the block size unless this is the final section of data to
		/// be decrypted and the Final parameter is <c>TRUE</c>.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hKey session key specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// The data to be decrypted is not valid. For example, when a block cipher is used and the Final flag is FALSE, the value specified
		/// by pdwDataLen must be a multiple of the block size. This error can also be returned when the padding is found to be not valid.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hHash parameter contains a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hKey parameter does not contain a valid handle to a key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_LEN</term>
		/// <term>The size of the output buffer is too small to hold the generated plaintext.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_DOUBLE_ENCRYPT</term>
		/// <term>The application attempted to decrypt the same data twice.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If a large amount of data is to be decrypted, it can be done in sections by calling <c>CryptDecrypt</c> repeatedly. The Final
		/// parameter must be set to <c>TRUE</c> only on the last call to <c>CryptDecrypt</c>, so that the decryption engine can properly
		/// finish the decryption process. The following extra actions are performed when Final is <c>TRUE</c>:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key is a block cipher key, the data is padded to a multiple of the block size of the cipher. To find the block size of a
		/// cipher, use CryptGetKeyParam to get the KP_BLOCKLEN value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the cipher is operating in a chaining mode, the next <c>CryptDecrypt</c> operation resets the cipher's feedback register to
		/// the KP_IV value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the cipher is a stream cipher, the next <c>CryptDecrypt</c> call resets the cipher to its initial state.</term>
		/// </item>
		/// </list>
		/// <para>
		/// There is no way to set the cipher's feedback register to the KP_IV value of the key without setting the Final parameter to
		/// <c>TRUE</c>. If this is necessary, as in the case where you do not want to add an additional padding block or change the size of
		/// each block, you can simulate this by creating a duplicate of the original key by using the CryptDuplicateKey function, and
		/// passing the duplicate key to the <c>CryptDecrypt</c> function. This causes the KP_IV of the original key to be placed in the
		/// duplicate key. After you create or import the original key, you cannot use the original key for encryption because the feedback
		/// register of the key will be changed. The following pseudocode shows how this can be done.
		/// </para>
		/// <para>
		/// The Microsoft Enhanced Cryptographic Provider supports direct encryption with RSA public keys and decryption with RSA private
		/// keys. The encryption uses PKCS #1 padding. On decryption, this padding is verified. The length of ciphertext data to be
		/// decrypted must be the same length as the modulus of the RSA key used to decrypt the data. If the ciphertext has zeros in the
		/// most significant bytes, these bytes must be included in the input data buffer and in the input buffer length. The ciphertext
		/// must be in little-endian format.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Decrypting a File.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecrypt BOOL CryptDecrypt( HCRYPTKEY hKey,
		// HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "7c3d2838-6fd1-4f6c-9586-8b94b459a31a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, CryptDecryptFlags dwFlags, [In, Out] IntPtr pbData, ref uint pdwDataLen);

		/// <summary>
		/// <para>The CryptDecrypt function decrypts data previously encrypted by using the CryptEncrypt function.</para>
		/// <para>
		/// Important changes to support Secure/Multipurpose Internet Mail Extensions (S/MIME) email interoperability have been made to
		/// CryptoAPI that affect the handling of enveloped messages. For more information, see the Remarks section of CryptMsgOpenToEncode.
		/// </para>
		/// </summary>
		/// <param name="hKey">
		/// <para>
		/// A handle to the key to use for the decryption. An application obtains this handle by using either the CryptGenKey or
		/// CryptImportKey function.
		/// </para>
		/// <para>This key specifies the decryption algorithm to be used.</para>
		/// </param>
		/// <param name="hHash">
		/// <para>
		/// A handle to a hash object. If data is to be decrypted and hashed simultaneously, a handle to a hash object is passed in this
		/// parameter. The hash value is updated with the decrypted plaintext. This option is useful when simultaneously decrypting and
		/// verifying a signature.
		/// </para>
		/// <para>
		/// Before calling <c>CryptDecrypt</c>, the application must obtain a handle to the hash object by calling the CryptCreateHash
		/// function. After the decryption is complete, the hash value can be obtained by using the CryptGetHashParam function, it can also
		/// be signed by using the CryptSignHash function, or it can be used to verify a digital signature by using the CryptVerifySignature function.
		/// </para>
		/// <para>If no hash is to be done, this parameter must be zero.</para>
		/// </param>
		/// <param name="Final">
		/// A Boolean value that specifies whether this is the last section in a series being decrypted. This value is <c>TRUE</c> if this
		/// is the last or only block. If this is not the last block, this value is <c>FALSE</c>. For more information, see Remarks.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_OAEP 0x00000040</term>
		/// <term>
		/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the CRYPT_DECRYPT_RSA_NO_PADDING_CHECK flag.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DECRYPT_RSA_NO_PADDING_CHECK 0x00000020</term>
		/// <term>
		/// Perform the decryption on the BLOB without checking the padding. This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption. This flag cannot be combined with the CRYPT_OAEP flag.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer that contains the data to be decrypted. After the decryption has been performed, the plaintext is placed
		/// back into this same buffer.
		/// </para>
		/// <para>The number of encrypted bytes in this buffer is specified by pdwDataLen.</para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that indicates the length of the pbData buffer. Before calling this function, the calling
		/// application sets the <c>DWORD</c> value to the number of bytes to be decrypted. Upon return, the <c>DWORD</c> value contains the
		/// number of bytes of the decrypted plaintext.
		/// </para>
		/// <para>
		/// When a block cipher is used, this data length must be a multiple of the block size unless this is the final section of data to
		/// be decrypted and the Final parameter is <c>TRUE</c>.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hKey session key specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// The data to be decrypted is not valid. For example, when a block cipher is used and the Final flag is FALSE, the value specified
		/// by pdwDataLen must be a multiple of the block size. This error can also be returned when the padding is found to be not valid.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hHash parameter contains a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hKey parameter does not contain a valid handle to a key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_LEN</term>
		/// <term>The size of the output buffer is too small to hold the generated plaintext.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_DOUBLE_ENCRYPT</term>
		/// <term>The application attempted to decrypt the same data twice.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If a large amount of data is to be decrypted, it can be done in sections by calling <c>CryptDecrypt</c> repeatedly. The Final
		/// parameter must be set to <c>TRUE</c> only on the last call to <c>CryptDecrypt</c>, so that the decryption engine can properly
		/// finish the decryption process. The following extra actions are performed when Final is <c>TRUE</c>:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key is a block cipher key, the data is padded to a multiple of the block size of the cipher. To find the block size of a
		/// cipher, use CryptGetKeyParam to get the KP_BLOCKLEN value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the cipher is operating in a chaining mode, the next <c>CryptDecrypt</c> operation resets the cipher's feedback register to
		/// the KP_IV value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the cipher is a stream cipher, the next <c>CryptDecrypt</c> call resets the cipher to its initial state.</term>
		/// </item>
		/// </list>
		/// <para>
		/// There is no way to set the cipher's feedback register to the KP_IV value of the key without setting the Final parameter to
		/// <c>TRUE</c>. If this is necessary, as in the case where you do not want to add an additional padding block or change the size of
		/// each block, you can simulate this by creating a duplicate of the original key by using the CryptDuplicateKey function, and
		/// passing the duplicate key to the <c>CryptDecrypt</c> function. This causes the KP_IV of the original key to be placed in the
		/// duplicate key. After you create or import the original key, you cannot use the original key for encryption because the feedback
		/// register of the key will be changed. The following pseudocode shows how this can be done.
		/// </para>
		/// <para>
		/// The Microsoft Enhanced Cryptographic Provider supports direct encryption with RSA public keys and decryption with RSA private
		/// keys. The encryption uses PKCS #1 padding. On decryption, this padding is verified. The length of ciphertext data to be
		/// decrypted must be the same length as the modulus of the RSA key used to decrypt the data. If the ciphertext has zeros in the
		/// most significant bytes, these bytes must be included in the input data buffer and in the input buffer length. The ciphertext
		/// must be in little-endian format.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Decrypting a File.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecrypt BOOL CryptDecrypt( HCRYPTKEY hKey,
		// HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "7c3d2838-6fd1-4f6c-9586-8b94b459a31a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, CryptDecryptFlags dwFlags, [In, Out] byte[] pbData, ref int pdwDataLen);

		/// <summary>
		/// <para>
		/// The CryptDeriveKey function generates cryptographic session keys derived from a base data value. This function guarantees that
		/// when the same cryptographic service provider (CSP) and algorithms are used, the keys generated from the same base data are
		/// identical. The base data can be a password or any other user data.
		/// </para>
		/// <para>
		/// This function is the same as CryptGenKey, except that the generated session keys are derived from base data instead of being
		/// random. <c>CryptDeriveKey</c> can only be used to generate session keys. It cannot generate public/private key pairs.
		/// </para>
		/// <para>
		/// A handle to the session key is returned in the phKey parameter. This handle can be used with any CryptoAPI function that
		/// requires a key handle.
		/// </para>
		/// </summary>
		/// <param name="hProv">A HCRYPTPROV handle of a CSP created by a call to CryptAcquireContext.</param>
		/// <param name="Algid">
		/// <para>
		/// An ALG_ID structure that identifies the symmetric encryption algorithm for which the key is to be generated. The algorithms
		/// available will most likely be different for each CSP. For more information about which algorithm identifier is used by the
		/// different providers for the key specs AT_KEYEXCHANGE and AT_SIGNATURE, see <c>ALG_ID</c>.
		/// </para>
		/// <para>
		/// For more information about ALG_ID values to use with the Microsoft Base Cryptographic Provider, see Base Provider Algorithms.
		/// For more information about <c>ALG_ID</c> values to use with the Microsoft Strong Cryptographic Provider or the Microsoft
		/// Enhanced Cryptographic Provider, see Enhanced Provider Algorithms.
		/// </para>
		/// </param>
		/// <param name="hBaseData">
		/// <para>A handle to a hash object that has been fed the exact base data.</para>
		/// <para>
		/// To obtain this handle, an application must first create a hash object with CryptCreateHash and then add the base data to the
		/// hash object with CryptHashData. This process is described in detail in Hashes and Digital Signatures.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>Specifies the type of key generated.</para>
		/// <para>
		/// The sizes of a session key can be set when the key is generated. The key size, representing the length of the key modulus in
		/// bits, is set with the upper 16 bits of this parameter. Thus, if a 128-bit RC4 session key is to be generated, the value
		/// 0x00800000 is combined with any other dwFlags predefined value with a bitwise- <c>OR</c> operation. Due to changing export
		/// control restrictions, the default CSP and default key length may change between operating system releases. It is important that
		/// both the encryption and decryption use the same CSP and that the key length be explicitly set using the dwFlags parameter to
		/// ensure interoperability on different operating system platforms.
		/// </para>
		/// <para>
		/// The lower 16 bits of this parameter can be zero or you can specify one or more of the following flags by using the bitwise-
		/// <c>OR</c> operator to combine them.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_CREATE_SALT</term>
		/// <term>
		/// Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value is
		/// 128 bits and the session key is 40 bits, there will be 88 bits left over. If this flag is set, then the key is assigned a salt
		/// value based on the unused hash value bits. You can retrieve this salt value by using the CryptGetKeyParam function with the
		/// dwParam parameter set to KP_SALT. If this flag is not set, then the key is given a salt value of zero. When keys with nonzero
		/// salt values are exported (by using CryptExportKey), the salt value must also be obtained and kept with the key BLOB.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_EXPORTABLE</term>
		/// <term>
		/// If this flag is set, the session key can be transferred out of the CSP into a key BLOB through the CryptExportKey function.
		/// Because keys generally must be exportable, this flag should usually be set. If this flag is not set, then the session key is not
		/// exportable. This means the key is available only within the current session and only the application that created it is able to
		/// use it. This flag does not apply to public/private key pairs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NO_SALT</term>
		/// <term>
		/// This flag specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Salt Value Functionality.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_UPDATE_KEY</term>
		/// <term>
		/// Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called
		/// multiple times. If this flag is set, a new session key is not generated. Instead, the key specified by phKey is modified. The
		/// precise behavior of this flag is dependent on the type of key being generated and on the particular CSP being used. Microsoft
		/// cryptographic service providers ignore this flag.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SERVER 1024 (0x400)</term>
		/// <term>
		/// This flag is used only with Schannel providers. If this flag is set, the key to be generated is a server-write key; otherwise,
		/// it is a client-write key.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="phKey">
		/// A pointer to a HCRYPTKEY variable to receive the address of the handle of the newly generated key. When you have finished using
		/// the key, release the handle by calling the CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes are listed in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The Algid parameter specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hBaseData parameter does not contain a valid handle to a hash object.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH_STATE</term>
		/// <term>An attempt was made to add data to a hash object that is already marked "finished."</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_SILENT_CONTEXT</term>
		/// <term>The provider could not perform the action because the context was acquired as silent.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When keys are generated for symmetric block ciphers, the key by default is set up in cipher block chaining (CBC) mode with an
		/// initialization vector of zero. This cipher mode provides a good default method for bulk-encrypting data. To change these
		/// parameters, use the CryptSetKeyParam function.
		/// </para>
		/// <para>
		/// The <c>CryptDeriveKey</c> function completes the hash. After <c>CryptDeriveKey</c> has been called, no more data can be added to
		/// the hash. Additional calls to CryptHashData or CryptHashSessionKey fail. After the application is done with the hash,
		/// CryptDestroyHash must be called to destroy the hash object.
		/// </para>
		/// <para>To choose an appropriate key length, the following methods are recommended.</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// To enumerate the algorithms that the CSP supports and to get maximum and minimum key lengths for each algorithm, call
		/// CryptGetProvParam with PP_ENUMALGS_EX.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Use the minimum and maximum lengths to choose an appropriate key length. It is not always advisable to choose the maximum length
		/// because this can lead to performance issues.
		/// </term>
		/// </item>
		/// <item>
		/// <term>After the desired key length has been chosen, use the upper 16 bits of the dwFlags parameter to specify the key length.</term>
		/// </item>
		/// </list>
		/// <para>
		/// Let <c>n</c> be the required derived key length, in bytes. The derived key is the first <c>n</c> bytes of the hash value after
		/// the hash computation has been completed by <c>CryptDeriveKey</c>. If the hash is not a member of the SHA-2 family and the
		/// required key is for either 3DES or AES, the key is derived as follows:
		/// </para>
		/// <list type="number">
		/// <item>
		/// <term>
		/// Form a 64-byte buffer by repeating the constant <c>0x36</c> 64 times. Let <c>k</c> be the length of the hash value that is
		/// represented by the input parameter hBaseData. Set the first <c>k</c> bytes of the buffer to the result of an <c>XOR</c>
		/// operation of the first <c>k</c> bytes of the buffer with the hash value that is represented by the input parameter hBaseData.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Form a 64-byte buffer by repeating the constant <c>0x5C</c> 64 times. Set the first <c>k</c> bytes of the buffer to the result
		/// of an <c>XOR</c> operation of the first <c>k</c> bytes of the buffer with the hash value that is represented by the input
		/// parameter hBaseData.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Hash the result of step 1 by using the same hash algorithm as that used to compute the hash value that is represented by the
		/// hBaseData parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Hash the result of step 2 by using the same hash algorithm as that used to compute the hash value that is represented by the
		/// hBaseData parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>Concatenate the result of step 3 with the result of step 4.</term>
		/// </item>
		/// <item>
		/// <term>Use the first <c>n</c> bytes of the result of step 5 as the derived key.</term>
		/// </item>
		/// </list>
		/// <para>
		/// The default RSA Full Cryptographic Service Provider is the Microsoft RSA Strong Cryptographic Provider. The default DSS
		/// Signature Diffie-Hellman Cryptographic Service Provider is the Microsoft Enhanced DSS Diffie-Hellman Cryptographic Provider.
		/// Each of these CSPs has a default 128-bit symmetric key length for RC2 and RC4.
		/// </para>
		/// <para>The following table lists minimum, default, and maximum key lengths for session key by algorithm and provider.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Provider</term>
		/// <term>Algorithms</term>
		/// <term>Minimum key length</term>
		/// <term>Default key length</term>
		/// <term>Maximum key length</term>
		/// </listheader>
		/// <item>
		/// <term>MS Base</term>
		/// <term>RC4 and RC2</term>
		/// <term>40</term>
		/// <term>40</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>MS Base</term>
		/// <term>DES</term>
		/// <term>56</term>
		/// <term>56</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>MS Enhanced</term>
		/// <term>RC4 and RC2</term>
		/// <term>40</term>
		/// <term>128</term>
		/// <term>128</term>
		/// </item>
		/// <item>
		/// <term>MS Enhanced</term>
		/// <term>DES</term>
		/// <term>56</term>
		/// <term>56</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>MS Enhanced</term>
		/// <term>3DES 112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// </item>
		/// <item>
		/// <term>MS Enhanced</term>
		/// <term>3DES</term>
		/// <term>168</term>
		/// <term>168</term>
		/// <term>168</term>
		/// </item>
		/// <item>
		/// <term>MS Strong</term>
		/// <term>RC4 and RC2</term>
		/// <term>40</term>
		/// <term>128</term>
		/// <term>128</term>
		/// </item>
		/// <item>
		/// <term>MS Strong</term>
		/// <term>DES</term>
		/// <term>56</term>
		/// <term>56</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>MS Strong</term>
		/// <term>3DES 112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// </item>
		/// <item>
		/// <term>MS Strong</term>
		/// <term>3DES</term>
		/// <term>168</term>
		/// <term>168</term>
		/// <term>168</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Base</term>
		/// <term>RC4 and RC2</term>
		/// <term>40</term>
		/// <term>40</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Base</term>
		/// <term>Cylink MEK</term>
		/// <term>40</term>
		/// <term>40</term>
		/// <term>40</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Base</term>
		/// <term>DES</term>
		/// <term>56</term>
		/// <term>56</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enh</term>
		/// <term>RC4 and RC2</term>
		/// <term>40</term>
		/// <term>128</term>
		/// <term>128</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enh</term>
		/// <term>Cylink MEK</term>
		/// <term>40</term>
		/// <term>40</term>
		/// <term>40</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enh</term>
		/// <term>DES</term>
		/// <term>56</term>
		/// <term>56</term>
		/// <term>56</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enh</term>
		/// <term>3DES 112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// <term>112</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enh</term>
		/// <term>3DES</term>
		/// <term>168</term>
		/// <term>168</term>
		/// <term>168</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Deriving a Session Key from a Password.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptderivekey BOOL CryptDeriveKey( HCRYPTPROV hProv,
		// ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "b031e3b4-0102-400e-96db-019d31402adc")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, CryptGenKeyFlags dwFlags, out SafeHCRYPTKEY phKey);

		/// <summary>
		/// The CryptDestroyHash function destroys the hash object referenced by the hHash parameter. After a hash object has been
		/// destroyed, it can no longer be used.
		/// <para>To help ensure security, we recommend that hash objects be destroyed after they have been used.</para>
		/// </summary>
		/// <param name="hHash">The handle of the hash object to be destroyed.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular cryptographic service provider (CSP) you are using. Some
		/// possible error codes follow.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The hash object specified by hHash is currently being used and cannot be destroyed.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>The hHash parameter specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>The hHash parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hHash handle specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hash object was created cannot be found.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When a hash object is destroyed, many CSPs overwrite the memory in the CSP where the hash object was held. The CSP memory is
		/// then freed.
		/// </para>
		/// <para>There should be a one-to-one correspondence between calls to CryptCreateHash and <c>CryptDestroyHash</c>.</para>
		/// <para>
		/// All hash objects that have been created by using a specific CSP must be destroyed before that CSP handle is released with the
		/// CryptReleaseContext function.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses the <c>CryptDestroyHash</c> function, see Example C Program: Creating and Hashing a Session Key.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdestroyhash BOOL CryptDestroyHash( HCRYPTHASH hHash );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "0a4d6086-5c4c-4e1e-9ab9-b35ee49ffcae")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDestroyHash(HCRYPTHASH hHash);

		/// <summary>
		/// The CryptDestroyKey function releases the handle referenced by the hKey parameter. After a key handle has been released, it is
		/// no longer valid and cannot be used again.
		/// <para>
		/// If the handle refers to a session key, or to a public key that has been imported into the cryptographic service provider (CSP)
		/// through CryptImportKey, this function destroys the key and frees the memory that the key used. Many CSPs overwrite the memory
		/// where the key was held before freeing it. However, the underlying public/private key pair is not destroyed by this function.
		/// Only the handle is destroyed.
		/// </para>
		/// </summary>
		/// <param name="hKey">The handle of the key to be destroyed.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes are listed in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The key object specified by hKey is currently being used and cannot be destroyed.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>The hKey parameter specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>The hKey parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hKey parameter does not contain a valid handle to a key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Keys take up both operating system's memory space and the CSP's memory space. Some CSPs are implemented in hardware with limited
		/// memory resources. Applications must destroy all keys with the <c>CryptDestroyKey</c> function when they are finished with them.
		/// </para>
		/// <para>
		/// All key handles that have been created or imported by using a specific CSP must be destroyed before that CSP handle is released
		/// with the CryptReleaseContext function.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses the <c>CryptDestroyKey</c> function, see Example C Program: Creating and Hashing a Session Key.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdestroykey BOOL CryptDestroyKey( HCRYPTKEY hKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "ed5d8047-c9fd-4765-915f-a6a014004b30")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDestroyKey(HCRYPTKEY hKey);

		/// <summary>
		/// <para>
		/// The <c>CryptDuplicateHash</c> function makes an exact copy of a hash to the point when the duplication is done. The duplicate
		/// hash includes the state of the hash.
		/// </para>
		/// <para>
		/// A hash can be created in a piece-by-piece way. The <c>CryptDuplicateHash</c> function can be used to create separate hashes of
		/// two different contents that begin with the same content.
		/// </para>
		/// </summary>
		/// <param name="hHash">Handle of the hash to be duplicated.</param>
		/// <param name="pdwReserved">Reserved for future use and must be zero.</param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <param name="phHash">
		/// Address of the handle of the duplicated hash. When you have finished using the hash, release the handle by calling the
		/// CryptDestroyHash function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns <c>TRUE</c>.</para>
		/// <para>If the function fails, it returns <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>
		/// The error code prefaced by "NTE" is generated by the particular cryptographic service provider (CSP) that you are using. Some
		/// possible error codes follow.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_CALL_NOT_IMPLEMENTED</term>
		/// <term>
		/// Because this is a new function, existing CSPs cannot implement it. This error is returned if the CSP does not support this function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>A handle to the original hash is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>CryptDuplicateHash</c> makes a copy of a hash and the exact state of the hash. This function might be used if a calling
		/// application needed to generate two hashes but both hashes had to start with some common data hashed. For example, a hash might
		/// be created, the common data hashed, a duplicate made with the <c>CryptDuplicateHash</c> function, and then the data unique to
		/// each hash would be added.
		/// </para>
		/// <para>
		/// The CryptDestroyHash function must be called to destroy any hashes that are created with <c>CryptDuplicateHash</c>. Destroying
		/// the original hash does not cause the duplicate hash to be destroyed. After a duplicate hash is made, it is separate from the
		/// original hash. There is no shared state between the two hashes.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows making an exact copy of a hash. For an example that includes the complete context for this example,
		/// see Example C Program: Duplicating a Hash.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptduplicatehash BOOL CryptDuplicateHash( HCRYPTHASH
		// hHash, DWORD *pdwReserved, DWORD dwFlags, HCRYPTHASH *phHash );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "527fce4d-8d42-437b-9692-42583092efbb")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDuplicateHash(HCRYPTHASH hHash, [Optional] IntPtr pdwReserved, [Optional] uint dwFlags, out SafeHCRYPTHASH phHash);

		/// <summary>The CryptDuplicateKey function makes an exact copy of a key and the state of the key.</summary>
		/// <param name="hKey">A handle to the key to be duplicated.</param>
		/// <param name="pdwReserved">Reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <param name="phKey">
		/// Address of the handle to the duplicated key. When you have finished using the key, release the handle by calling the
		/// CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError.</para>
		/// <para>
		/// The error code prefaced by "NTE" is generated by the particular CSP being used. Some possible error codes are listed in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_CALL_NOT_IMPLEMENTED</term>
		/// <term>
		/// Because this is a new function, existing CSPs might not implement it. This error is returned if the CSP does not support this function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>A handle to the original key is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>CryptDuplicateKey</c> makes a copy of a key and the exact state of the key. One scenario when this function can be used is
		/// when an application needs to encrypt two separate messages with the same key but with different salt values. The original key is
		/// generated and then a duplicate key is made by using the <c>CryptDuplicateKey</c> function. The different salt values are then
		/// set on the original and duplicate keys with separate calls to the CryptSetKeyParam function.
		/// </para>
		/// <para>
		/// CryptDestroyKey must be called to destroy any keys that are created by using <c>CryptDuplicateKey</c>. Destroying the original
		/// key does not cause the duplicate key to be destroyed. After a duplicate key is made, it is separate from the original key. There
		/// is no shared state between the two keys.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows the creation of a session key that is a duplicate of an existing session key. For an example that
		/// includes the complete context for this example, see Example C Program: Duplicating a Session Key.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptduplicatekey BOOL CryptDuplicateKey( HCRYPTKEY hKey,
		// DWORD *pdwReserved, DWORD dwFlags, HCRYPTKEY *phKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "c5658008-7c92-4877-871a-a764884efd79")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDuplicateKey(HCRYPTKEY hKey, [Optional] IntPtr pdwReserved, [Optional] uint dwFlags, out SafeHCRYPTKEY phKey);

		/// <summary>
		/// <para>
		/// The CryptEncrypt function encrypts data. The algorithm used to encrypt the data is designated by the key held by the CSP module
		/// and is referenced by the hKey parameter.
		/// </para>
		/// <para>
		/// Important changes to support Secure/Multipurpose Internet Mail Extensions (S/MIME) email interoperability have been made to
		/// CryptoAPI that affect the handling of enveloped messages. For more information, see the Remarks section of CryptMsgOpenToEncode.
		/// </para>
		/// <para>
		/// <c>Important</c> The <c>CryptEncrypt</c> function is not guaranteed to be thread safe and may return incorrect results if
		/// invoked simultaneously by multiple callers.
		/// </para>
		/// </summary>
		/// <param name="hKey">
		/// <para>
		/// A handle to the encryption key. An application obtains this handle by using either the CryptGenKey or the CryptImportKey function.
		/// </para>
		/// <para>The key specifies the encryption algorithm used.</para>
		/// </param>
		/// <param name="hHash">
		/// <para>
		/// A handle to a hash object. If data is to be hashed and encrypted simultaneously, a handle to a hash object can be passed in the
		/// hHash parameter. The hash value is updated with the plaintext passed in. This option is useful when generating signed and
		/// encrypted text.
		/// </para>
		/// <para>
		/// Before calling <c>CryptEncrypt</c>, the application must obtain a handle to the hash object by calling the CryptCreateHash
		/// function. After the encryption is complete, the hash value can be obtained by using the CryptGetHashParam function, or the hash
		/// can be signed by using the CryptSignHash function.
		/// </para>
		/// <para>If no hash is to be done, this parameter must be <c>NULL</c>.</para>
		/// </param>
		/// <param name="Final">
		/// A Boolean value that specifies whether this is the last section in a series being encrypted. Final is set to <c>TRUE</c> for the
		/// last or only block and to <c>FALSE</c> if there are more blocks to be encrypted. For more information, see Remarks.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following dwFlags value is defined but reserved for future use.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_OAEP</term>
		/// <term>
		/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer that contains the plaintext to be encrypted. The plaintext in this buffer is overwritten with the
		/// ciphertext created by this function.
		/// </para>
		/// <para>
		/// The pdwDataLen parameter points to a variable that contains the length, in bytes, of the plaintext. The dwBufLen parameter
		/// contains the total size, in bytes, of this buffer.
		/// </para>
		/// <para>
		/// If this parameter contains <c>NULL</c>, this function will calculate the required size for the ciphertext and place that in the
		/// value pointed to by the pdwDataLen parameter.
		/// </para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that , on entry, contains the length, in bytes, of the plaintext in the pbData buffer. On
		/// exit, this <c>DWORD</c> contains the length, in bytes, of the ciphertext written to the pbData buffer.
		/// </para>
		/// <para>
		/// If the buffer allocated for pbData is not large enough to hold the encrypted data, GetLastError returns <c>ERROR_MORE_DATA</c>
		/// and stores the required buffer size, in bytes, in the <c>DWORD</c> value pointed to by pdwDataLen.
		/// </para>
		/// <para>
		/// If pbData is <c>NULL</c>, no error is returned, and the function stores the size of the encrypted data, in bytes, in the
		/// <c>DWORD</c> value pointed to by pdwDataLen. This allows an application to determine the correct buffer size.
		/// </para>
		/// <para>
		/// When a block cipher is used, this data length must be a multiple of the block size unless this is the final section of data to
		/// be encrypted and the Final parameter is <c>TRUE</c>.
		/// </para>
		/// </param>
		/// <param name="dwBufLen">
		/// <para>Specifies the total size, in bytes, of the input pbData buffer.</para>
		/// <para>
		/// Note that, depending on the algorithm used, the encrypted text can be larger than the original plaintext. In this case, the
		/// pbData buffer needs to be large enough to contain the encrypted text and any padding.
		/// </para>
		/// <para>
		/// As a rule, if a stream cipher is used, the ciphertext is the same size as the plaintext. If a block cipher is used, the
		/// ciphertext is up to a block length larger than the plaintext.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hKey session key specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// The data to be encrypted is not valid. For example, when a block cipher is used and the Final flag is FALSE, the value specified
		/// by pdwDataLen must be a multiple of the block size.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hHash parameter contains a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH_STATE</term>
		/// <term>An attempt was made to add data to a hash object that is already marked "finished."</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hKey parameter does not contain a valid handle to a key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_LEN</term>
		/// <term>The size of the output buffer is too small to hold the generated ciphertext.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_DOUBLE_ENCRYPT</term>
		/// <term>The application attempted to encrypt the same data twice.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If a large amount of data is to be encrypted, it can be done in sections by calling <c>CryptEncrypt</c> repeatedly. The Final
		/// parameter must be set to <c>TRUE</c> on the last call to <c>CryptEncrypt</c>, so that the encryption engine can properly finish
		/// the encryption process. The following extra actions are performed when Final is <c>TRUE</c>:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key is a block cipher key, the data is padded to a multiple of the block size of the cipher. If the data length equals
		/// the block size of the cipher, one additional block of padding is appended to the data. To find the block size of a cipher, use
		/// CryptGetKeyParam to get the KP_BLOCKLEN value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the cipher is operating in a chaining mode, the next <c>CryptEncrypt</c> operation resets the cipher's feedback register to
		/// the KP_IV value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the cipher is a stream cipher, the next <c>CryptEncrypt</c> resets the cipher to its initial state.</term>
		/// </item>
		/// </list>
		/// <para>
		/// There is no way to set the cipher's feedback register to the KP_IV value of the key without setting the Final parameter to
		/// <c>TRUE</c>. If this is necessary, as in the case where you do not want to add an additional padding block or change the size of
		/// each block, you can simulate this by creating a duplicate of the original key by using the CryptDuplicateKey function, and
		/// passing the duplicate key to the <c>CryptEncrypt</c> function. This causes the KP_IV of the original key to be placed in the
		/// duplicate key. After you create or import the original key, you cannot use the original key for encryption because the feedback
		/// register of the key will be changed. The following pseudocode shows how this can be done.
		/// </para>
		/// <para>
		/// The Microsoft Enhanced Cryptographic Provider supports direct encryption with RSA public keys and decryption with RSA private
		/// keys. The encryption uses PKCS #1 padding. On decryption, this padding is verified. The length of plaintext data that can be
		/// encrypted with a call to <c>CryptEncrypt</c> with an RSA key is the length of the key modulus minus eleven bytes. The eleven
		/// bytes is the chosen minimum for PKCS #1 padding. The ciphertext is returned in little-endian format.
		/// </para>
		/// <para>Examples</para>
		/// <para>For examples that use this function, see Example C Program: Encrypting a File and Example C Program: Decrypting a File.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptencrypt BOOL CryptEncrypt( HCRYPTKEY hKey,
		// HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "697c4960-552b-4c3a-95cf-4632af56945b")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEncrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, CryptEncryptFlags dwFlags, [In, Out] IntPtr pbData, ref uint pdwDataLen, uint dwBufLen);

		/// <summary>
		/// <para>
		/// The CryptEncrypt function encrypts data. The algorithm used to encrypt the data is designated by the key held by the CSP module
		/// and is referenced by the hKey parameter.
		/// </para>
		/// <para>
		/// Important changes to support Secure/Multipurpose Internet Mail Extensions (S/MIME) email interoperability have been made to
		/// CryptoAPI that affect the handling of enveloped messages. For more information, see the Remarks section of CryptMsgOpenToEncode.
		/// </para>
		/// <para>
		/// <c>Important</c> The <c>CryptEncrypt</c> function is not guaranteed to be thread safe and may return incorrect results if
		/// invoked simultaneously by multiple callers.
		/// </para>
		/// </summary>
		/// <param name="hKey">
		/// <para>
		/// A handle to the encryption key. An application obtains this handle by using either the CryptGenKey or the CryptImportKey function.
		/// </para>
		/// <para>The key specifies the encryption algorithm used.</para>
		/// </param>
		/// <param name="hHash">
		/// <para>
		/// A handle to a hash object. If data is to be hashed and encrypted simultaneously, a handle to a hash object can be passed in the
		/// hHash parameter. The hash value is updated with the plaintext passed in. This option is useful when generating signed and
		/// encrypted text.
		/// </para>
		/// <para>
		/// Before calling <c>CryptEncrypt</c>, the application must obtain a handle to the hash object by calling the CryptCreateHash
		/// function. After the encryption is complete, the hash value can be obtained by using the CryptGetHashParam function, or the hash
		/// can be signed by using the CryptSignHash function.
		/// </para>
		/// <para>If no hash is to be done, this parameter must be <c>NULL</c>.</para>
		/// </param>
		/// <param name="Final">
		/// A Boolean value that specifies whether this is the last section in a series being encrypted. Final is set to <c>TRUE</c> for the
		/// last or only block and to <c>FALSE</c> if there are more blocks to be encrypted. For more information, see Remarks.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following dwFlags value is defined but reserved for future use.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_OAEP</term>
		/// <term>
		/// Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced
		/// Cryptographic Provider with RSA encryption/decryption.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer that contains the plaintext to be encrypted. The plaintext in this buffer is overwritten with the
		/// ciphertext created by this function.
		/// </para>
		/// <para>
		/// The pdwDataLen parameter points to a variable that contains the length, in bytes, of the plaintext. The dwBufLen parameter
		/// contains the total size, in bytes, of this buffer.
		/// </para>
		/// <para>
		/// If this parameter contains <c>NULL</c>, this function will calculate the required size for the ciphertext and place that in the
		/// value pointed to by the pdwDataLen parameter.
		/// </para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that , on entry, contains the length, in bytes, of the plaintext in the pbData buffer. On
		/// exit, this <c>DWORD</c> contains the length, in bytes, of the ciphertext written to the pbData buffer.
		/// </para>
		/// <para>
		/// If the buffer allocated for pbData is not large enough to hold the encrypted data, GetLastError returns <c>ERROR_MORE_DATA</c>
		/// and stores the required buffer size, in bytes, in the <c>DWORD</c> value pointed to by pdwDataLen.
		/// </para>
		/// <para>
		/// If pbData is <c>NULL</c>, no error is returned, and the function stores the size of the encrypted data, in bytes, in the
		/// <c>DWORD</c> value pointed to by pdwDataLen. This allows an application to determine the correct buffer size.
		/// </para>
		/// <para>
		/// When a block cipher is used, this data length must be a multiple of the block size unless this is the final section of data to
		/// be encrypted and the Final parameter is <c>TRUE</c>.
		/// </para>
		/// </param>
		/// <param name="dwBufLen">
		/// <para>Specifies the total size, in bytes, of the input pbData buffer.</para>
		/// <para>
		/// Note that, depending on the algorithm used, the encrypted text can be larger than the original plaintext. In this case, the
		/// pbData buffer needs to be large enough to contain the encrypted text and any padding.
		/// </para>
		/// <para>
		/// As a rule, if a stream cipher is used, the ciphertext is the same size as the plaintext. If a block cipher is used, the
		/// ciphertext is up to a block length larger than the plaintext.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hKey session key specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// The data to be encrypted is not valid. For example, when a block cipher is used and the Final flag is FALSE, the value specified
		/// by pdwDataLen must be a multiple of the block size.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hHash parameter contains a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH_STATE</term>
		/// <term>An attempt was made to add data to a hash object that is already marked "finished."</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hKey parameter does not contain a valid handle to a key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_LEN</term>
		/// <term>The size of the output buffer is too small to hold the generated ciphertext.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_DOUBLE_ENCRYPT</term>
		/// <term>The application attempted to encrypt the same data twice.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If a large amount of data is to be encrypted, it can be done in sections by calling <c>CryptEncrypt</c> repeatedly. The Final
		/// parameter must be set to <c>TRUE</c> on the last call to <c>CryptEncrypt</c>, so that the encryption engine can properly finish
		/// the encryption process. The following extra actions are performed when Final is <c>TRUE</c>:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key is a block cipher key, the data is padded to a multiple of the block size of the cipher. If the data length equals
		/// the block size of the cipher, one additional block of padding is appended to the data. To find the block size of a cipher, use
		/// CryptGetKeyParam to get the KP_BLOCKLEN value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the cipher is operating in a chaining mode, the next <c>CryptEncrypt</c> operation resets the cipher's feedback register to
		/// the KP_IV value of the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the cipher is a stream cipher, the next <c>CryptEncrypt</c> resets the cipher to its initial state.</term>
		/// </item>
		/// </list>
		/// <para>
		/// There is no way to set the cipher's feedback register to the KP_IV value of the key without setting the Final parameter to
		/// <c>TRUE</c>. If this is necessary, as in the case where you do not want to add an additional padding block or change the size of
		/// each block, you can simulate this by creating a duplicate of the original key by using the CryptDuplicateKey function, and
		/// passing the duplicate key to the <c>CryptEncrypt</c> function. This causes the KP_IV of the original key to be placed in the
		/// duplicate key. After you create or import the original key, you cannot use the original key for encryption because the feedback
		/// register of the key will be changed. The following pseudocode shows how this can be done.
		/// </para>
		/// <para>
		/// The Microsoft Enhanced Cryptographic Provider supports direct encryption with RSA public keys and decryption with RSA private
		/// keys. The encryption uses PKCS #1 padding. On decryption, this padding is verified. The length of plaintext data that can be
		/// encrypted with a call to <c>CryptEncrypt</c> with an RSA key is the length of the key modulus minus eleven bytes. The eleven
		/// bytes is the chosen minimum for PKCS #1 padding. The ciphertext is returned in little-endian format.
		/// </para>
		/// <para>Examples</para>
		/// <para>For examples that use this function, see Example C Program: Encrypting a File and Example C Program: Decrypting a File.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptencrypt BOOL CryptEncrypt( HCRYPTKEY hKey,
		// HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "697c4960-552b-4c3a-95cf-4632af56945b")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEncrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, [MarshalAs(UnmanagedType.Bool)] bool Final, CryptEncryptFlags dwFlags, [In, Out] byte[] pbData, ref int pdwDataLen, int dwBufLen);

		/// <summary>
		/// The CryptEnumProviders function retrieves the first or next available cryptographic service providers (CSPs). Used in a loop,
		/// this function can retrieve in sequence all of the CSPs available on a computer.
		/// <para>
		/// Possible CSPs include Microsoft Base Cryptographic Provider version 1.0 and Microsoft Enhanced Cryptographic Provider version 1.0.
		/// </para>
		/// </summary>
		/// <param name="dwIndex">Index of the next provider to be enumerated.</param>
		/// <param name="pdwReserved">Reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <param name="pdwProvType">Address of the <c>DWORD</c> value designating the type of the enumerated provider.</param>
		/// <param name="szProvName">
		/// <para>
		/// A pointer to a buffer that receives the data from the enumerated provider. This is a string including the terminating null character.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to set the size of the name for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbProvName">
		/// <para>
		/// A pointer to a <c>DWORD</c> value specifying the size, in bytes, of the buffer pointed to by the pszProvName parameter. When the
		/// function returns, the <c>DWORD</c> value contains the number of bytes stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>The pszProvName buffer was not large enough to hold the provider name.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NO_MORE_ITEMS</term>
		/// <term>There are no more items to enumerate.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter has an unrecognized value.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>Something was wrong with the type registration.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>This function enumerates the providers available on a computer. The provider types can be enumerated by using CryptEnumProviderTypes.</para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows a loop listing all available cryptographic service providers. For another example that uses the
		/// <c>CryptEnumProviders</c> function, see Example C Program: Enumerating CSP Providers and Provider Types.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptenumprovidersa BOOL CryptEnumProvidersA( DWORD
		// dwIndex, DWORD *pdwReserved, DWORD dwFlags, DWORD *pdwProvType, LPSTR szProvName, DWORD *pcbProvName );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "2d93ef0f-b48f-481b-ba62-c535476fde08")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEnumProviders(uint dwIndex, [Optional] IntPtr pdwReserved, [Optional] uint dwFlags, out uint pdwProvType, [Optional, MarshalAs(UnmanagedType.LPTStr)] StringBuilder szProvName, ref uint pcbProvName);

		/// <summary>
		/// The CryptEnumProviders function retrieves the first or next available cryptographic service providers (CSPs). Used in a loop,
		/// this function can retrieve in sequence all of the CSPs available on a computer.
		/// <para>
		/// Possible CSPs include Microsoft Base Cryptographic Provider version 1.0 and Microsoft Enhanced Cryptographic Provider version 1.0.
		/// </para>
		/// </summary>
		/// <returns>A sequence of tuples with a provider name and type.</returns>
		[PInvokeData("wincrypt.h", MSDNShortId = "2d93ef0f-b48f-481b-ba62-c535476fde08")]
		public static IEnumerable<Tuple<uint, string>> CryptEnumProviders()
		{
			var idx = 0U;
			uint type;
			var sb = new StringBuilder(1024);
			var sz = 0U;
			while (CryptEnumProviders(idx, default, 0, out type, null, ref sz))
			{
				sb.EnsureCapacity((int)sz);
				if (CryptEnumProviders(idx, default, 0, out type, sb, ref sz))
				{
					yield return new Tuple<uint, string>(type, sb.ToString());
					++idx;
				}
				else
					Win32Error.ThrowLastError();
			}
		}

		/// <summary>
		/// The CryptEnumProviderTypes function retrieves the first or next types of cryptographic service provider (CSP) supported on the
		/// computer. Used in a loop, this function retrieves in sequence all of the CSP types available on a computer.
		/// <para>Provider types include PROV_RSA_FULL, PROV_RSA_SCHANNEL, and PROV_DSS.</para>
		/// </summary>
		/// <param name="dwIndex">Index of the next provider type to be enumerated.</param>
		/// <param name="pdwReserved">Reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <param name="pdwProvType">Address of the <c>DWORD</c> value designating the enumerated provider type.</param>
		/// <param name="szTypeName">
		/// <para>
		/// A pointer to a buffer that receives the data from the enumerated provider type. This is a string including the terminating
		/// <c>NULL</c> character. Some provider types do not have display names, and in this case no name is returned and the returned
		/// value pointed to by pcbTypeName is zero.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to get the size of the name for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbTypeName">
		/// <para>
		/// A pointer to a <c>DWORD</c> value specifying the size, in bytes, of the buffer pointed to by the pszTypeName parameter. When the
		/// function returns, the <c>DWORD</c> value contains the number of bytes stored or to be stored in the buffer. Some provider types
		/// do not have display names, and in this case no name is returned and the returned value pointed to by pcbTypeName is zero.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_NO_MORE_ITEMS</term>
		/// <term>There are no more items to enumerate.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter has an unrecognized value.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>Something was wrong with the type registration.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function enumerates the provider types available on a computer. Providers for any specific provider type can be enumerated
		/// using CryptEnumProviders.
		/// </para>
		/// <para>Examples</para>
		/// <para>The following example shows a loop listing all available cryptographic service provider types.</para>
		/// <para>
		/// For another example that uses the <c>CryptEnumProviderTypes</c> function, see Example C Program: Enumerating CSP Providers and
		/// Provider Types.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptenumprovidertypesa BOOL CryptEnumProviderTypesA(
		// DWORD dwIndex, DWORD *pdwReserved, DWORD dwFlags, DWORD *pdwProvType, LPSTR szTypeName, DWORD *pcbTypeName );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "7568c963-4d06-4af0-bd15-240402425046")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptEnumProviderTypes(uint dwIndex, [Optional] IntPtr pdwReserved, [Optional] uint dwFlags, out uint pdwProvType, [Optional, MarshalAs(UnmanagedType.LPTStr)] StringBuilder szTypeName, ref uint pcbTypeName);

		/// <summary>
		/// The CryptEnumProviderTypes function retrieves the first or next types of cryptographic service provider (CSP) supported on the
		/// computer. Used in a loop, this function retrieves in sequence all of the CSP types available on a computer.
		/// <para>Provider types include PROV_RSA_FULL, PROV_RSA_SCHANNEL, and PROV_DSS.</para>
		/// </summary>
		/// <returns>A sequence of tuples with a provider type name and type.</returns>
		[PInvokeData("wincrypt.h", MSDNShortId = "7568c963-4d06-4af0-bd15-240402425046")]
		public static IEnumerable<Tuple<uint, string>> CryptEnumProviderTypes()
		{
			var idx = 0U;
			uint type;
			var sb = new StringBuilder(1024);
			var sz = 0U;
			while (CryptEnumProviderTypes(idx, default, 0, out type, null, ref sz))
			{
				sb.EnsureCapacity((int)sz);
				if (CryptEnumProviderTypes(idx, default, 0, out type, sb, ref sz))
				{
					yield return new Tuple<uint, string>(type, sb.ToString());
					++idx;
				}
				else
					Win32Error.ThrowLastError();
			}
		}

		/// <summary>
		/// <para>
		/// The CryptExportKey function exports a cryptographic key or a key pair from a cryptographic service provider (CSP) in a secure manner.
		/// </para>
		/// <para>
		/// A handle to the key to be exported is passed to the function, and the function returns a key BLOB. This key BLOB can be sent
		/// over a nonsecure transport or stored in a nonsecure storage location. This function can export an Schannel session key, regular
		/// session key, public key, or public/private key pair. The key BLOB to export is useless until the intended recipient uses the
		/// CryptImportKey function on it to import the key or key pair into a recipient's CSP.
		/// </para>
		/// </summary>
		/// <param name="hKey">A handle to the key to be exported.</param>
		/// <param name="hExpKey">
		/// <para>
		/// A handle to a cryptographic key of the destination user. The key data within the exported key BLOB is encrypted using this key.
		/// This ensures that only the destination user is able to make use of the key BLOB. Both hExpKey and hKey must come from the same CSP.
		/// </para>
		/// <para>
		/// Most often, this is the key exchange public key of the destination user. However, certain protocols in some CSPs require that a
		/// session key belonging to the destination user be used for this purpose.
		/// </para>
		/// <para>If the key BLOB type specified by dwBlobType is <c>PUBLICKEYBLOB</c>, this parameter is unused and must be set to zero.</para>
		/// <para>
		/// If the key BLOB type specified by dwBlobType is <c>PRIVATEKEYBLOB</c>, this is typically a handle to a session key that is to be
		/// used to encrypt the key BLOB. Some CSPs allow this parameter to be zero, in which case the application must encrypt the private
		/// key BLOB manually so as to protect it.
		/// </para>
		/// <para>
		/// To determine how Microsoft cryptographic service providers respond to this parameter, see the private key BLOB sections of
		/// Microsoft Cryptographic Service Providers.
		/// </para>
		/// <para>
		/// <c>Note</c> Some CSPs may modify this parameter as a result of the operation. Applications that subsequently use this key for
		/// other purposes should call the CryptDuplicateKey function to create a duplicate key handle. When the application has finished
		/// using the handle, release it by calling the CryptDestroyKey function.
		/// </para>
		/// </param>
		/// <param name="dwBlobType">
		/// <para>
		/// Specifies the type of key BLOB to be exported in pbData. This must be one of the following constants as discussed in
		/// Cryptographic Key Storage and Exchange.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>OPAQUEKEYBLOB</term>
		/// <term>
		/// Used to store session keys in an Schannel CSP or any other vendor-specific format. OPAQUEKEYBLOBs are nontransferable and must
		/// be used within the CSP that generated the BLOB.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PRIVATEKEYBLOB</term>
		/// <term>Used to transport public/private key pairs.</term>
		/// </item>
		/// <item>
		/// <term>PUBLICKEYBLOB</term>
		/// <term>Used to transport public keys.</term>
		/// </item>
		/// <item>
		/// <term>SIMPLEBLOB</term>
		/// <term>Used to transport session keys.</term>
		/// </item>
		/// <item>
		/// <term>PLAINTEXTKEYBLOB</term>
		/// <term>A PLAINTEXTKEYBLOB used to export any key supported by the CSP in use.</term>
		/// </item>
		/// <item>
		/// <term>SYMMETRICWRAPKEYBLOB</term>
		/// <term>
		/// Used to export and import a symmetric key wrapped with another symmetric key. The actual wrapped key is in the format specified
		/// in the IETF RFC 3217 standard.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// Specifies additional options for the function. This parameter can be zero or a combination of one or more of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_BLOB_VER3 0x00000080</term>
		/// <term>This flag causes this function to export version 3 of a BLOB type.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DESTROYKEY 0x00000004</term>
		/// <term>This flag destroys the original key in the OPAQUEKEYBLOB. This flag is available in Schannel CSPs only.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_OAEP 0x00000040</term>
		/// <term>This flag causes PKCS #1 version 2 formatting to be created with the RSA encryption and decryption when exporting SIMPLEBLOBs.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SSL2_FALLBACK 0x00000002</term>
		/// <term>
		/// The first eight bytes of the RSA encryption block padding must be set to 0x03 rather than to random data. This prevents version
		/// rollback attacks and is discussed in the SSL3 specification. This flag is available for Schannel CSPs only.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_Y_ONLY 0x00000001</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer that receives the key BLOB data. The format of this BLOB varies depending on the BLOB type requested in
		/// the dwBlobType parameter. For the format for PRIVATEKEYBLOBs, PUBLICKEYBLOBs, and SIMPLEBLOBs, see Base Provider Key BLOBs.
		/// </para>
		/// <para>
		/// If this parameter is <c>NULL</c>, the required buffer size is placed in the value pointed to by the pdwDataLen parameter. For
		/// more information, see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that, on entry, contains the size, in bytes, of the buffer pointed to by the pbData parameter.
		/// When the function returns, this value contains the number of bytes stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. On input, buffer sizes are usually specified
		/// large enough to ensure that the largest possible output data fits in the buffer. On output, the variable pointed to by this
		/// parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// <para>To retrieve the required size of the</para>
		/// <para>pbData</para>
		/// <para>buffer, pass</para>
		/// <para>NULL</para>
		/// <para>for</para>
		/// <para>pbData</para>
		/// <para>. The required buffer size will be placed in the value pointed to by this parameter.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. The following table shows some of the possible
		/// error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pdwDataLen.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// Either the algorithm that works with the public key to be exported is not supported by this CSP, or an attempt was made to
		/// export a session key that was encrypted with something other than one of your public keys.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>One or both of the keys specified by hKey and hExpKey are not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY_STATE</term>
		/// <term>
		/// You do not have permission to export the key. That is, when the hKey key was created, the CRYPT_EXPORTABLE flag was not specified.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_PUBLIC_KEY</term>
		/// <term>The key BLOB type specified by dwBlobType is PUBLICKEYBLOB, but hExpKey does not contain a public key handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwBlobType parameter specifies an unknown BLOB type.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hKey key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_KEY</term>
		/// <term>A session key is being exported, and the hExpKey parameter does not specify a public key.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// For any of the DES key permutations that use a PLAINTEXTKEYBLOB, only the full key size, including parity bit, may be exported.
		/// The following key sizes are supported.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Algorithm</term>
		/// <term>Supported key size</term>
		/// </listheader>
		/// <item>
		/// <term>CALG_DES</term>
		/// <term>64 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES_112</term>
		/// <term>128 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES</term>
		/// <term>192 bits</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows how to export a cryptographic key or a key pair in a more secure manner. This example assumes that a
		/// cryptographic context has been acquired and that a public key is available for export. For an example that includes the complete
		/// context for using this function, see Example C Program: Signing a Hash and Verifying the Hash Signature. For another example
		/// that uses this function, see Example C Program: Exporting a Session Key.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptexportkey BOOL CryptExportKey( HCRYPTKEY hKey,
		// HCRYPTKEY hExpKey, DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "8a7c7b46-3bea-4043-b568-6d91d6335737")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptExportKey(HCRYPTKEY hKey, HCRYPTKEY hExpKey, [MarshalAs(UnmanagedType.U4)] BlobType dwBlobType, CryptExportKeyFlags dwFlags, [Out, Optional] IntPtr pbData, ref uint pdwDataLen);

		/// <summary>
		/// <para>
		/// The CryptGenKey function generates a random cryptographic session key or a public/private key pair. A handle to the key or key
		/// pair is returned in phKey. This handle can then be used as needed with any CryptoAPI function that requires a key handle.
		/// </para>
		/// <para>
		/// The calling application must specify the algorithm when calling this function. Because this algorithm type is kept bundled with
		/// the key, the application does not need to specify the algorithm later when the actual cryptographic operations are performed.
		/// </para>
		/// </summary>
		/// <param name="hProv">A handle to a cryptographic service provider (CSP) created by a call to CryptAcquireContext.</param>
		/// <param name="Algid">
		/// <para>
		/// An ALG_ID value that identifies the algorithm for which the key is to be generated. Values for this parameter vary depending on
		/// the CSP used.
		/// </para>
		/// <para>For <c>ALG_ID</c> values to use with the Microsoft Base Cryptographic Provider, see Base Provider Algorithms.</para>
		/// <para>
		/// For <c>ALG_ID</c> values to use with the Microsoft Strong Cryptographic Provider or the Microsoft Enhanced Cryptographic
		/// Provider, see Enhanced Provider Algorithms.
		/// </para>
		/// <para>For a Diffie-Hellman CSP, use one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CALG_DH_EPHEM</term>
		/// <term>Specifies an "Ephemeral" Diffie-Hellman key.</term>
		/// </item>
		/// <item>
		/// <term>CALG_DH_SF</term>
		/// <term>Specifies a "Store and Forward" Diffie-Hellman key.</term>
		/// </item>
		/// </list>
		/// <para>
		/// In addition to generating session keys for symmetric algorithms, this function can also generate public/private key pairs. Each
		/// CryptoAPI client generally possesses two public/private key pairs. To generate one of these key pairs, set the Algid parameter
		/// to one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>AT_KEYEXCHANGE</term>
		/// <term>Key exchange</term>
		/// </item>
		/// <item>
		/// <term>AT_SIGNATURE</term>
		/// <term>Digital signature</term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> When key specifications AT_KEYEXCHANGE and AT_SIGNATURE are specified, the algorithm identifiers that are used to
		/// generate the key depend on the provider used. As a result, for these key specifications, the values returned from
		/// CryptGetKeyParam (when the KP_ALGID parameter is specified) depend on the provider used. To determine which algorithm identifier
		/// is used by the different providers for the key specs AT_KEYEXCHANGE and AT_SIGNATURE, see ALG_ID.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// Specifies the type of key generated. The sizes of a session key, RSA signature key, and RSA key exchange keys can be set when
		/// the key is generated. The key size, representing the length of the key modulus in bits, is set with the upper 16 bits of this
		/// parameter. Thus, if a 2,048-bit RSA signature key is to be generated, the value 0x08000000 is combined with any other dwFlags
		/// predefined value with a bitwise- <c>OR</c> operation. The upper 16 bits of 0x08000000 is 0x0800, or decimal 2,048. The
		/// <c>RSA1024BIT_KEY</c> value can be used to specify a 1024-bit RSA key.
		/// </para>
		/// <para>
		/// Due to changing export control restrictions, the default CSP and default key length may change between operating system
		/// versions. It is important that both the encryption and decryption use the same CSP and that the key length be explicitly set
		/// using the dwFlags parameter to ensure interoperability on different operating system platforms.
		/// </para>
		/// <para>
		/// In particular, the default RSA Full Cryptographic Service Provider is the Microsoft RSA Strong Cryptographic Provider. The
		/// default DSS Signature Diffie-Hellman Cryptographic Service Provider is the Microsoft Enhanced DSS Diffie-Hellman Cryptographic
		/// Provider. Each of these CSPs has a default 128-bit symmetric key length for RC2 and RC4 and a 1,024-bit default key length for
		/// public key algorithms.
		/// </para>
		/// <para>
		/// If the upper 16 bits is zero, the default key size is generated. If a key larger than the maximum or smaller than the minimum is
		/// specified, the call fails with the ERROR_INVALID_PARAMETER code.
		/// </para>
		/// <para>The following table lists minimum, default, and maximum signature and exchange key lengths beginning with Windows XP.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Key type and provider</term>
		/// <term>Minimum length</term>
		/// <term>Default length</term>
		/// <term>Maximum length</term>
		/// </listheader>
		/// <item>
		/// <term>RSA Base Provider Signature and ExchangeKeys</term>
		/// <term>384</term>
		/// <term>512</term>
		/// <term>16,384</term>
		/// </item>
		/// <item>
		/// <term>RSA Strong and Enhanced Providers Signature and Exchange Keys</term>
		/// <term>384</term>
		/// <term>1,024</term>
		/// <term>16,384</term>
		/// </item>
		/// <item>
		/// <term>DSS Base Providers Signature Keys</term>
		/// <term>512</term>
		/// <term>1,024</term>
		/// <term>1,024</term>
		/// </item>
		/// <item>
		/// <term>DSS Base Providers Exchange Keys</term>
		/// <term>Not applicable</term>
		/// <term>Not applicable</term>
		/// <term>Not applicable</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Base Providers Signature Keys</term>
		/// <term>512</term>
		/// <term>1,024</term>
		/// <term>1,024</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Base Providers Exchange Keys</term>
		/// <term>512</term>
		/// <term>512</term>
		/// <term>1,024</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enhanced Providers Signature Keys</term>
		/// <term>512</term>
		/// <term>1,024</term>
		/// <term>1,024</term>
		/// </item>
		/// <item>
		/// <term>DSS/DH Enhanced Providers Exchange Keys</term>
		/// <term>512</term>
		/// <term>1,024</term>
		/// <term>4,096</term>
		/// </item>
		/// </list>
		/// <para>For session key lengths, see CryptDeriveKey.</para>
		/// <para>For more information about keys generated using Microsoft providers, see Microsoft Cryptographic Service Providers.</para>
		/// <para>The lower 16-bits of this parameter can be zero or a combination of one or more of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_ARCHIVABLE</term>
		/// <term>
		/// If this flag is set, the key can be exported until its handle is closed by a call to CryptDestroyKey. This allows newly
		/// generated keys to be exported upon creation for archiving or key recovery. After the handle is closed, the key is no longer exportable.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_CREATE_IV</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_CREATE_SALT</term>
		/// <term>
		/// If this flag is set, then the key is assigned a random salt value automatically. You can retrieve this salt value by using the
		/// CryptGetKeyParam function with the dwParam parameter set to KP_SALT. If this flag is not set, then the key is given a salt value
		/// of zero. When keys with nonzero salt values are exported (through CryptExportKey), then the salt value must also be obtained and
		/// kept with the key BLOB.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_DATA_KEY</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_EXPORTABLE</term>
		/// <term>
		/// If this flag is set, then the key can be transferred out of the CSP into a key BLOB by using the CryptExportKey function.
		/// Because session keys generally must be exportable, this flag should usually be set when they are created. If this flag is not
		/// set, then the key is not exportable. For a session key, this means that the key is available only within the current session and
		/// only the application that created it will be able to use it. For a public/private key pair, this means that the private key
		/// cannot be transported or backed up. This flag applies only to session key and private key BLOBs. It does not apply to public
		/// keys, which are always exportable.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_FORCE_KEY_PROTECTION_HIGH</term>
		/// <term>
		/// This flag specifies strong key protection. When this flag is set, the user is prompted to enter a password for the key when the
		/// key is created. The user will be prompted to enter the password whenever this key is used. This flag is only used by the CSPs
		/// that are provided by Microsoft. Third party CSPs will define their own behavior for strong key protection. Specifying this flag
		/// causes the same result as calling this function with the CRYPT_USER_PROTECTED flag when strong key protection is specified in
		/// the system registry. If this flag is specified and the provider handle in the hProv parameter was created by using the
		/// CRYPT_VERIFYCONTEXT or CRYPT_SILENT flag, this function will set the last error to NTE_SILENT_CONTEXT and return zero. Windows
		/// Server 2003 and Windows XP: This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_KEK</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_INITIATOR</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NO_SALT</term>
		/// <term>
		/// This flag specifies that a no salt value gets allocated for a forty-bit symmetric key. For more information, see Salt Value Functionality.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_ONLINE</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_PREGEN</term>
		/// <term>
		/// This flag specifies an initial Diffie-Hellman or DSS key generation. This flag is useful only with Diffie-Hellman and DSS CSPs.
		/// When used, a default key length will be used unless a key length is specified in the upper 16 bits of the dwFlags parameter. If
		/// parameters that involve key lengths are set on a PREGEN Diffie-Hellman or DSS key using CryptSetKeyParam, the key lengths must
		/// be compatible with the key length set here.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_RECIPIENT</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SF</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SGCKEY</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_USER_PROTECTED</term>
		/// <term>
		/// If this flag is set, the user is notified through a dialog box or another method when certain actions are attempting to use this
		/// key. The precise behavior is specified by the CSP being used. If the provider context was opened with the CRYPT_SILENT flag set,
		/// using this flag causes a failure and the last error is set to NTE_SILENT_CONTEXT.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_VOLATILE</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="phKey">
		/// Address to which the function copies the handle of the newly generated key. When you have finished using the key, delete the
		/// handle to the key by calling the CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>Returns nonzero if successful or zero otherwise.</para>
		/// <para>For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes are listed in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The Algid parameter specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_SILENT_CONTEXT</term>
		/// <term>The provider could not perform the action because the context was acquired as silent.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If keys are generated for symmetric block ciphers, the key, by default, is set up in cipher block chaining (CBC) mode with an
		/// initialization vector of zero. This cipher mode provides a good default method for bulk encrypting data. To change these
		/// parameters, use the CryptSetKeyParam function.
		/// </para>
		/// <para>To choose an appropriate key length, the following methods are recommended:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// Enumerate the algorithms that the CSP supports and get maximum and minimum key lengths for each algorithm. To do this, call
		/// CryptGetProvParam with PP_ENUMALGS_EX.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// Use the minimum and maximum lengths to choose an appropriate key length. It is not always advisable to choose the maximum length
		/// because this can lead to performance issues.
		/// </term>
		/// </item>
		/// <item>
		/// <term>After the desired key length has been chosen, use the upper 16 bits of the dwFlags parameter to specify the key length.</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows the creation of a random session key. For an example that includes the complete context for this
		/// example, see Example C Program: Encrypting a File. For another example that uses this function, see Example C Program:
		/// Decrypting a File.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenkey BOOL CryptGenKey( HCRYPTPROV hProv, ALG_ID
		// Algid, DWORD dwFlags, HCRYPTKEY *phKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "b65dd856-2dfa-4cda-9b2f-b32f3c291470")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGenKey(HCRYPTPROV hProv, ALG_ID Algid, CryptGenKeyFlags dwFlags, out SafeHCRYPTKEY phKey);

		/// <summary>The CryptGenRandom function fills a buffer with cryptographically random bytes.</summary>
		/// <param name="hProv">Handle of a cryptographic service provider (CSP) created by a call to CryptAcquireContext.</param>
		/// <param name="dwLen">Number of bytes of random data to be generated.</param>
		/// <param name="pbBuffer">
		/// <para>Buffer to receive the returned data. This buffer must be at least dwLen bytes in length.</para>
		/// <para>Optionally, the application can fill this buffer with data to use as an auxiliary random seed.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes are listed in the
		/// following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The data produced by this function is cryptographically random. It is far more random than the data generated by the typical
		/// random number generator such as the one shipped with your C compiler.
		/// </para>
		/// <para>This function is often used to generate random initialization vectors and salt values.</para>
		/// <para>
		/// Software random number generators work in fundamentally the same way. They start with a random number, known as the seed, and
		/// then use an algorithm to generate a pseudo-random sequence of bits based on it. The most difficult part of this process is to
		/// get a seed that is truly random. This is usually based on user input latency, or the jitter from one or more hardware components.
		/// </para>
		/// <para>
		/// With Microsoft CSPs, <c>CryptGenRandom</c> uses the same random number generator used by other security components. This allows
		/// numerous processes to contribute to a system-wide seed. CryptoAPI stores an intermediate random seed with every user. To form
		/// the seed for the random number generator, a calling application supplies bits it might have—for instance, mouse or keyboard
		/// timing input—that are then combined with both the stored seed and various system data and user data such as the process ID and
		/// thread ID, the system clock, the system time, the system counter, memory status, free disk clusters, the hashed user environment
		/// block. This result is used to seed the pseudorandom number generator (PRNG). In Windows Vista with Service Pack 1 (SP1) and
		/// later, an implementation of the AES counter-mode based PRNG specified in NIST Special Publication 800-90 is used. In Windows
		/// Vista, Windows Storage Server 2003, and Windows XP, the PRNG specified in Federal Information Processing Standard (FIPS) 186-2
		/// is used. If an application has access to a good random source, it can fill the pbBuffer buffer with some random data before
		/// calling <c>CryptGenRandom</c>. The CSP then uses this data to further randomize its internal seed. It is acceptable to omit the
		/// step of initializing the pbBuffer buffer before calling <c>CryptGenRandom</c>.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows the generation of 8 random bytes. These can be used to create cryptographic keys or for any
		/// application that uses random numbers. For an example that includes the complete context for this example, see Example C Program:
		/// Duplicating a Session Key.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom BOOL CryptGenRandom( HCRYPTPROV hProv,
		// DWORD dwLen, BYTE *pbBuffer );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "3e5a437f-7439-43c9-a191-2908d2df0eb6")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGenRandom(HCRYPTPROV hProv, uint dwLen, [In, Out] IntPtr pbBuffer);

		/// <summary>
		/// The CryptGetDefaultProvider function finds the default cryptographic service provider (CSP) of a specified provider type for the
		/// local computer or current user. The name of the default CSP for the provider type specified in the dwProvType parameter is
		/// returned in the pszProvName buffer.
		/// </summary>
		/// <param name="dwProvType">
		/// <para>The provider type for which the default CSP name is to be found.</para>
		/// <para>Defined provider types are as follows:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>PROV_RSA_FULL</term>
		/// </item>
		/// <item>
		/// <term>PROV_RSA_SIG</term>
		/// </item>
		/// <item>
		/// <term>PROV_DSS</term>
		/// </item>
		/// <item>
		/// <term>PROV_DSS_DH</term>
		/// </item>
		/// <item>
		/// <term>PROV_DH_SCHANNEL</term>
		/// </item>
		/// <item>
		/// <term>PROV_FORTEZZA</term>
		/// </item>
		/// <item>
		/// <term>PROV_MS_EXCHANGE</term>
		/// </item>
		/// <item>
		/// <term>PROV_RSA_SCHANNEL</term>
		/// </item>
		/// <item>
		/// <term>PROV_SSL</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pdwReserved">This parameter is reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_USER_DEFAULT 0x00000002</term>
		/// <term>Returns the user-context default CSP of the specified type.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_MACHINE_DEFAULT 0x00000001</term>
		/// <term>Returns the computer default CSP of the specified type.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pszProvName">
		/// <para>A pointer to a null-terminated character string buffer to receive the name of the default CSP.</para>
		/// <para>
		/// To find the size of the buffer for memory allocation purposes, this parameter can be <c>NULL</c>. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbProvName">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that specifies the size, in bytes, of the buffer pointed to by the pszProvName parameter. When
		/// the function returns, the <c>DWORD</c> value contains the number of bytes stored or to be stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error code prefaced by NTE is generated by the particular CSP being used. Possible error codes include the following.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>The buffer for the name is not large enough.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter has an unrecognized value.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function determines which installed CSP is currently set as the default for the local computer or current user. This
		/// information is often displayed to the user.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example retrieves the name of the default CSP for the PROV_RSA_FULL provider type. For another example that uses
		/// this function, see Example C Program: Enumerating CSP Providers and Provider Types.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgetdefaultprovidera BOOL CryptGetDefaultProviderA(
		// DWORD dwProvType, DWORD *pdwReserved, DWORD dwFlags, LPSTR pszProvName, DWORD *pcbProvName );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "5d15641e-1ad7-441d-9423-65fd51de9812")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGetDefaultProvider(uint dwProvType, [Optional] IntPtr pdwReserved, CryptProviderFlags dwFlags, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszProvName, ref uint pcbProvName);

		/// <summary>
		/// The CryptGetHashParam function retrieves data that governs the operations of a hash object. The actual hash value can be
		/// retrieved by using this function.
		/// </summary>
		/// <param name="hHash">Handle of the hash object to be queried.</param>
		/// <param name="dwParam">
		/// <para>Query type. This parameter can be set to one of the following queries.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>HP_ALGID Hash algorithm</term>
		/// <term>
		/// An ALG_ID that indicates the algorithm specified when the hash object was created. For a list of hash algorithms, see CryptCreateHash.
		/// </term>
		/// </item>
		/// <item>
		/// <term>HP_HASHSIZE Hash value size</term>
		/// <term>
		/// DWORD value indicating the number of bytes in the hash value. This value will vary depending on the hash algorithm. Applications
		/// must retrieve this value just before the HP_HASHVAL value so the correct amount of memory can be allocated.
		/// </term>
		/// </item>
		/// <item>
		/// <term>HP_HASHVAL Hash value</term>
		/// <term>
		/// The hash value or message hash for the hash object specified by hHash. This value is generated based on the data supplied to the
		/// hash object earlier through the CryptHashData and CryptHashSessionKey functions. The CryptGetHashParam function completes the
		/// hash. After CryptGetHashParam has been called, no more data can be added to the hash. Additional calls to CryptHashData or
		/// CryptHashSessionKey fail. After the application is done with the hash, CryptDestroyHash should be called to destroy the hash object.
		/// </term>
		/// </item>
		/// </list>
		/// <para><c>Note</c> CSPs can add more values that this function can query.</para>
		/// </param>
		/// <param name="pbData">
		/// <para>A pointer to a buffer that receives the specified value data. The form of this data varies, depending on the value number.</para>
		/// <para>This parameter can be <c>NULL</c> to determine the memory size required.</para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value specifying the size, in bytes, of the pbData buffer. When the function returns, the
		/// <c>DWORD</c> value contains the number of bytes stored in the buffer.
		/// </para>
		/// <para>If pbData is <c>NULL</c>, set the value of pdwDataLen to zero.</para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <param name="dwFlags">Reserved for future use and must be zero.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is <c>TRUE</c>.</para>
		/// <para>If the function fails, the return value is <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pdwDataLen.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown value number.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hash was created cannot be found.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgethashparam BOOL CryptGetHashParam( HCRYPTHASH
		// hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "ed008c07-1a40-4075-bdaa-eb7f7e12d9c3")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGetHashParam(HCRYPTHASH hHash, HashParam dwParam, [Out, Optional] IntPtr pbData, ref uint pdwDataLen, uint dwFlags = 0);

		/// <summary>
		/// The CryptGetHashParam function retrieves data that governs the operations of a hash object. The actual hash value can be
		/// retrieved by using this function.
		/// </summary>
		/// <typeparam name="T">The expected return type.</typeparam>
		/// <param name="hHash">Handle of the hash object to be queried.</param>
		/// <param name="dwParam">
		/// <para>Query type. This parameter can be set to one of the following queries.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>HP_ALGID Hash algorithm</term>
		/// <term>
		/// An ALG_ID that indicates the algorithm specified when the hash object was created. For a list of hash algorithms, see CryptCreateHash.
		/// </term>
		/// </item>
		/// <item>
		/// <term>HP_HASHSIZE Hash value size</term>
		/// <term>
		/// DWORD value indicating the number of bytes in the hash value. This value will vary depending on the hash algorithm. Applications
		/// must retrieve this value just before the HP_HASHVAL value so the correct amount of memory can be allocated.
		/// </term>
		/// </item>
		/// <item>
		/// <term>HP_HASHVAL Hash value</term>
		/// <term>
		/// The hash value or message hash for the hash object specified by hHash. This value is generated based on the data supplied to the
		/// hash object earlier through the CryptHashData and CryptHashSessionKey functions. The CryptGetHashParam function completes the
		/// hash. After CryptGetHashParam has been called, no more data can be added to the hash. Additional calls to CryptHashData or
		/// CryptHashSessionKey fail. After the application is done with the hash, CryptDestroyHash should be called to destroy the hash object.
		/// </term>
		/// </item>
		/// </list>
		/// <para><c>Note</c> CSPs can add more values that this function can query.</para>
		/// </param>
		/// <returns>The specified value data. The form of this data varies, depending on the value number.</returns>
		public static T CryptGetHashParam<T>(HCRYPTHASH hHash, HashParam dwParam) => CryptGetValue<HCRYPTHASH, HashParam, T>(CryptGetHashParam, hHash, dwParam);

		/// <summary>
		/// The CryptGetKeyParam function retrieves data that governs the operations of a key. If the Microsoft Cryptographic Service
		/// Provider is used, the base symmetric keying material is not obtainable by this or any other function.
		/// </summary>
		/// <param name="hKey">The handle of the key being queried.</param>
		/// <param name="dwParam">
		/// <para>Specifies the type of query being made.</para>
		/// <para>For all key types, this parameter can contain one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_ALGID</term>
		/// <term>
		/// Retrieve the key algorithm. The pbData parameter is a pointer to an ALG_ID value that receives the identifier of the algorithm
		/// that was specified when the key was created. When AT_KEYEXCHANGE or AT_SIGNATURE is specified for the Algid parameter of the
		/// CryptGenKey function, the algorithm identifiers that are used to generate the key depend on the provider used. For more
		/// information, see ALG_ID.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_BLOCKLEN</term>
		/// <term>
		/// If a session key is specified by the hKey parameter, retrieve the block length of the key cipher. The pbData parameter is a
		/// pointer to a DWORD value that receives the block length, in bits. For stream ciphers, this value is always zero. If a
		/// public/private key pair is specified by hKey, retrieve the encryption granularity of the key pair. The pbData parameter is a
		/// pointer to a DWORD value that receives the encryption granularity, in bits. For example, the Microsoft Base Cryptographic
		/// Provider generates 512-bit RSA key pairs, so a value of 512 is returned for these keys. If the public key algorithm does not
		/// support encryption, the value retrieved is undefined.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_CERTIFICATE</term>
		/// <term>
		/// pbData is the address of a buffer that receives the X.509 certificate that has been encoded by using Distinguished Encoding
		/// Rules (DER). The public key in the certificate must match the corresponding signature or exchange key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_GET_USE_COUNT</term>
		/// <term>This value is not used.</term>
		/// </item>
		/// <item>
		/// <term>KP_KEYLEN</term>
		/// <term>
		/// Retrieve the actual length of the key. The pbData parameter is a pointer to a DWORD value that receives the key length, in bits.
		/// KP_KEYLEN can be used to get the length of any key type. Microsoft cryptographic service providers (CSPs) return a key length of
		/// 64 bits for CALG_DES, 128 bits for CALG_3DES_112, and 192 bits for CALG_3DES. These lengths are different from the lengths
		/// returned when you are enumerating algorithms with the dwParam value of the CryptGetProvParam function set to PP_ENUMALGS. The
		/// length returned by this call is the actual size of the key, including the parity bits included in the key. Microsoft CSPs that
		/// support the CALG_CYLINK_MEK ALG_ID return 64 bits for that algorithm. CALG_CYLINK_MEK is a 40-bit key but has parity and zeroed
		/// key bits to make the key length 64 bits.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_SALT</term>
		/// <term>
		/// Retrieve the salt value of the key. The pbData parameter is a pointer to a BYTE array that receives the salt value in
		/// little-endian form. The size of the salt value varies depending on the CSP and algorithm being used. Salt values do not apply to
		/// public/private key pairs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PERMISSIONS</term>
		/// <term>
		/// Retrieve the key permissions. The pbData parameter is a pointer to a DWORD value that receives the permission flags for the key.
		/// The following permission identifiers are currently defined. The key permissions can be zero or a combination of one or more of
		/// the following values. CRYPT_ARCHIVE Allow export during the lifetime of the handle of the key. This permission can be set only
		/// if it is already set in the internal permissions field of the key. Attempts to clear this permission are ignored. CRYPT_DECRYPT
		/// Allow decryption. CRYPT_ENCRYPT Allow encryption. CRYPT_EXPORT Allow the key to be exported. CRYPT_EXPORT_KEY Allow the key to
		/// be used for exporting keys. CRYPT_IMPORT_KEY Allow the key to be used for importing keys. CRYPT_MAC Allow Message Authentication
		/// Codes (MACs) to be used with key. CRYPT_READ Allow values to be read. CRYPT_WRITE Allow values to be set.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Digital Signature Standard (DSS) key is specified by the hKey parameter, the dwParam value can also be set to one of the
		/// following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_P</term>
		/// <term>
		/// Retrieve the modulus prime number P of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
		/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_Q</term>
		/// <term>
		/// Retrieve the modulus prime number Q of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
		/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_G</term>
		/// <term>
		/// Retrieve the generator G of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in little-endian
		/// form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a block cipher session key is specified by the hKey parameter, the dwParam value can also be set to one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_EFFECTIVE_KEYLEN</term>
		/// <term>
		/// Retrieve the effective key length of an RC2 key. The pbData parameter is a pointer to a DWORD value that receives the effective
		/// key length.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_IV</term>
		/// <term>
		/// Retrieve the initialization vector of the key. The pbData parameter is a pointer to a BYTE array that receives the
		/// initialization vector. The size of this array is the block size, in bytes. For example, if the block length is 64 bits, the
		/// initialization vector consists of 8 bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PADDING</term>
		/// <term>
		/// Retrieve the padding mode. The pbData parameter is a pointer to a DWORD value that receives a numeric identifier that identifies
		/// the padding method used by the cipher. This can be one of the following values. PKCS5_PADDING Specifies the PKCS 5 (sec 6.2)
		/// padding method. RANDOM_PADDING The padding uses random numbers. This padding method is not supported by the Microsoft supplied
		/// CSPs. ZERO_PADDING The padding uses zeros. This padding method is not supported by the Microsoft supplied CSPs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE</term>
		/// <term>
		/// Retrieve the cipher mode. The pbData parameter is a pointer to a DWORD value that receives a cipher mode identifier. For more
		/// information about cipher modes, see Data Encryption and Decryption. The following cipher mode identifiers are currently defined.
		/// CRYPT_MODE_CBC The cipher mode is cipher block chaining. CRYPT_MODE_CFB The cipher mode is cipher feedback (CFB). Microsoft CSPs
		/// currently support only 8-bit feedback in cipher feedback mode. CRYPT_MODE_ECB The cipher mode is electronic codebook.
		/// CRYPT_MODE_OFB The cipher mode is Output Feedback (OFB). Microsoft CSPs currently do not support Output Feedback Mode.
		/// CRYPT_MODE_CTS The cipher mode is ciphertext stealing mode.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE_BITS</term>
		/// <term>
		/// Retrieve the number of bits to feed back. The pbData parameter is a pointer to a DWORD value that receives the number of bits
		/// that are processed per cycle when the OFB or CFB cipher modes are used.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Diffie-Hellman algorithm or Digital Signature Algorithm (DSA) key is specified by hKey, the dwParam value can also be set
		/// to the following value.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_VERIFY_PARAMS</term>
		/// <term>
		/// Verifies the parameters of a Diffie-Hellman algorithm or DSA key. The pbData parameter is not used, and the value pointed to by
		/// pdwDataLen receives zero. This function returns a nonzero value if the key parameters are valid or zero otherwise.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_KEYVAL</term>
		/// <term>
		/// This value is not used. Windows Vista, Windows Server 2003 and Windows XP: Retrieve the secret agreement value from an imported
		/// Diffie-Hellman algorithm key of type CALG_AGREEDKEY_ANY. The pbData parameter is the address of a buffer that receives the
		/// secret agreement value, in little-endian format. This buffer must be the same length as the key. The dwFlags parameter must be
		/// set to 0xF42A19B6. This property can only be retrieved by a thread running under the local system account.This property is
		/// available for use in the operating systems listed above. It may be altered or unavailable in subsequent versions.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If a certificate is specified by hKey, the dwParam value can also be set to the following value.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_CERTIFICATE</term>
		/// <term>
		/// A buffer that contains the DER-encoded X.509 certificate. The pbData parameter is not used, and the value pointed to by
		/// pdwDataLen receives zero. This function returns a nonzero value if the key parameters are valid or zero otherwise.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>A pointer to a buffer that receives the data. The form of this data depends on the value of dwParam.</para>
		/// <para>
		/// If the size of this buffer is not known, the required size can be retrieved at run time by passing <c>NULL</c> for this
		/// parameter and setting the value pointed to by pdwDataLen to zero. This function will place the required size of the buffer, in
		/// bytes, in the value pointed to by pdwDataLen. For more information, see Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that, on entry, contains the size, in bytes, of the buffer pointed to by the pbData parameter.
		/// When the function returns, the <c>DWORD</c> value contains the number of bytes stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size may be slightly smaller than the size of the buffer specified on input. On input, buffer sizes are sometimes
		/// specified large enough to ensure that the largest possible output data fits in the buffer. On output, the variable pointed to by
		/// this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <param name="dwFlags">This parameter is reserved for future use and must be set to zero.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero.</para>
		/// <para>If the function fails, it returns zero. For extended error information, call GetLastError.</para>
		/// <para>
		/// The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes include the following.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pdwDataLen.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY or NTE_NO_KEY</term>
		/// <term>The key specified by the hKey parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown value number.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the key was created cannot be found.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgetkeyparam BOOL CryptGetKeyParam( HCRYPTKEY hKey,
		// DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "07956d74-0e22-484b-9bf1-e0184a2ff32f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGetKeyParam(HCRYPTKEY hKey, KeyParam dwParam, [Out, Optional] IntPtr pbData, ref uint pdwDataLen, uint dwFlags = 0);

		/// <summary>
		/// The CryptGetKeyParam function retrieves data that governs the operations of a key. If the Microsoft Cryptographic Service
		/// Provider is used, the base symmetric keying material is not obtainable by this or any other function.
		/// </summary>
		/// <typeparam name="T">The expected return type.</typeparam>
		/// <param name="hKey">The handle of the key being queried.</param>
		/// <param name="dwParam">
		/// <para>Specifies the type of query being made.</para>
		/// <para>For all key types, this parameter can contain one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_ALGID</term>
		/// <term>
		/// Retrieve the key algorithm. The pbData parameter is a pointer to an ALG_ID value that receives the identifier of the algorithm
		/// that was specified when the key was created. When AT_KEYEXCHANGE or AT_SIGNATURE is specified for the Algid parameter of the
		/// CryptGenKey function, the algorithm identifiers that are used to generate the key depend on the provider used. For more
		/// information, see ALG_ID.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_BLOCKLEN</term>
		/// <term>
		/// If a session key is specified by the hKey parameter, retrieve the block length of the key cipher. The pbData parameter is a
		/// pointer to a DWORD value that receives the block length, in bits. For stream ciphers, this value is always zero. If a
		/// public/private key pair is specified by hKey, retrieve the encryption granularity of the key pair. The pbData parameter is a
		/// pointer to a DWORD value that receives the encryption granularity, in bits. For example, the Microsoft Base Cryptographic
		/// Provider generates 512-bit RSA key pairs, so a value of 512 is returned for these keys. If the public key algorithm does not
		/// support encryption, the value retrieved is undefined.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_CERTIFICATE</term>
		/// <term>
		/// pbData is the address of a buffer that receives the X.509 certificate that has been encoded by using Distinguished Encoding
		/// Rules (DER). The public key in the certificate must match the corresponding signature or exchange key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_GET_USE_COUNT</term>
		/// <term>This value is not used.</term>
		/// </item>
		/// <item>
		/// <term>KP_KEYLEN</term>
		/// <term>
		/// Retrieve the actual length of the key. The pbData parameter is a pointer to a DWORD value that receives the key length, in bits.
		/// KP_KEYLEN can be used to get the length of any key type. Microsoft cryptographic service providers (CSPs) return a key length of
		/// 64 bits for CALG_DES, 128 bits for CALG_3DES_112, and 192 bits for CALG_3DES. These lengths are different from the lengths
		/// returned when you are enumerating algorithms with the dwParam value of the CryptGetProvParam function set to PP_ENUMALGS. The
		/// length returned by this call is the actual size of the key, including the parity bits included in the key. Microsoft CSPs that
		/// support the CALG_CYLINK_MEK ALG_ID return 64 bits for that algorithm. CALG_CYLINK_MEK is a 40-bit key but has parity and zeroed
		/// key bits to make the key length 64 bits.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_SALT</term>
		/// <term>
		/// Retrieve the salt value of the key. The pbData parameter is a pointer to a BYTE array that receives the salt value in
		/// little-endian form. The size of the salt value varies depending on the CSP and algorithm being used. Salt values do not apply to
		/// public/private key pairs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PERMISSIONS</term>
		/// <term>
		/// Retrieve the key permissions. The pbData parameter is a pointer to a DWORD value that receives the permission flags for the key.
		/// The following permission identifiers are currently defined. The key permissions can be zero or a combination of one or more of
		/// the following values. CRYPT_ARCHIVE Allow export during the lifetime of the handle of the key. This permission can be set only
		/// if it is already set in the internal permissions field of the key. Attempts to clear this permission are ignored. CRYPT_DECRYPT
		/// Allow decryption. CRYPT_ENCRYPT Allow encryption. CRYPT_EXPORT Allow the key to be exported. CRYPT_EXPORT_KEY Allow the key to
		/// be used for exporting keys. CRYPT_IMPORT_KEY Allow the key to be used for importing keys. CRYPT_MAC Allow Message Authentication
		/// Codes (MACs) to be used with key. CRYPT_READ Allow values to be read. CRYPT_WRITE Allow values to be set.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Digital Signature Standard (DSS) key is specified by the hKey parameter, the dwParam value can also be set to one of the
		/// following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_P</term>
		/// <term>
		/// Retrieve the modulus prime number P of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
		/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_Q</term>
		/// <term>
		/// Retrieve the modulus prime number Q of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in
		/// little-endian form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_G</term>
		/// <term>
		/// Retrieve the generator G of the DSS key. The pbData parameter is a pointer to a buffer that receives the value in little-endian
		/// form. The pdwDataLen parameter contains the size of the buffer, in bytes.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a block cipher session key is specified by the hKey parameter, the dwParam value can also be set to one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_EFFECTIVE_KEYLEN</term>
		/// <term>
		/// Retrieve the effective key length of an RC2 key. The pbData parameter is a pointer to a DWORD value that receives the effective
		/// key length.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_IV</term>
		/// <term>
		/// Retrieve the initialization vector of the key. The pbData parameter is a pointer to a BYTE array that receives the
		/// initialization vector. The size of this array is the block size, in bytes. For example, if the block length is 64 bits, the
		/// initialization vector consists of 8 bytes.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PADDING</term>
		/// <term>
		/// Retrieve the padding mode. The pbData parameter is a pointer to a DWORD value that receives a numeric identifier that identifies
		/// the padding method used by the cipher. This can be one of the following values. PKCS5_PADDING Specifies the PKCS 5 (sec 6.2)
		/// padding method. RANDOM_PADDING The padding uses random numbers. This padding method is not supported by the Microsoft supplied
		/// CSPs. ZERO_PADDING The padding uses zeros. This padding method is not supported by the Microsoft supplied CSPs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE</term>
		/// <term>
		/// Retrieve the cipher mode. The pbData parameter is a pointer to a DWORD value that receives a cipher mode identifier. For more
		/// information about cipher modes, see Data Encryption and Decryption. The following cipher mode identifiers are currently defined.
		/// CRYPT_MODE_CBC The cipher mode is cipher block chaining. CRYPT_MODE_CFB The cipher mode is cipher feedback (CFB). Microsoft CSPs
		/// currently support only 8-bit feedback in cipher feedback mode. CRYPT_MODE_ECB The cipher mode is electronic codebook.
		/// CRYPT_MODE_OFB The cipher mode is Output Feedback (OFB). Microsoft CSPs currently do not support Output Feedback Mode.
		/// CRYPT_MODE_CTS The cipher mode is ciphertext stealing mode.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE_BITS</term>
		/// <term>
		/// Retrieve the number of bits to feed back. The pbData parameter is a pointer to a DWORD value that receives the number of bits
		/// that are processed per cycle when the OFB or CFB cipher modes are used.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Diffie-Hellman algorithm or Digital Signature Algorithm (DSA) key is specified by hKey, the dwParam value can also be set
		/// to the following value.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_VERIFY_PARAMS</term>
		/// <term>
		/// Verifies the parameters of a Diffie-Hellman algorithm or DSA key. The pbData parameter is not used, and the value pointed to by
		/// pdwDataLen receives zero. This function returns a nonzero value if the key parameters are valid or zero otherwise.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_KEYVAL</term>
		/// <term>
		/// This value is not used. Windows Vista, Windows Server 2003 and Windows XP: Retrieve the secret agreement value from an imported
		/// Diffie-Hellman algorithm key of type CALG_AGREEDKEY_ANY. The pbData parameter is the address of a buffer that receives the
		/// secret agreement value, in little-endian format. This buffer must be the same length as the key. The dwFlags parameter must be
		/// set to 0xF42A19B6. This property can only be retrieved by a thread running under the local system account.This property is
		/// available for use in the operating systems listed above. It may be altered or unavailable in subsequent versions.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If a certificate is specified by hKey, the dwParam value can also be set to the following value.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_CERTIFICATE</term>
		/// <term>
		/// A buffer that contains the DER-encoded X.509 certificate. The pbData parameter is not used, and the value pointed to by
		/// pdwDataLen receives zero. This function returns a nonzero value if the key parameters are valid or zero otherwise.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>The specified value data. The form of this data varies, depending on the value number.</returns>
		public static T CryptGetKeyParam<T>(HCRYPTKEY hKey, KeyParam dwParam) => CryptGetValue<HCRYPTKEY, KeyParam, T>(CryptGetKeyParam, hKey, dwParam);

		/// <summary>
		/// The CryptGetProvParam function retrieves parameters that govern the operations of a cryptographic service provider (CSP).
		/// </summary>
		/// <param name="hProv">
		/// A handle of the CSP target of the query. This handle must have been created by using the CryptAcquireContext function.
		/// </param>
		/// <param name="dwParam">
		/// <para>The nature of the query. The following queries are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PP_ADMIN_PIN 31 (0x1F)</term>
		/// <term>Returns the administrator personal identification number (PIN) in the pbData parameter as a LPSTR.</term>
		/// </item>
		/// <item>
		/// <term>PP_APPLI_CERT 18 (0x12)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_CHANGE_PASSWORD 7 (0x7)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_CERTCHAIN 9 (0x9)</term>
		/// <term>Returns the certificate chain associated with the hProv handle. The returned certificate chain is X509_ASN_ENCODING encoded.</term>
		/// </item>
		/// <item>
		/// <term>PP_CONTAINER 6 (0x6)</term>
		/// <term>
		/// The name of the current key container as a null-terminated CHAR string. This string is exactly the same as the one passed in the
		/// pszContainer parameter of the CryptAcquireContext function to specify the key container to use. The pszContainer parameter can
		/// be read to determine the name of the default key container.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_CRYPT_COUNT_KEY_USE 41 (0x29)</term>
		/// <term>Not implemented by Microsoft CSPs. This behavior may be implemented by other CSPs. Windows XP: This parameter is not supported.</term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMALGS 1 (0x1)</term>
		/// <term>
		/// A PROV_ENUMALGS structure that contains information about one algorithm supported by the CSP being queried. The first time this
		/// value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first
		/// element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags
		/// parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. This
		/// function is not thread safe, and all of the available algorithms might not be enumerated if this function is used in a
		/// multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMALGS_EX 22 (0x16)</term>
		/// <term>
		/// A PROV_ENUMALGS_EX structure that contains information about one algorithm supported by the CSP being queried. The structure
		/// returned contains more information about the algorithm than the structure returned for PP_ENUMALGS. The first time this value is
		/// read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first element in
		/// the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags parameter. When
		/// this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. This function is not
		/// thread safe and all of the available algorithms might not be enumerated if this function is used in a multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMCONTAINERS 2 (0x2)</term>
		/// <term>
		/// The name of one of the key containers maintained by the CSP in the form of a null-terminated CHAR string. The first time this
		/// value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first
		/// element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags
		/// parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. To
		/// enumerate key containers associated with a computer, first call CryptAcquireContext using the CRYPT_MACHINE_KEYSET flag, and
		/// then use the handle returned from CryptAcquireContext as the hProv parameter in the call to CryptGetProvParam. This function is
		/// not thread safe and all of the available algorithms might not be enumerated if this function is used in a multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMELECTROOTS 26 (0x1A)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMEX_SIGNING_PROT 40 (0x28)</term>
		/// <term>
		/// Indicates that the current CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function succeeds, the
		/// CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function fails with an NTE_BAD_TYPE error code,
		/// the CSP does not support the dwProtocols member.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMMANDROOTS 25 (0x19)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_IMPTYPE 3 (0x3)</term>
		/// <term>A DWORD value that indicates how the CSP is implemented. For a table of possible values, see Remarks.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEY_TYPE_SUBTYPE 10 (0xA)</term>
		/// <term>This query is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYEXCHANGE_PIN 32 (0x20)</term>
		/// <term>Specifies that the key exchange PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSET_SEC_DESCR 8 (0x8)</term>
		/// <term>
		/// Retrieves the security descriptor for the key storage container. The pbData parameter is the address of a SECURITY_DESCRIPTOR
		/// structure that receives the security descriptor for the key storage container. The security descriptor is returned in
		/// self-relative format.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSET_TYPE 27 (0x1B)</term>
		/// <term>
		/// Determines whether the hProv parameter is a computer key set. The pbData parameter must be a DWORD; the DWORD will be set to the
		/// CRYPT_MACHINE_KEYSET flag if that flag was passed to the CryptAcquireContext function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSPEC 39 (0x27)</term>
		/// <term>
		/// Returns information about the key specifier values that the CSP supports. Key specifier values are joined in a logical OR and
		/// returned in the pbData parameter of the call as a DWORD. For example, the Microsoft Base Cryptographic Provider version 1.0
		/// returns a DWORD value of AT_SIGNATURE | AT_KEYEXCHANGE.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSTORAGE 17 (0x11)</term>
		/// <term>Returns a DWORD value of CRYPT_SEC_DESCR.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYX_KEYSIZE_INC 35 (0x23)</term>
		/// <term>
		/// The number of bits for the increment length of AT_KEYEXCHANGE. This information is used with information returned in the
		/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_KEYX_KEYSIZE_INC, the valid key lengths for
		/// AT_KEYEXCHANGE can be determined. These key lengths can then be used with CryptGenKey. For example if a CSP enumerates
		/// CALG_RSA_KEYX (AT_KEYEXCHANGE) with a minimum key length of 512 bits and a maximum of 1024 bits, and returns the increment
		/// length as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_NAME 4 (0x4)</term>
		/// <term>
		/// The name of the CSP in the form of a null-terminated CHAR string. This string is identical to the one passed in the pszProvider
		/// parameter of the CryptAcquireContext function to specify that the current CSP be used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_PROVTYPE 16 (0x10)</term>
		/// <term>A DWORD value that indicates the provider type of the CSP.</term>
		/// </item>
		/// <item>
		/// <term>PP_ROOT_CERTSTORE 46 (0x2E)</term>
		/// <term>
		/// Obtains the root certificate store for the smart card. This certificate store contains all of the root certificates that are
		/// stored on the smart card. The pbData parameter is the address of an HCERTSTORE variable that receives the handle of the
		/// certificate store. When this handle is no longer needed, the caller must close it by using the CertCloseStore function. Windows
		/// Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SESSION_KEYSIZE 20 (0x14)</term>
		/// <term>The size, in bits, of the session key.</term>
		/// </item>
		/// <item>
		/// <term>PP_SGC_INFO 37 (0x25)</term>
		/// <term>Used with server gated cryptography.</term>
		/// </item>
		/// <item>
		/// <term>PP_SIG_KEYSIZE_INC 34 (0x22)</term>
		/// <term>
		/// The number of bits for the increment length of AT_SIGNATURE. This information is used with information returned in the
		/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_SIG_KEYSIZE_INC, the valid key lengths for
		/// AT_SIGNATURE can be determined. These key lengths can then be used with CryptGenKey. For example, if a CSP enumerates
		/// CALG_RSA_SIGN (AT_SIGNATURE) with a minimum key length of 512 bits and a maximum of 1024 bits, and returns the increment length
		/// as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SIGNATURE_PIN 33 (0x21)</term>
		/// <term>Specifies that the key signature PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.</term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_GUID 45 (0x2D)</term>
		/// <term>
		/// Obtains the identifier of the smart card. The pbData parameter is the address of a GUID structure that receives the identifier
		/// of the smart card. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_READER 43 (0x2B)</term>
		/// <term>
		/// Obtains the name of the smart card reader. The pbData parameter is the address of an ANSI character array that receives a
		/// null-terminated ANSI string that contains the name of the smart card reader. The size of this buffer, contained in the variable
		/// pointed to by the pdwDataLen parameter, must include the NULL terminator. Windows Server 2003 and Windows XP: This parameter is
		/// not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SYM_KEYSIZE 19 (0x13)</term>
		/// <term>The size of the symmetric key.</term>
		/// </item>
		/// <item>
		/// <term>PP_UI_PROMPT 21 (0x15)</term>
		/// <term>This query is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_UNIQUE_CONTAINER 36 (0x24)</term>
		/// <term>
		/// The unique container name of the current key container in the form of a null-terminated CHAR string. For many CSPs, this name is
		/// the same name returned when the PP_CONTAINER value is used. The CryptAcquireContext function must work with this container name.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USE_HARDWARE_RNG 38 (0x26)</term>
		/// <term>
		/// Indicates whether a hardware random number generator (RNG) is supported. When PP_USE_HARDWARE_RNG is specified, the function
		/// succeeds and returns TRUE if a hardware RNG is supported. The function fails and returns FALSE if a hardware RNG is not
		/// supported. If a RNG is supported, PP_USE_HARDWARE_RNG can be set in CryptSetProvParam to indicate that the CSP must exclusively
		/// use the hardware RNG for this provider context. When PP_USE_HARDWARE_RNG is used, the pbData parameter must be NULL and dwFlags
		/// must be zero. None of the Microsoft CSPs currently support using a hardware RNG.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USER_CERTSTORE 42 (0x2A)</term>
		/// <term>
		/// Obtains the user certificate store for the smart card. This certificate store contains all of the user certificates that are
		/// stored on the smart card. The certificates in this store are encoded by using PKCS_7_ASN_ENCODING or X509_ASN_ENCODING encoding
		/// and should contain the CERT_KEY_PROV_INFO_PROP_ID property. The pbData parameter is the address of an HCERTSTORE variable that
		/// receives the handle of an in-memory certificate store. When this handle is no longer needed, the caller must close it by using
		/// the CertCloseStore function. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_VERSION 5 (0x5)</term>
		/// <term>
		/// The version number of the CSP. The least significant byte contains the minor version number and the next most significant byte
		/// the major version number. Version 2.0 is represented as 0x00000200. To maintain backward compatibility with earlier versions of
		/// the Microsoft Base Cryptographic Provider and the Microsoft Enhanced Cryptographic Provider, the provider names retain the
		/// "v1.0" designation in later versions.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// <para>
		/// A pointer to a buffer to receive the data. The form of this data varies depending on the value of dwParam. When dwParam is set
		/// to PP_USE_HARDWARE_RNG, pbData must be set to <c>NULL</c>.
		/// </para>
		/// <para>
		/// This parameter can be <c>NULL</c> to set the size of this information for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pdwDataLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that specifies the size, in bytes, of the buffer pointed to by the pbData parameter. When the
		/// function returns, the <c>DWORD</c> value contains the number of bytes stored or to be stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer. If PP_ENUMALGS, or PP_ENUMALGS_EX is
		/// set, the pdwDataLen parameter works somewhat differently. If pbData is <c>NULL</c> or the value pointed to by pdwDataLen is too
		/// small, the value returned in this parameter is the size of the largest item in the enumeration list instead of the size of the
		/// item currently being read. If PP_ENUMCONTAINERS is set, the first call to the function returns the size of the maximum
		/// key-container allowed by the current provider. This is in contrast to other possible behaviors, like returning the length of the
		/// longest existing container, or the length of the current container. Subsequent enumerating calls will not change the dwLen
		/// parameter. For each enumerated container, the caller can determine the length of the <c>null</c>-terminated string
		/// programmatically, if desired. If one of the enumeration values is read and the pbData parameter is <c>NULL</c>, the CRYPT_FIRST
		/// flag must be specified for the size information to be correctly retrieved.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// If dwParam is <c>PP_KEYSET_SEC_DESCR</c>, the security descriptor on the key container where the keys are stored is retrieved.
		/// For this case, dwFlags is used to pass in the <c>SECURITY_INFORMATION</c> bit flags that indicate the requested security
		/// information, as defined in the Platform SDK. <c>SECURITY_INFORMATION</c> bit flags can be combined with a bitwise- <c>OR</c> operation.
		/// </para>
		/// <para>The following values are defined for use with <c>PP_KEYSET_SEC_DESCR</c>.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>OWNER_SECURITY_INFORMATION</term>
		/// <term>Owner identifier of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>GROUP_SECURITY_INFORMATION</term>
		/// <term>Primary group identifier of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>DACL_SECURITY_INFORMATION</term>
		/// <term>Discretionary ACL of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>SACL_SECURITY_INFORMATION</term>
		/// <term>System ACL of the object is being referenced.</term>
		/// </item>
		/// </list>
		/// <para>The following values are defined for use with <c>PP_ENUMALGS</c>, <c>PP_ENUMALGS_EX</c>, and <c>PP_ENUMCONTAINERS</c>.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_FIRST 1 (0x1)</term>
		/// <term>Retrieve the first element in the enumeration. This has the same effect as resetting the enumerator.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NEXT 2 (0x2)</term>
		/// <term>
		/// Retrieve the next element in the enumeration. When there are no more elements to retrieve, this function will fail and set the
		/// last error to ERROR_NO_MORE_ITEMS.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SGC_ENUM 4 (0x4)</term>
		/// <term>
		/// Retrieve server-gated cryptography (SGC) enabled certificates. SGC enabled certificates are no longer supported. For more
		/// information, see Microsoft Support Article 875450.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SGC</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_FASTSGC</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by NTE are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the
		/// ERROR_MORE_DATA code and stores the required buffer size, in bytes, in the variable pointed to by pdwDataLen.
		/// </term>
		/// </item>
		/// <item>
		/// <term>ERROR_NO_MORE_ITEMS</term>
		/// <term>
		/// The end of the enumeration list has been reached. No valid data has been placed in the pbData buffer. This error code is
		/// returned only when dwParam equals PP_ENUMALGS or PP_ENUMCONTAINERS.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter specifies a flag that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown value number.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context specified by hProv is not valid.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>This function must not be used on a thread of a multithreaded program.</para>
		/// <para>The following values are returned in pbData if dwParam is PP_IMPTYPE.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_IMPL_HARDWARE1</term>
		/// <term>Implementation is in hardware.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IMPL_SOFTWARE2</term>
		/// <term>Implementation is in software.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IMPL_MIXED3</term>
		/// <term>Implementation involves both hardware and software.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IMPL_UNKNOWN4</term>
		/// <term>Implementation type is unknown.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IMPL_REMOVABLE8</term>
		/// <term>Implementation is in removable media.</term>
		/// </item>
		/// </list>
		/// <para>
		/// The dwFlags parameter is used to pass in the <c>SECURITY_INFORMATION</c> bit flags that indicate the requested security
		/// information. The pointer to the security descriptor is returned in the pbData parameter and the length of the security
		/// descriptor is returned in the pdwDataLen parameter. Key-container security is handled with SetFileSecurity and GetFileSecurity.
		/// </para>
		/// <para>
		/// The class of an algorithm enumerated with dwParam set to PP_ENUMALGS or PP_ENUMALGS_EX can be determined. This might be done to
		/// display a list of encryption algorithms supported and to disregard the rest. The <c>GET_ALG_CLASS(</c> x <c>)</c> macro takes an
		/// algorithm identifier as an argument and returns a code indicating the general class of that algorithm. Possible return values include:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>ALG_CLASS_DATA_ENCRYPT</term>
		/// </item>
		/// <item>
		/// <term>ALG_CLASS_HASH</term>
		/// </item>
		/// <item>
		/// <term>ALG_CLASS_KEY_EXCHANGE</term>
		/// </item>
		/// <item>
		/// <term>ALG_CLASS_SIGNATURE</term>
		/// </item>
		/// </list>
		/// <para>
		/// The following table lists the algorithms supported by the Microsoft Base Cryptographic Provider along with the class of each algorithm.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Name</term>
		/// <term>Identifier</term>
		/// <term>Class</term>
		/// </listheader>
		/// <item>
		/// <term>"MD2"</term>
		/// <term>CALG_MD2</term>
		/// <term>ALG_CLASS_HASH</term>
		/// </item>
		/// <item>
		/// <term>"MD5"</term>
		/// <term>CALG_MD5</term>
		/// <term>ALG_CLASS_HASH</term>
		/// </item>
		/// <item>
		/// <term>"SHA"</term>
		/// <term>CALG_SHA</term>
		/// <term>ALG_CLASS_HASH</term>
		/// </item>
		/// <item>
		/// <term>"MAC"</term>
		/// <term>CALG_MAC</term>
		/// <term>ALG_CLASS_HASH</term>
		/// </item>
		/// <item>
		/// <term>"RSA_SIGN"</term>
		/// <term>CALG_RSA_SIGN</term>
		/// <term>ALG_CLASS_SIGNATURE</term>
		/// </item>
		/// <item>
		/// <term>"RSA_KEYX"</term>
		/// <term>CALG_RSA_KEYX</term>
		/// <term>ALG_CLASS_KEY_EXCHANGE</term>
		/// </item>
		/// <item>
		/// <term>"RC2"</term>
		/// <term>CALG_RC2</term>
		/// <term>ALG_CLASS_DATA_ENCRYPT</term>
		/// </item>
		/// <item>
		/// <term>"RC4"</term>
		/// <term>CALG_RC4</term>
		/// <term>ALG_CLASS_DATA_ENCRYPT</term>
		/// </item>
		/// </list>
		/// <para>
		/// Applications must not use an algorithm with an algorithm identifier that is not recognized. Using an unknown cryptographic
		/// algorithm can produce unpredictable results.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows finding the name of the CSP associated with a cryptographic service provider handle and the name of
		/// the key container associated with the handle. For the complete context for this example, see Example C Program: Using CryptAcquireContext.
		/// </para>
		/// <para>For another example that uses this function, see Example C Program: Enumerating CSP Providers and Provider Types.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgetprovparam BOOL CryptGetProvParam( HCRYPTPROV
		// hProv, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "c0b7c1c8-aa42-4d40-a7f7-99c0821c8977")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGetProvParam(HCRYPTPROV hProv, ProvParam dwParam, [Out, Optional] IntPtr pbData, ref uint pdwDataLen, uint dwFlags);

		/// <summary>
		/// The CryptGetProvParam function retrieves parameters that govern the operations of a cryptographic service provider (CSP).
		/// </summary>
		/// <typeparam name="T">The expected return type.</typeparam>
		/// <param name="hProv">
		/// A handle of the CSP target of the query. This handle must have been created by using the CryptAcquireContext function.
		/// </param>
		/// <param name="dwParam">
		/// <para>The nature of the query. The following queries are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PP_ADMIN_PIN 31 (0x1F)</term>
		/// <term>Returns the administrator personal identification number (PIN) in the pbData parameter as a LPSTR.</term>
		/// </item>
		/// <item>
		/// <term>PP_APPLI_CERT 18 (0x12)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_CHANGE_PASSWORD 7 (0x7)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_CERTCHAIN 9 (0x9)</term>
		/// <term>Returns the certificate chain associated with the hProv handle. The returned certificate chain is X509_ASN_ENCODING encoded.</term>
		/// </item>
		/// <item>
		/// <term>PP_CONTAINER 6 (0x6)</term>
		/// <term>
		/// The name of the current key container as a null-terminated CHAR string. This string is exactly the same as the one passed in the
		/// pszContainer parameter of the CryptAcquireContext function to specify the key container to use. The pszContainer parameter can
		/// be read to determine the name of the default key container.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_CRYPT_COUNT_KEY_USE 41 (0x29)</term>
		/// <term>Not implemented by Microsoft CSPs. This behavior may be implemented by other CSPs. Windows XP: This parameter is not supported.</term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMALGS 1 (0x1)</term>
		/// <term>
		/// A PROV_ENUMALGS structure that contains information about one algorithm supported by the CSP being queried. The first time this
		/// value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first
		/// element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags
		/// parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. This
		/// function is not thread safe, and all of the available algorithms might not be enumerated if this function is used in a
		/// multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMALGS_EX 22 (0x16)</term>
		/// <term>
		/// A PROV_ENUMALGS_EX structure that contains information about one algorithm supported by the CSP being queried. The structure
		/// returned contains more information about the algorithm than the structure returned for PP_ENUMALGS. The first time this value is
		/// read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first element in
		/// the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags parameter. When
		/// this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. This function is not
		/// thread safe and all of the available algorithms might not be enumerated if this function is used in a multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMCONTAINERS 2 (0x2)</term>
		/// <term>
		/// The name of one of the key containers maintained by the CSP in the form of a null-terminated CHAR string. The first time this
		/// value is read, the dwFlags parameter must contain the CRYPT_FIRST flag. Doing so causes this function to retrieve the first
		/// element in the enumeration. The subsequent elements can then be retrieved by setting the CRYPT_NEXT flag in the dwFlags
		/// parameter. When this function fails with the ERROR_NO_MORE_ITEMS error code, the end of the enumeration has been reached. To
		/// enumerate key containers associated with a computer, first call CryptAcquireContext using the CRYPT_MACHINE_KEYSET flag, and
		/// then use the handle returned from CryptAcquireContext as the hProv parameter in the call to CryptGetProvParam. This function is
		/// not thread safe and all of the available algorithms might not be enumerated if this function is used in a multithreaded context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMELECTROOTS 26 (0x1A)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMEX_SIGNING_PROT 40 (0x28)</term>
		/// <term>
		/// Indicates that the current CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function succeeds, the
		/// CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. If this function fails with an NTE_BAD_TYPE error code,
		/// the CSP does not support the dwProtocols member.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ENUMMANDROOTS 25 (0x19)</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_IMPTYPE 3 (0x3)</term>
		/// <term>A DWORD value that indicates how the CSP is implemented. For a table of possible values, see Remarks.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEY_TYPE_SUBTYPE 10 (0xA)</term>
		/// <term>This query is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYEXCHANGE_PIN 32 (0x20)</term>
		/// <term>Specifies that the key exchange PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSET_SEC_DESCR 8 (0x8)</term>
		/// <term>
		/// Retrieves the security descriptor for the key storage container. The pbData parameter is the address of a SECURITY_DESCRIPTOR
		/// structure that receives the security descriptor for the key storage container. The security descriptor is returned in
		/// self-relative format.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSET_TYPE 27 (0x1B)</term>
		/// <term>
		/// Determines whether the hProv parameter is a computer key set. The pbData parameter must be a DWORD; the DWORD will be set to the
		/// CRYPT_MACHINE_KEYSET flag if that flag was passed to the CryptAcquireContext function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSPEC 39 (0x27)</term>
		/// <term>
		/// Returns information about the key specifier values that the CSP supports. Key specifier values are joined in a logical OR and
		/// returned in the pbData parameter of the call as a DWORD. For example, the Microsoft Base Cryptographic Provider version 1.0
		/// returns a DWORD value of AT_SIGNATURE | AT_KEYEXCHANGE.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSTORAGE 17 (0x11)</term>
		/// <term>Returns a DWORD value of CRYPT_SEC_DESCR.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYX_KEYSIZE_INC 35 (0x23)</term>
		/// <term>
		/// The number of bits for the increment length of AT_KEYEXCHANGE. This information is used with information returned in the
		/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_KEYX_KEYSIZE_INC, the valid key lengths for
		/// AT_KEYEXCHANGE can be determined. These key lengths can then be used with CryptGenKey. For example if a CSP enumerates
		/// CALG_RSA_KEYX (AT_KEYEXCHANGE) with a minimum key length of 512 bits and a maximum of 1024 bits, and returns the increment
		/// length as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_NAME 4 (0x4)</term>
		/// <term>
		/// The name of the CSP in the form of a null-terminated CHAR string. This string is identical to the one passed in the pszProvider
		/// parameter of the CryptAcquireContext function to specify that the current CSP be used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_PROVTYPE 16 (0x10)</term>
		/// <term>A DWORD value that indicates the provider type of the CSP.</term>
		/// </item>
		/// <item>
		/// <term>PP_ROOT_CERTSTORE 46 (0x2E)</term>
		/// <term>
		/// Obtains the root certificate store for the smart card. This certificate store contains all of the root certificates that are
		/// stored on the smart card. The pbData parameter is the address of an HCERTSTORE variable that receives the handle of the
		/// certificate store. When this handle is no longer needed, the caller must close it by using the CertCloseStore function. Windows
		/// Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SESSION_KEYSIZE 20 (0x14)</term>
		/// <term>The size, in bits, of the session key.</term>
		/// </item>
		/// <item>
		/// <term>PP_SGC_INFO 37 (0x25)</term>
		/// <term>Used with server gated cryptography.</term>
		/// </item>
		/// <item>
		/// <term>PP_SIG_KEYSIZE_INC 34 (0x22)</term>
		/// <term>
		/// The number of bits for the increment length of AT_SIGNATURE. This information is used with information returned in the
		/// PP_ENUMALGS_EX value. With the information returned when using PP_ENUMALGS_EX and PP_SIG_KEYSIZE_INC, the valid key lengths for
		/// AT_SIGNATURE can be determined. These key lengths can then be used with CryptGenKey. For example, if a CSP enumerates
		/// CALG_RSA_SIGN (AT_SIGNATURE) with a minimum key length of 512 bits and a maximum of 1024 bits, and returns the increment length
		/// as 64 bits, then valid key lengths are 512, 576, 640,… 1024.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SIGNATURE_PIN 33 (0x21)</term>
		/// <term>Specifies that the key signature PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.</term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_GUID 45 (0x2D)</term>
		/// <term>
		/// Obtains the identifier of the smart card. The pbData parameter is the address of a GUID structure that receives the identifier
		/// of the smart card. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_READER 43 (0x2B)</term>
		/// <term>
		/// Obtains the name of the smart card reader. The pbData parameter is the address of an ANSI character array that receives a
		/// null-terminated ANSI string that contains the name of the smart card reader. The size of this buffer, contained in the variable
		/// pointed to by the pdwDataLen parameter, must include the NULL terminator. Windows Server 2003 and Windows XP: This parameter is
		/// not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SYM_KEYSIZE 19 (0x13)</term>
		/// <term>The size of the symmetric key.</term>
		/// </item>
		/// <item>
		/// <term>PP_UI_PROMPT 21 (0x15)</term>
		/// <term>This query is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_UNIQUE_CONTAINER 36 (0x24)</term>
		/// <term>
		/// The unique container name of the current key container in the form of a null-terminated CHAR string. For many CSPs, this name is
		/// the same name returned when the PP_CONTAINER value is used. The CryptAcquireContext function must work with this container name.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USE_HARDWARE_RNG 38 (0x26)</term>
		/// <term>
		/// Indicates whether a hardware random number generator (RNG) is supported. When PP_USE_HARDWARE_RNG is specified, the function
		/// succeeds and returns TRUE if a hardware RNG is supported. The function fails and returns FALSE if a hardware RNG is not
		/// supported. If a RNG is supported, PP_USE_HARDWARE_RNG can be set in CryptSetProvParam to indicate that the CSP must exclusively
		/// use the hardware RNG for this provider context. When PP_USE_HARDWARE_RNG is used, the pbData parameter must be NULL and dwFlags
		/// must be zero. None of the Microsoft CSPs currently support using a hardware RNG.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USER_CERTSTORE 42 (0x2A)</term>
		/// <term>
		/// Obtains the user certificate store for the smart card. This certificate store contains all of the user certificates that are
		/// stored on the smart card. The certificates in this store are encoded by using PKCS_7_ASN_ENCODING or X509_ASN_ENCODING encoding
		/// and should contain the CERT_KEY_PROV_INFO_PROP_ID property. The pbData parameter is the address of an HCERTSTORE variable that
		/// receives the handle of an in-memory certificate store. When this handle is no longer needed, the caller must close it by using
		/// the CertCloseStore function. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_VERSION 5 (0x5)</term>
		/// <term>
		/// The version number of the CSP. The least significant byte contains the minor version number and the next most significant byte
		/// the major version number. Version 2.0 is represented as 0x00000200. To maintain backward compatibility with earlier versions of
		/// the Microsoft Base Cryptographic Provider and the Microsoft Enhanced Cryptographic Provider, the provider names retain the
		/// "v1.0" designation in later versions.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// If dwParam is <c>PP_KEYSET_SEC_DESCR</c>, the security descriptor on the key container where the keys are stored is retrieved.
		/// For this case, dwFlags is used to pass in the <c>SECURITY_INFORMATION</c> bit flags that indicate the requested security
		/// information, as defined in the Platform SDK. <c>SECURITY_INFORMATION</c> bit flags can be combined with a bitwise- <c>OR</c> operation.
		/// </para>
		/// <para>The following values are defined for use with <c>PP_KEYSET_SEC_DESCR</c>.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>OWNER_SECURITY_INFORMATION</term>
		/// <term>Owner identifier of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>GROUP_SECURITY_INFORMATION</term>
		/// <term>Primary group identifier of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>DACL_SECURITY_INFORMATION</term>
		/// <term>Discretionary ACL of the object is being referenced.</term>
		/// </item>
		/// <item>
		/// <term>SACL_SECURITY_INFORMATION</term>
		/// <term>System ACL of the object is being referenced.</term>
		/// </item>
		/// </list>
		/// <para>The following values are defined for use with <c>PP_ENUMALGS</c>, <c>PP_ENUMALGS_EX</c>, and <c>PP_ENUMCONTAINERS</c>.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_FIRST 1 (0x1)</term>
		/// <term>Retrieve the first element in the enumeration. This has the same effect as resetting the enumerator.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NEXT 2 (0x2)</term>
		/// <term>
		/// Retrieve the next element in the enumeration. When there are no more elements to retrieve, this function will fail and set the
		/// last error to ERROR_NO_MORE_ITEMS.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SGC_ENUM 4 (0x4)</term>
		/// <term>
		/// Retrieve server-gated cryptography (SGC) enabled certificates. SGC enabled certificates are no longer supported. For more
		/// information, see Microsoft Support Article 875450.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_SGC</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_FASTSGC</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>The specified value data. The form of this data varies, depending on the value number.</returns>
		public static T CryptGetProvParam<T>(HCRYPTPROV hProv, ProvParam dwParam, uint dwFlags) => CryptGetValue<HCRYPTPROV, ProvParam, T>(CryptGetProvParam, hProv, dwParam, dwFlags);

		/// <summary>
		/// The CryptGetUserKey function retrieves a handle of one of a user's two public/private key pairs. This function is used only by
		/// the owner of the public/private key pairs and only when the handle of a cryptographic service provider (CSP) and its associated
		/// key container is available. If the CSP handle is not available and the user's certificate is, use CryptAcquireCertificatePrivateKey.
		/// </summary>
		/// <param name="hProv"><c>HCRYPTPROV</c> handle of a cryptographic service provider (CSP) created by a call to CryptAcquireContext.</param>
		/// <param name="dwKeySpec">
		/// <para>Identifies the private key to use from the key container. It can be AT_KEYEXCHANGE or AT_SIGNATURE.</para>
		/// <para>
		/// Additionally, some providers allow access to other user-specific keys through this function. For details, see the documentation
		/// on the specific provider.
		/// </para>
		/// </param>
		/// <param name="phUserKey">
		/// A pointer to the HCRYPTKEY handle of the retrieved keys. When you have finished using the key, delete the handle by calling the
		/// CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The dwKeySpec parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_KEY</term>
		/// <term>The key requested by the dwKeySpec parameter does not exist.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgetuserkey
		// BOOL CryptGetUserKey( HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "d9166b98-e5f1-4e5c-b6f1-2a086b102e0f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptGetUserKey(HCRYPTPROV hProv, CertKeySpec dwKeySpec, out SafeHCRYPTKEY phUserKey);

		/// <summary>
		/// The CryptHashData function adds data to a specified hash object. This function and CryptHashSessionKey can be called multiple
		/// times to compute the hash of long or discontinuous data streams.
		/// <para>Before calling this function, CryptCreateHash must be called to create a handle of a hash object.</para>
		/// </summary>
		/// <param name="hHash">Handle of the hash object.</param>
		/// <param name="pbData">A pointer to a buffer that contains the data to be added to the hash object.</param>
		/// <param name="dwDataLen">Number of bytes of data to be added. This must be zero if the CRYPT_USERDATA flag is set.</param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_OWF_REPL_LM_HASH 0x00000001</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_USERDATA 1 (0x1)</term>
		/// <term>
		/// All Microsoft Cryptographic Providers ignore this parameter. For any CSP that does not ignore this parameter, if this flag is
		/// set, the CSP prompts the user to input data directly. This data is added to the hash. The application is not allowed access to
		/// the data. This flag can be used to allow the user to enter a PIN into the system.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is <c>TRUE</c>.</para>
		/// <para>If the function fails, the return value is <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hHash handle specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH_STATE</term>
		/// <term>An attempt was made to add data to a hash object that is already marked "finished."</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>
		/// A keyed hash algorithm is being used, but the session key is no longer valid. This error is generated if the session key is
		/// destroyed before the hashing operation is complete.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_LEN</term>
		/// <term>The CSP does not ignore the CRYPT_USERDATA flag, the flag is set, and the dwDataLen parameter has a nonzero value.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hash object was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-crypthashdata BOOL CryptHashData( HCRYPTHASH hHash, const
		// BYTE *pbData, DWORD dwDataLen, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "ec1482a2-c2cb-4c5f-af9c-d493134413d6")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptHashData(HCRYPTHASH hHash, [In] IntPtr pbData, uint dwDataLen, uint dwFlags);

		/// <summary>
		/// The CryptHashSessionKey function computes the cryptographic hash of a session key object. This function can be called multiple
		/// times with the same hash handle to compute the hash of multiple keys. Calls to CryptHashSessionKey can be interspersed with
		/// calls to CryptHashData.
		/// <para>Before calling this function, CryptCreateHash must be called to create the handle of a hash object.</para>
		/// </summary>
		/// <param name="hHash">A handle to the hash object.</param>
		/// <param name="hKey">A handle to the key object to be hashed.</param>
		/// <param name="dwFlags">
		/// <para>The following flag value is defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_LITTLE_ENDIAN 0x00000001</term>
		/// <term>
		/// When this flag is set, the bytes of the key are hashed in little-endian form. Note that by default (when dwFlags is zero), the
		/// bytes of the key are hashed in big-endian form.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is <c>TRUE</c>.</para>
		/// <para>If the function fails, the return value is <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hHash handle specifies an algorithm that this CSP does not support.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH_STATE</term>
		/// <term>An attempt was made to add data to a hash object that is already marked "finished."</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>
		/// A keyed hash algorithm is being used, but the session key is no longer valid. This error is generated if the session key is
		/// destroyed before the hashing operation is complete.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hash object was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-crypthashsessionkey BOOL CryptHashSessionKey( HCRYPTHASH
		// hHash, HCRYPTKEY hKey, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "75781993-7faf-4149-80cc-ae50dbd4de2a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptHashSessionKey(HCRYPTHASH hHash, HCRYPTKEY hKey, CryptHashSessionKeyFlags dwFlags);

		/// <summary>
		/// The CryptImportKey function transfers a cryptographic key from a key BLOB into a cryptographic service provider (CSP). This
		/// function can be used to import an Schannel session key, regular session key, public key, or public/private key pair. For all but
		/// the public key, the key or key pair is encrypted.
		/// </summary>
		/// <param name="hProv">The handle of a CSP obtained with the CryptAcquireContext function.</param>
		/// <param name="pbData">
		/// A <c>BYTE</c> array that contains a PUBLICKEYSTRUC BLOB header followed by the encrypted key. This key BLOB is created by the
		/// CryptExportKey function, either in this application or by another application possibly running on a different computer.
		/// </param>
		/// <param name="dwDataLen">Contains the length, in bytes, of the key BLOB.</param>
		/// <param name="hPubKey">
		/// <para>
		/// A handle to the cryptographic key that decrypts the key stored in pbData. This key must come from the same CSP to which hProv
		/// refers. The meaning of this parameter differs depending on the CSP type and the type of key BLOB being imported:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with the key exchange key pair, for example, a <c>SIMPLEBLOB</c>, this parameter can be the handle
		/// to the key exchange key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with a session key, for example, an encrypted <c>PRIVATEKEYBLOB</c>, this parameter contains the
		/// handle of this session key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the key BLOB is not encrypted, for example, a <c>PUBLICKEYBLOB</c>, this parameter is not used and must be zero.</term>
		/// </item>
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with a session key in an Schannel CSP, for example, an encrypted <c>OPAQUEKEYBLOB</c> or any other
		/// vendor-specific <c>OPAQUEKEYBLOB</c>, this parameter is not used and must be set to zero.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Some CSPs may modify this parameter as a result of the operation. Applications that subsequently use this key for
		/// other purposes should call the CryptDuplicateKey function to create a duplicate key handle. When the application has finished
		/// using the handle, release it by calling the CryptDestroyKey function.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// Currently used only when a public/private key pair in the form of a <c>PRIVATEKEYBLOB</c> is imported into the CSP.
		/// <para>This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_EXPORTABLE</term>
		/// <term>
		/// The key being imported is eventually to be reexported. If this flag is not used, then calls to CryptExportKey with the key
		/// handle fail.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_OAEP</term>
		/// <term>This flag causes PKCS #1 version 2 formatting to be checked with RSA encryption and decryption when importing SIMPLEBLOBs.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NO_SALT</term>
		/// <term>A no-salt value gets allocated for a 40-bit symmetric key. For more information, see Salt Value Functionality.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_USER_PROTECTED</term>
		/// <term>
		/// If this flag is set, the CSP notifies the user through a dialog box or some other method when certain actions are attempted
		/// using this key. The precise behavior is specified by the CSP or the CSP type used. If the provider context was acquired with
		/// CRYPT_SILENT set, using this flag causes a failure and the last error is set to NTE_SILENT_CONTEXT.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IPSEC_HMAC_KEY</term>
		/// <term>
		/// Allows for the import of an RC2 key that is larger than 16 bytes. If this flag is not set, calls to the CryptImportKey function
		/// with RC2 keys that are greater than 16 bytes fail, and a call to GetLastError will return NTE_BAD_DATA.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="phKey">
		/// A pointer to a <c>HCRYPTKEY</c> value that receives the handle of the imported key. When you have finished using the key,
		/// release the handle by calling the CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero.</para>
		/// <para>If the function fails, it returns zero. For extended error information, call GetLastError.</para>
		/// <para>Error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>Some CSPs set this error if a private key is imported into a container while another thread or process is using this key.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The simple key BLOB to be imported is not encrypted with the expected key exchange algorithm.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// Either the algorithm that works with the public key to be imported is not supported by this CSP, or an attempt was made to
		/// import a session key that was encrypted with something other than one of your public keys.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter specified is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The key BLOB type is not supported by this CSP and is possibly not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_VER</term>
		/// <term>The version number of the key BLOB does not match the CSP version. This usually indicates that the CSP needs to be upgraded.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When importing a Hash-Based Message Authentication Code (HMAC) key, the caller must identify the imported key as a
		/// <c>PLAINTEXTKEYBLOB</c> type and set the appropriate algorithm identifier in the <c>aiKeyAlg</c> field of the PUBLICKEYSTRUC
		/// BLOB header.
		/// </para>
		/// <para>
		/// The <c>CryptImportKey</c> function can be used to import a plaintext key for symmetric algorithms; however, we recommend that,
		/// for ease of use, you use the CryptGenKey function instead. When you import a plaintext key, the structure of the key BLOB that
		/// is passed in the pbData parameter is a PLAINTEXTKEYBLOB.
		/// </para>
		/// <para>You can use the <c>PLAINTEXTKEYBLOB</c> type with any algorithm or type of key combination supported by the CSP in use.</para>
		/// <para>For an example of importing a plaintext key, see Example C Program: Importing a Plaintext Key.</para>
		/// <para>The following example shows how you can set the header fields.</para>
		/// <para>The length of the key is specified in keyBlob.keyLength, which is followed by the actual key data.</para>
		/// <para>
		/// <c>Note</c> The HMAC algorithms do not have their own algorithm identifiers; use CALG_RC2 instead. <c>CRYPT_IPSEC_HMAC_KEY</c>
		/// allows the import of RC2 keys longer than 16 bytes.
		/// </para>
		/// <para>
		/// For any of the Data Encryption Standard (DES) key permutations that use <c>PLAINTEXTKEYBLOB</c>, only the full key size,
		/// including parity bit, can be imported.
		/// </para>
		/// <para>The following key sizes are supported.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Algorithm</term>
		/// <term>Supported key size</term>
		/// </listheader>
		/// <item>
		/// <term>CALG_DES</term>
		/// <term>64 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES_112</term>
		/// <term>128 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES</term>
		/// <term>192 bits</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows how to import a key from a key BLOB. For a full example for this function, see Example C Program:
		/// Signing a Hash and Verifying the Hash Signature. For additional code that uses this function, see Example C Program: Decrypting
		/// a File.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptimportkey BOOL CryptImportKey( HCRYPTPROV hProv,
		// const BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "f48b6ec9-e03b-43b0-9f22-120ae93d934c")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptImportKey(HCRYPTPROV hProv, [In] IntPtr pbData, uint dwDataLen, HCRYPTKEY hPubKey, uint dwFlags, out SafeHCRYPTKEY phKey);

		/// <summary>
		/// The CryptImportKey function transfers a cryptographic key from a key BLOB into a cryptographic service provider (CSP). This
		/// function can be used to import an Schannel session key, regular session key, public key, or public/private key pair. For all but
		/// the public key, the key or key pair is encrypted.
		/// </summary>
		/// <param name="hProv">The handle of a CSP obtained with the CryptAcquireContext function.</param>
		/// <param name="pbData">
		/// A <c>BYTE</c> array that contains a PUBLICKEYSTRUC BLOB header followed by the encrypted key. This key BLOB is created by the
		/// CryptExportKey function, either in this application or by another application possibly running on a different computer.
		/// </param>
		/// <param name="dwDataLen">Contains the length, in bytes, of the key BLOB.</param>
		/// <param name="hPubKey">
		/// <para>
		/// A handle to the cryptographic key that decrypts the key stored in pbData. This key must come from the same CSP to which hProv
		/// refers. The meaning of this parameter differs depending on the CSP type and the type of key BLOB being imported:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with the key exchange key pair, for example, a <c>SIMPLEBLOB</c>, this parameter can be the handle
		/// to the key exchange key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with a session key, for example, an encrypted <c>PRIVATEKEYBLOB</c>, this parameter contains the
		/// handle of this session key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the key BLOB is not encrypted, for example, a <c>PUBLICKEYBLOB</c>, this parameter is not used and must be zero.</term>
		/// </item>
		/// <item>
		/// <term>
		/// If the key BLOB is encrypted with a session key in an Schannel CSP, for example, an encrypted <c>OPAQUEKEYBLOB</c> or any other
		/// vendor-specific <c>OPAQUEKEYBLOB</c>, this parameter is not used and must be set to zero.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// <c>Note</c> Some CSPs may modify this parameter as a result of the operation. Applications that subsequently use this key for
		/// other purposes should call the CryptDuplicateKey function to create a duplicate key handle. When the application has finished
		/// using the handle, release it by calling the CryptDestroyKey function.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// Currently used only when a public/private key pair in the form of a <c>PRIVATEKEYBLOB</c> is imported into the CSP.
		/// <para>This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_EXPORTABLE</term>
		/// <term>
		/// The key being imported is eventually to be reexported. If this flag is not used, then calls to CryptExportKey with the key
		/// handle fail.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_OAEP</term>
		/// <term>This flag causes PKCS #1 version 2 formatting to be checked with RSA encryption and decryption when importing SIMPLEBLOBs.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_NO_SALT</term>
		/// <term>A no-salt value gets allocated for a 40-bit symmetric key. For more information, see Salt Value Functionality.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_USER_PROTECTED</term>
		/// <term>
		/// If this flag is set, the CSP notifies the user through a dialog box or some other method when certain actions are attempted
		/// using this key. The precise behavior is specified by the CSP or the CSP type used. If the provider context was acquired with
		/// CRYPT_SILENT set, using this flag causes a failure and the last error is set to NTE_SILENT_CONTEXT.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_IPSEC_HMAC_KEY</term>
		/// <term>
		/// Allows for the import of an RC2 key that is larger than 16 bytes. If this flag is not set, calls to the CryptImportKey function
		/// with RC2 keys that are greater than 16 bytes fail, and a call to GetLastError will return NTE_BAD_DATA.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="phKey">
		/// A pointer to a <c>HCRYPTKEY</c> value that receives the handle of the imported key. When you have finished using the key,
		/// release the handle by calling the CryptDestroyKey function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero.</para>
		/// <para>If the function fails, it returns zero. For extended error information, call GetLastError.</para>
		/// <para>Error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>Some CSPs set this error if a private key is imported into a container while another thread or process is using this key.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The simple key BLOB to be imported is not encrypted with the expected key exchange algorithm.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_DATA</term>
		/// <term>
		/// Either the algorithm that works with the public key to be imported is not supported by this CSP, or an attempt was made to
		/// import a session key that was encrypted with something other than one of your public keys.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter specified is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The key BLOB type is not supported by this CSP and is possibly not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_VER</term>
		/// <term>The version number of the key BLOB does not match the CSP version. This usually indicates that the CSP needs to be upgraded.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When importing a Hash-Based Message Authentication Code (HMAC) key, the caller must identify the imported key as a
		/// <c>PLAINTEXTKEYBLOB</c> type and set the appropriate algorithm identifier in the <c>aiKeyAlg</c> field of the PUBLICKEYSTRUC
		/// BLOB header.
		/// </para>
		/// <para>
		/// The <c>CryptImportKey</c> function can be used to import a plaintext key for symmetric algorithms; however, we recommend that,
		/// for ease of use, you use the CryptGenKey function instead. When you import a plaintext key, the structure of the key BLOB that
		/// is passed in the pbData parameter is a PLAINTEXTKEYBLOB.
		/// </para>
		/// <para>You can use the <c>PLAINTEXTKEYBLOB</c> type with any algorithm or type of key combination supported by the CSP in use.</para>
		/// <para>For an example of importing a plaintext key, see Example C Program: Importing a Plaintext Key.</para>
		/// <para>The following example shows how you can set the header fields.</para>
		/// <para>The length of the key is specified in keyBlob.keyLength, which is followed by the actual key data.</para>
		/// <para>
		/// <c>Note</c> The HMAC algorithms do not have their own algorithm identifiers; use CALG_RC2 instead. <c>CRYPT_IPSEC_HMAC_KEY</c>
		/// allows the import of RC2 keys longer than 16 bytes.
		/// </para>
		/// <para>
		/// For any of the Data Encryption Standard (DES) key permutations that use <c>PLAINTEXTKEYBLOB</c>, only the full key size,
		/// including parity bit, can be imported.
		/// </para>
		/// <para>The following key sizes are supported.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Algorithm</term>
		/// <term>Supported key size</term>
		/// </listheader>
		/// <item>
		/// <term>CALG_DES</term>
		/// <term>64 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES_112</term>
		/// <term>128 bits</term>
		/// </item>
		/// <item>
		/// <term>CALG_3DES</term>
		/// <term>192 bits</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows how to import a key from a key BLOB. For a full example for this function, see Example C Program:
		/// Signing a Hash and Verifying the Hash Signature. For additional code that uses this function, see Example C Program: Decrypting
		/// a File.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptimportkey BOOL CryptImportKey( HCRYPTPROV hProv,
		// const BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "f48b6ec9-e03b-43b0-9f22-120ae93d934c")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptImportKey(HCRYPTPROV hProv, [In] byte[] pbData, int dwDataLen, HCRYPTKEY hPubKey, uint dwFlags, out SafeHCRYPTKEY phKey);

		/// <summary>
		/// <para>
		/// The CryptReleaseContext function releases the handle of a cryptographic service provider (CSP) and a key container. At each call
		/// to this function, the reference count on the CSP is reduced by one. When the reference count reaches zero, the context is fully
		/// released and it can no longer be used by any function in the application.
		/// </para>
		/// <para>
		/// An application calls this function after finishing the use of the CSP. After this function is called, the released CSP handle is
		/// no longer valid. This function does not destroy key containers or key pairs.
		/// </para>
		/// </summary>
		/// <param name="hProv">Handle of a cryptographic service provider (CSP) created by a call to CryptAcquireContext.</param>
		/// <param name="dwFlags">
		/// Reserved for future use and must be zero. If dwFlags is not set to zero, this function returns <c>FALSE</c> but the CSP is released.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError. Some
		/// possible error codes are listed in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The CSP context specified by hProv is currently being used by another process.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The hProv parameter does not contain a valid context handle.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// After this function has been called, the CSP session is finished and all existing session keys and hash objects created by using
		/// the hProv handle are no longer valid. In practice, all of these objects should be destroyed with calls to CryptDestroyKey and
		/// CryptDestroyHash before <c>CryptReleaseContext</c> is called.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Creating and Hashing a Session Key.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptreleasecontext BOOL CryptReleaseContext( HCRYPTPROV
		// hProv, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "c1e3e708-b543-4e87-8638-a9946a83e614")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptReleaseContext(HCRYPTPROV hProv, uint dwFlags = 0);

		/// <summary>
		/// The CryptSetHashParam function customizes the operations of a hash object, including setting up initial hash contents and
		/// selecting a specific hashing algorithm.
		/// </summary>
		/// <param name="hHash">A handle to the hash object on which to set parameters.</param>
		/// <param name="dwParam">
		/// <para>This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>HP_HMAC_INFO.</term>
		/// <term>
		/// A pointer to an HMAC_INFO structure that specifies the cryptographic hash algorithm and the inner and outer strings to be used.
		/// </term>
		/// </item>
		/// <item>
		/// <term>HP_HASHVAL.</term>
		/// <term>
		/// A byte array that contains a hash value to place directly into the hash object. Before setting this value, the size of the hash
		/// value must be determined by using the CryptGetHashParam function to read the HP_HASHSIZE value. Some cryptographic service
		/// providers (CSPs) do not support this capability.
		/// </term>
		/// </item>
		/// </list>
		/// <para><c>Note</c> Some CSP types can add additional values that can be set by using this function.</para>
		/// </param>
		/// <param name="pbData">
		/// A value data buffer. Place the value data in this buffer before calling <c>CryptSetHashParam</c>. The form of this data varies,
		/// depending on the value number.
		/// </param>
		/// <param name="dwFlags">This parameter is reserved for future use and must be set to zero.</param>
		/// <returns>
		/// <para>If the function succeeds, the function returns <c>TRUE</c>.</para>
		/// <para>If the function fails, it returns <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The CSP context is currently being used by another process.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero or the pbData buffer contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown value.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hKey key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Occasionally, a hash value that has been generated elsewhere must be signed. This can be done by using the following sequence of operations:
		/// </para>
		/// <list type="number">
		/// <item>
		/// <term>Create a hash object by using CryptCreateHash.</term>
		/// </item>
		/// <item>
		/// <term>Set the HP_HASHVAL value.</term>
		/// </item>
		/// <item>
		/// <term>Sign the hash value by using CryptSignHash and obtain a digital signature block.</term>
		/// </item>
		/// <item>
		/// <term>Destroy the hash object by using CryptDestroyHash.</term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsethashparam BOOL CryptSetHashParam( HCRYPTHASH
		// hHash, DWORD dwParam, const BYTE *pbData, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "0c8d3ef9-e7b5-4e49-a2f8-9c85b16549da")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSetHashParam(HCRYPTHASH hHash, HashParam dwParam, [In] IntPtr pbData, uint dwFlags = 0);

		/// <summary>
		/// The CryptSetKeyParam function customizes various aspects of a session key's operations. The values set by this function are not
		/// persisted to memory and can only be used with in a single session.
		/// <para>
		/// The Microsoft Base Cryptographic Provider does not permit setting values for key exchange or signature keys; however, custom
		/// providers can define values that can be set for its keys.
		/// </para>
		/// </summary>
		/// <param name="hKey">A handle to the key for which values are to be set.</param>
		/// <param name="dwParam">
		/// <para>The following tables contain predefined values that can be used.</para>
		/// <para>For all key types, this parameter can contain one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_ALGID</term>
		/// <term>
		/// pbData points to an appropriate ALG_ID. This is used when exchanging session keys with the Microsoft Base Digital Signature
		/// Standard (DSS), Diffie-Hellman Cryptographic Provider, or compatible CSPs. After a key is agreed upon with the CryptImportKey
		/// function, the session key is enabled for use by setting its algorithm type.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_CERTIFICATE</term>
		/// <term>
		/// pbData is the address of a buffer that contains the X.509 certificate that has been encoded by using Distinguished Encoding
		/// Rules (DER). The public key in the certificate must match the corresponding signature or exchange key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PERMISSIONS</term>
		/// <term>pbData points to a DWORD value that specifies zero or more permission flags. For a description of these flags, see CryptGetKeyParam.</term>
		/// </item>
		/// <item>
		/// <term>KP_SALT</term>
		/// <term>
		/// pbData points to a BYTE array that specifies a new salt value to be made part of the session key. The size of the salt value
		/// varies depending on the CSP being used. Before setting this value, determine the size of the salt value by calling the
		/// CryptGetKeyParam function. Salt values are used to make the session keys more unique, which makes dictionary attacks more
		/// difficult. The salt value is zero by default for Microsoft Base Cryptographic Provider.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_SALT_EX</term>
		/// <term>pbData points to a CRYPT_INTEGER_BLOB structure that contains the salt. For more information, see Specifying a Salt Value.</term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Digital Signature Standard (DSS) key is specified by the hKey parameter, the dwParam value can also be set to one of the
		/// following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_G</term>
		/// <term>
		/// pbData points to the generator G from the DSS key BLOB. The data is in the form of a CRYPT_INTEGER_BLOB structure, where the
		/// pbData member is the value, and the cbData member is the length of the value. The value is expected with no header information
		/// and in little-endian form.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_P</term>
		/// <term>
		/// pbData points to the prime modulus P of a DSS key BLOB. The data is in the form of a CRYPT_INTEGER_BLOB structure. The pbData
		/// member is the value, and the cbData member is the length of the value. The value is expected with no header information and in
		/// little-endian form.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_Q</term>
		/// <term>
		/// pbData points to the prime Q of a DSS key BLOB. The data is in the form of a CRYPT_INTEGER_BLOB structure where the pbData
		/// member is the value, and the cbData member is the length of the value. The value is expected with no header information and in
		/// little-endian form.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_X</term>
		/// <term>
		/// After the P, Q, and G values have been set, a call that specifies the KP_X value for dwParam and NULL for the pbData parameter
		/// can be made to the CryptSetKeyParam function. This causes the X and Y values to be generated.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a Diffie-Hellman algorithm or Digital Signature Algorithm (DSA) key is specified by hKey, the dwParam value can also be set
		/// to one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_CMS_DH_KEY_INFO</term>
		/// <term>
		/// Sets the information for an imported Diffie-Hellman key. The pbData parameter is the address of a CMS_DH_KEY_INFO structure that
		/// contains the key information to be set.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PUB_PARAMS</term>
		/// <term>
		/// Sets the public parameters (P, Q, G, and so on) of a DSS or Diffie-Hellman key. The key handle for this key must be in the
		/// PREGEN state, generated with the CRYPT_PREGEN flag. The pbData parameter must be a pointer to a DATA_BLOB structure where the
		/// data in this structure is a DHPUBKEY_VER3 or DSSPUBKEY_VER3 BLOB. The function copies the public parameters from this
		/// CRYPT_INTEGER_BLOB structure to the key handle. After this call is made, the KP_X parameter value should be used with
		/// CryptSetKeyParam to create the actual private key. The KP_PUB_PARAMS parameter is used as one call rather than multiple calls
		/// with the parameter values KP_P, KP_Q, and KP_G.
		/// </term>
		/// </item>
		/// </list>
		/// <para>
		/// If a block cipher session key is specified by the hKey parameter, the dwParam value can also be set to one of the following values.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_EFFECTIVE_KEYLEN</term>
		/// <term>
		/// This value type can only be used with RC2 keys and has been added because of the implementation of the CryptSetKeyParam function
		/// in the Microsoft Enhanced Cryptographic Provider prior to Windows 2000. In the previous implementation, the RC2 keys in the
		/// Enhanced Provider were 128 bits in strength, but the effective key length used to expand keys into the key table was only 40
		/// bits. This reduced the strength of the algorithm to 40 bits. To maintain backward compatibility, the previous implementation
		/// will remain as is. However, the effective key length can be set to be greater than 40 bits by using KP_EFFECTIVE_KEYLEN in the
		/// CryptSetKeyParam call. The effective key length is passed in the pbData parameter as a pointer to a DWORD value with the
		/// effective key length value. The minimum effective key length on the Microsoft Base Cryptographic Provider is one, and the
		/// maximum is 40. In the Microsoft Enhanced Cryptographic Provider, the minimum is one and the maximum is 1,024. The key length
		/// must be set prior to encrypting or decrypting with the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_HIGHEST_VERSION</term>
		/// <term>
		/// Sets the highest Transport Layer Security (TLS) version allowed. This property only applies to SSL and TLS keys. The pbData
		/// parameter is the address of a DWORD variable that contains the highest TLS version number supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_IV</term>
		/// <term>
		/// pbData points to a BYTE array that specifies the initialization vector. This array must contain BlockLength/8 elements. For
		/// example, if the block length is 64 bits, the initialization vector consists of 8 bytes. The initialization vector is set to zero
		/// by default for the Microsoft Base Cryptographic Provider.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_KEYVAL</term>
		/// <term>
		/// Set the key value for a Data Encryption Standard (DES) key. The pbData parameter is the address of a buffer that contains the
		/// key. This buffer must be the same length as the key. This property only applies to DES keys.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_PADDING</term>
		/// <term>
		/// Set the padding mode. The pbData parameter is a pointer to a DWORD value that receives a numeric identifier that identifies the
		/// padding method used by the cipher. This can be one of the following values. PKCS5_PADDING Specifies the PKCS 5 (sec 6.2) padding
		/// method. RANDOM_PADDING The padding uses a random number. This padding method is not supported by the Microsoft supplied CSPs.
		/// ZERO_PADDING The padding uses zeros. This padding method is not supported by the Microsoft supplied CSPs.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE</term>
		/// <term>
		/// pbData points to a DWORD value that specifies the cipher mode to be used. For a list of the defined cipher modes, see
		/// CryptGetKeyParam. The cipher mode is set to CRYPT_MODE_CBC by default for the Microsoft Base Cryptographic Provider.
		/// </term>
		/// </item>
		/// <item>
		/// <term>KP_MODE_BITS</term>
		/// <term>
		/// pbData points to a DWORD value that indicates the number of bits processed per cycle when the Output Feedback (OFB) or Cipher
		/// Feedback (CFB) cipher mode is used. The number of bits processed per cycle is set to 8 by default for the Microsoft Base
		/// Cryptographic Provider.
		/// </term>
		/// </item>
		/// </list>
		/// <para>If an RSA key is specified in the hKey parameter, the dwParam parameter value can be the following value.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>KP_OAEP_PARAMS</term>
		/// <term>
		/// Set the Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2) parameters for the key. The pbData parameter is the
		/// address of a CRYPT_DATA_BLOB structure that contains the OAEP label. This property only applies to RSA keys.
		/// </term>
		/// </item>
		/// </list>
		/// <para>Note that the following values are not used:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>KP_ADMIN_PIN</term>
		/// </item>
		/// <item>
		/// <term>KP_CMS_KEY_INFO</term>
		/// </item>
		/// <item>
		/// <term>KP_INFO</term>
		/// </item>
		/// <item>
		/// <term>KP_KEYEXCHANGE_PIN</term>
		/// </item>
		/// <item>
		/// <term>KP_PRECOMP_MD5</term>
		/// </item>
		/// <item>
		/// <term>KP_PRECOMP_SHA</term>
		/// </item>
		/// <item>
		/// <term>KP_PREHASH</term>
		/// </item>
		/// <item>
		/// <term>KP_PUB_EX_LEN</term>
		/// </item>
		/// <item>
		/// <term>KP_PUB_EX_VAL</term>
		/// </item>
		/// <item>
		/// <term>KP_RA</term>
		/// </item>
		/// <item>
		/// <term>KP_RB</term>
		/// </item>
		/// <item>
		/// <term>KP_ROUNDS</term>
		/// </item>
		/// <item>
		/// <term>KP_RP</term>
		/// </item>
		/// <item>
		/// <term>KP_SIGNATURE_PIN</term>
		/// </item>
		/// <item>
		/// <term>KP_Y</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// A pointer to a buffer initialized with the value to be set before calling <c>CryptSetKeyParam</c>. The form of this data varies
		/// depending on the value of dwParam.
		/// </param>
		/// <param name="dwFlags">
		/// Used only when dwParam is KP_ALGID. The dwFlags parameter is used to pass in flag values for the enabled key. The dwFlags
		/// parameter can hold values such as the key size and the other flag values allowed when generating the same type of key with
		/// CryptGenKey. For information about allowable flag values, see <c>CryptGenKey</c>.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP being used. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The CSP context is currently being used by another process.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero, or the pbData buffer contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown parameter.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hKey key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FIXEDPARAMETER</term>
		/// <term>
		/// Some CSPs have hard-coded P, Q, and G values. If this is the case, then using KP_P, KP_Q, and KP_G for the value of dwParam
		/// causes this error.
		/// </term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// If the KP_Q, KP_P, or KP_X parameters are set on a PREGEN Diffie-Hellman or DSS key, the key lengths must be compatible with the
		/// key length set using the upper 16 bits of the dwFlags parameter when the key was created using CryptGenKey. If no key length was
		/// set in <c>CryptGenKey</c>, the default key length was used. This will create an error if a nondefault key length is used to set
		/// P, Q, or X.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// For an example that uses this function, see Example C Program: Duplicating a Session Key. For more code that uses this function,
		/// see Example C Program: Setting and Getting Session Key Parameters .
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetkeyparam BOOL CryptSetKeyParam( HCRYPTKEY hKey,
		// DWORD dwParam, const BYTE *pbData, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "e99a84a2-c23e-4251-8062-dd286ccc29b7")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSetKeyParam(HCRYPTKEY hKey, KeyParam dwParam, [In] IntPtr pbData, uint dwFlags);

		/// <summary>
		/// <para>The CryptSetProvider function specifies the current user's default cryptographic service provider (CSP).</para>
		/// <para>
		/// If a current user's default provider is set, that default provider is acquired by any call by that user to CryptAcquireContext
		/// specifying a dwProvType provider type but not a CSP name.
		/// </para>
		/// <para>An enhanced version of this function, CryptSetProviderEx, is also available.</para>
		/// <para><c>Note</c> Typical applications do not use this function. It is intended for use solely by administrative applications.</para>
		/// </summary>
		/// <param name="pszProvName">
		/// Name of the new default CSP. The named CSP must be installed on the computer. For a list of available cryptographic providers,
		/// see Cryptographic Provider Names.
		/// </param>
		/// <param name="dwProvType">Provider type of the CSP specified by pszProvName.</param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>
		/// If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError. Some possible error
		/// codes are listed in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// <para>Errors can also be propagated from internal calls to RegCreateKeyEx and RegSetValueEx.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Typical applications do not specify a CSP name when calling CryptAcquireContext; however, an application does have the option of
		/// selecting a specific CSP. This gives a user the freedom to select a CSP with an appropriate level of security.
		/// </para>
		/// <para>
		/// Since calling <c>CryptSetProvider</c> determines the CSP of a specified type used by all applications that run from that point
		/// on, this function must not be called without users' consent.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetprovidera BOOL CryptSetProviderA( LPCSTR
		// pszProvName, DWORD dwProvType );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "44023a0c-3fb4-4746-a676-1671c3ad901b")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSetProvider([MarshalAs(UnmanagedType.LPTStr)] string pszProvName, uint dwProvType);

		/// <summary>
		/// <para>
		/// The CryptSetProviderEx function specifies the default cryptographic service provider (CSP) of a specified provider type for the
		/// local computer or current user.
		/// </para>
		/// <note>Typical applications do not use this function. It is intended for use solely by administrative applications.</note>
		/// </summary>
		/// <param name="pszProvName">
		/// The name of the new default CSP. This must be a CSP installed on the computer. For a list of available cryptographic providers,
		/// see Cryptographic Provider Names.
		/// </param>
		/// <param name="dwProvType">The provider type of the CSP specified by pszProvName.</param>
		/// <param name="pdwReserved">This parameter is reserved for future use and must be <c>NULL</c>.</param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_DELETE_DEFAULT 0x00000004</term>
		/// <term>Can be used in conjunction with CRYPT_MACHINE_DEFAULT or CRYPT_USER_DEFAULT to delete the default.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_USER_DEFAULT 0x00000002</term>
		/// <term>Causes the user-context default CSP of the specified type to be set.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_MACHINE_DEFAULT 0x00000001</term>
		/// <term>Causes the computer default CSP of the specified type to be set.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError. Possible
		/// error codes include those shown in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_NOT_ENOUGH_MEMORY</term>
		/// <term>The operating system ran out of memory.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// Most applications do not specify a CSP name when calling the CryptAcquireContext function; however, an application can specify a
		/// CSP name and thereby select a CSP with an appropriate level of security. Because calls to <c>CryptSetProviderEx</c> determine
		/// the CSP of a specified type used by all applications from that point on, <c>CryptSetProviderEx</c> must never be called without
		/// a user's consent.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetproviderexa BOOL CryptSetProviderExA( LPCSTR
		// pszProvName, DWORD dwProvType, DWORD *pdwReserved, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "5f0c2724-5144-4a22-a7da-2a5162f06f5d")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSetProviderEx([MarshalAs(UnmanagedType.LPTStr)] string pszProvName, uint dwProvType, [Optional] IntPtr pdwReserved, CryptProviderFlags dwFlags);

		/// <summary>
		/// The CryptSetProvParam function customizes the operations of a cryptographic service provider (CSP). This function is commonly
		/// used to set a security descriptor on the key container associated with a CSP to control access to the private keys in that key container.
		/// </summary>
		/// <param name="hProv">
		/// The handle of a CSP for which to set values. This handle must have already been created by using the CryptAcquireContext function.
		/// </param>
		/// <param name="dwParam">
		/// <para>Specifies the parameter to set. This can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>PP_CLIENT_HWND 1 (0x1)</term>
		/// <term>
		/// Set the window handle that the provider uses as the parent of any dialog boxes it creates. pbData contains a pointer to an HWND
		/// that contains the parent window handle. This parameter must be set before calling CryptAcquireContext because many CSPs will
		/// display a user interface when CryptAcquireContext is called. You can pass NULL for the hProv parameter to set this window handle
		/// for all cryptographic contexts subsequently acquired within this process.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_DELETEKEY 24 (0x18)</term>
		/// <term>
		/// Delete the ephemeral key associated with a hash, encryption, or verification context. This will free memory and clear registry
		/// settings associated with the key.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_KEYEXCHANGE_ALG</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYEXCHANGE_PIN 32 (0x20)</term>
		/// <term>Specifies that the key exchange PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYEXCHANGE_KEYSIZE</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_KEYSET_SEC_DESCR 8 (0x8)</term>
		/// <term>
		/// Sets the security descriptor on the key storage container. The pbData parameter is the address of a SECURITY_DESCRIPTOR
		/// structure that contains the new security descriptor for the key storage container.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_PIN_PROMPT_STRING 44 (0x2C)</term>
		/// <term>
		/// Sets an alternate prompt string to display to the user when the user's PIN is requested. The pbData parameter is a pointer to a
		/// null-terminated Unicode string.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_ROOT_CERTSTORE 46 (0x2E)</term>
		/// <term>
		/// Sets the root certificate store for the smart card. The provider will copy the root certificates from this store onto the smart
		/// card. The pbData parameter is an HCERTSTORE variable that contains the handle of the new certificate store. The provider will
		/// copy the certificates from the store during this call, so it is safe to close this store after this function is called. Windows
		/// XP and Windows Server 2003: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SIGNATURE_ALG</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_SIGNATURE_PIN 33 (0x21)</term>
		/// <term>Specifies the signature PIN. The pbData parameter is a null-terminated ASCII string that represents the PIN.</term>
		/// </item>
		/// <item>
		/// <term>PP_SIGNATURE_KEYSIZE</term>
		/// <term>This constant is not used.</term>
		/// </item>
		/// <item>
		/// <term>PP_UI_PROMPT 21 (0x15)</term>
		/// <term>
		/// For a smart card provider, sets the search string that is displayed to the user as a prompt to insert the smart card. This
		/// string is passed as the lpstrSearchDesc member of the OPENCARDNAME_EX structure that is passed to the SCardUIDlgSelectCard
		/// function. This string is used for the lifetime of the calling process. The pbData parameter is a pointer to a null-terminated
		/// Unicode string.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USE_HARDWARE_RNG 38 (0x26)</term>
		/// <term>
		/// Specifies that the CSP must exclusively use the hardware random number generator (RNG). When PP_USE_HARDWARE_RNG is set, random
		/// values are taken exclusively from the hardware RNG and no other sources are used. If a hardware RNG is supported by the CSP and
		/// it can be exclusively used, the function succeeds and returns TRUE; otherwise, the function fails and returns FALSE. The pbData
		/// parameter must be NULL and dwFlags must be zero when using this value. None of the Microsoft CSPs currently support using a
		/// hardware RNG.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_USER_CERTSTORE 42 (0x2A)</term>
		/// <term>
		/// Specifies the user certificate store for the smart card. This certificate store contains all of the user certificates that are
		/// stored on the smart card. The certificates in this store are encoded by using PKCS_7_ASN_ENCODING or X509_ASN_ENCODING encoding
		/// and should contain the CERT_KEY_PROV_INFO_PROP_ID property. The pbData parameter is an HCERTSTORE variable that receives the
		/// handle of an in-memory certificate store. When this handle is no longer needed, the caller must close it by using the
		/// CertCloseStore function. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SECURE_KEYEXCHANGE_PIN 47 (0x2F)</term>
		/// <term>Specifies that an encrypted key exchange PIN is contained in pbData. The pbData parameter contains a DATA_BLOB.</term>
		/// </item>
		/// <item>
		/// <term>PP_SECURE_SIGNATURE_PIN 48 (0x30)</term>
		/// <term>Specifies that an encrypted signature PIN is contained in pbData. The pbData parameter contains a DATA_BLOB.</term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_READER 43 (0x2B)</term>
		/// <term>
		/// Specifies the name of the smart card reader. The pbData parameter is the address of an ANSI character array that contains a
		/// null-terminated ANSI string that contains the name of the smart card reader. Windows Server 2003 and Windows XP: This parameter
		/// is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>PP_SMARTCARD_GUID 45 (0x2D)</term>
		/// <term>
		/// Specifies the identifier of the smart card. The pbData parameter is the address of a GUID structure that contains the identifier
		/// of the smart card. Windows Server 2003 and Windows XP: This parameter is not supported.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbData">
		/// A pointer to a data buffer that contains the value to be set as a provider parameter. The form of this data varies depending on
		/// the dwParam value. If dwParam contains <c>PP_USE_HARDWARE_RNG</c>, this parameter must be <c>NULL</c>.
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// If dwParam contains <c>PP_KEYSET_SEC_DESCR</c>, dwFlags contains the <c>SECURITY_INFORMATION</c> applicable bit flags, as
		/// defined in the Platform SDK. Key-container security is handled by using SetFileSecurity and GetFileSecurity.
		/// </para>
		/// <para>These bit flags can be combined by using a bitwise- <c>OR</c> operation. For more information, see CryptGetProvParam.</para>
		/// <para>If dwParam is <c>PP_USE_HARDWARE_RNG</c> or <c>PP_DELETEKEY</c>, dwFlags must be set to zero.</para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP being used. Error codes include the following.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_BUSY</term>
		/// <term>The CSP context is currently being used by another process.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero or the pbData buffer contains a value that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_TYPE</term>
		/// <term>The dwParam parameter specifies an unknown parameter.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hKey key was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_FAIL</term>
		/// <term>The function failed in some unexpected way.</term>
		/// </item>
		/// </list>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetprovparam BOOL CryptSetProvParam( HCRYPTPROV
		// hProv, DWORD dwParam, const BYTE *pbData, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "98306a7b-b218-4eb4-99f0-0b5bcc632a13")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSetProvParam(HCRYPTPROV hProv, ProvParam dwParam, [In] IntPtr pbData, uint dwFlags);

		/// <summary>
		/// The CryptSignHash function signs data. Because all signature algorithms are asymmetric and thus slow, CryptoAPI does not allow
		/// data to be signed directly. Instead, data is first hashed, and CryptSignHash is used to sign the hash.
		/// </summary>
		/// <param name="hHash">Handle of the hash object to be signed.</param>
		/// <param name="dwKeySpec">
		/// <para>Identifies the private key to use from the provider's container. It can be AT_KEYEXCHANGE or AT_SIGNATURE.</para>
		/// <para>The signature algorithm used is specified when the key pair is originally created.</para>
		/// <para>The only signature algorithm that the Microsoft Base Cryptographic Provider supports is the RSA Public Key algorithm.</para>
		/// </param>
		/// <param name="szDescription">
		/// This parameter is no longer used and must be set to <c>NULL</c> to prevent security vulnerabilities. However, it is still
		/// supported for backward compatibility in the Microsoft Base Cryptographic Provider.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_NOHASHOID 0x00000001</term>
		/// <term>
		/// Used with RSA providers. The hash object identifier (OID) is not placed in the RSA public key encryption. If this flag is not
		/// set, the hash OID in the default signature is as specified in the definition of DigestInfo in PKCS #1.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_TYPE2_FORMAT 0x00000002</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_X931_FORMAT 0x00000004</term>
		/// <term>Use the RSA signature padding method specified in the ANSI X9.31 standard.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbSignature">
		/// <para>A pointer to a buffer receiving the signature data.</para>
		/// <para>
		/// This parameter can be <c>NULL</c> to set the buffer size for memory allocation purposes. For more information, see Retrieving
		/// Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pdwSigLen">
		/// <para>
		/// A pointer to a <c>DWORD</c> value that specifies the size, in bytes, of the pbSignature buffer. When the function returns, the
		/// <c>DWORD</c> value contains the number of bytes stored in the buffer.
		/// </para>
		/// <para>
		/// <c>Note</c> When processing the data returned in the buffer, applications must use the actual size of the data returned. The
		/// actual size can be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually
		/// specified large enough to ensure that the largest possible output data fits in the buffer.) On output, the variable pointed to
		/// by this parameter is updated to reflect the actual size of the data copied to the buffer.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns <c>TRUE</c>.</para>
		/// <para>If the function fails, it returns <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_MORE_DATA</term>
		/// <term>
		/// The buffer specified by the pbSignature parameter is not large enough to hold the returned data. The required buffer size, in
		/// bytes, is in the pdwSigLenDWORD value.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_ALGID</term>
		/// <term>The hHash handle specifies an algorithm that this CSP does not support, or the dwKeySpec parameter has an incorrect value.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The CSP context that was specified when the hash object was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_KEY</term>
		/// <term>The private key specified by dwKeySpec does not exist.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object. The CryptHashData or
		/// CryptHashSessionKey function is then used to add the data or session keys to the hash object. The <c>CryptSignHash</c> function
		/// completes the hash.
		/// </para>
		/// <para>
		/// While the DSS CSP supports hashing with both the MD5 and the SHA hash algorithms, the DSS CSP only supports signing SHA hashes.
		/// </para>
		/// <para>
		/// After this function is called, no more data can be added to the hash. Additional calls to CryptHashData or CryptHashSessionKey fail.
		/// </para>
		/// <para>After the application finishes using the hash, destroy the hash object by calling the CryptDestroyHash function.</para>
		/// <para>
		/// By default, the Microsoft RSA providers use the PKCS #1 padding method for the signature. The hash OID in the <c>DigestInfo</c>
		/// element of the signature is automatically set to the algorithm OID associated with the hash object. Using the
		/// <c>CRYPT_NOHASHOID</c> flag will cause this OID to be omitted from the signature.
		/// </para>
		/// <para>
		/// Occasionally, a hash value that has been generated elsewhere must be signed. This can be done by using the following sequence of operations:
		/// </para>
		/// <list type="number">
		/// <item>
		/// <term>Create a hash object by using CryptCreateHash.</term>
		/// </item>
		/// <item>
		/// <term>Set the hash value in the hash object by using the <c>HP_HASHVAL</c> value of the dwParam parameter in CryptSetHashParam.</term>
		/// </item>
		/// <item>
		/// <term>Sign the hash value by using <c>CryptSignHash</c> and obtain a digital signature block.</term>
		/// </item>
		/// <item>
		/// <term>Destroy the hash object by using CryptDestroyHash.</term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>
		/// The following example shows signing data by first hashing the data to be signed and then signing the hash by using the
		/// <c>CryptSignHash</c> function.
		/// </para>
		/// <para>
		/// For a complete example including the context for this code, see Example C Program: Signing a Hash and Verifying the Hash Signature.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsignhasha BOOL CryptSignHashA( HCRYPTHASH hHash,
		// DWORD dwKeySpec, LPCSTR szDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "9cf0de04-fdad-457d-8137-16d98f915cd5")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptSignHash(HCRYPTHASH hHash, CertKeySpec dwKeySpec, [Optional, MarshalAs(UnmanagedType.LPTStr)] string szDescription, CryptSignFlags dwFlags, [Out, Optional] IntPtr pbSignature, ref uint pdwSigLen);

		/// <summary>
		/// <para>The CryptVerifySignature function verifies the signature of a hash object.</para>
		/// <para>
		/// Before calling this function, CryptCreateHash must be called to create the handle of a hash object. CryptHashData or
		/// CryptHashSessionKey is then used to add data or session keys to the hash object.
		/// </para>
		/// <para>After <c>CryptVerifySignature</c> completes, only CryptDestroyHash can be called by using the hHash handle.</para>
		/// </summary>
		/// <param name="hHash">A handle to the hash object to verify.</param>
		/// <param name="pbSignature">The address of the signature data to be verified.</param>
		/// <param name="dwSigLen">The number of bytes in the pbSignature signature data.</param>
		/// <param name="hPubKey">
		/// A handle to the public key to use to authenticate the signature. This public key must belong to the key pair that was originally
		/// used to create the digital signature.
		/// </param>
		/// <param name="szDescription">
		/// This parameter should no longer be used and must be set to <c>NULL</c> to prevent security vulnerabilities. However, it is still
		/// supported for backward compatibility in the Microsoft Base Cryptographic Provider.
		/// </param>
		/// <param name="dwFlags">
		/// <para>The following flag values are defined.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_NOHASHOID 0x00000001</term>
		/// <term>
		/// This flag is used with RSA providers. When verifying the signature, the hash object identifier (OID) is not expected to be
		/// present or checked. If this flag is not set, the hash OID in the default signature is verified as specified in the definition of
		/// DigestInfo in PKCS #7.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CRYPT_TYPE2_FORMAT 0x00000002</term>
		/// <term>This flag is not used.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_X931_FORMAT 0x00000004</term>
		/// <term>Use X.931 support for the FIPS 186-2–compliant version of RSA (rDSA).</term>
		/// </item>
		/// </list>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is <c>TRUE</c>.</para>
		/// <para>If the function fails, the return value is <c>FALSE</c>. For extended error information, call GetLastError.</para>
		/// <para>The error codes prefaced by "NTE" are generated by the particular CSP you are using. Some possible error codes follow.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Return code</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>ERROR_INVALID_HANDLE</term>
		/// <term>One of the parameters specifies a handle that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>ERROR_INVALID_PARAMETER</term>
		/// <term>One of the parameters contains a value that is not valid. This is most often a pointer that is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_FLAGS</term>
		/// <term>The dwFlags parameter is nonzero.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_HASH</term>
		/// <term>The hash object specified by the hHash parameter is not valid.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_KEY</term>
		/// <term>The hPubKey parameter does not contain a handle to a valid public key.</term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_SIGNATURE</term>
		/// <term>
		/// The signature was not valid. This might be because the data itself has changed, the description string did not match, or the
		/// wrong public key was specified by hPubKey. This error can also be returned if the hashing or signature algorithms do not match
		/// the ones used to create the signature.
		/// </term>
		/// </item>
		/// <item>
		/// <term>NTE_BAD_UID</term>
		/// <term>The cryptographic service provider (CSP) context that was specified when the hash object was created cannot be found.</term>
		/// </item>
		/// <item>
		/// <term>NTE_NO_MEMORY</term>
		/// <term>The CSP ran out of memory during the operation.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The <c>CryptVerifySignature</c> function completes the hash. After this call, no more data can be added to the hash. Additional
		/// calls to CryptHashData or CryptHashSessionKey fail. After the application is done with the hash, CryptDestroyHash should be
		/// called to destroy the hash object.
		/// </para>
		/// <para>
		/// If you generate a signature by using the .NET Framework APIs and try to verify it by using the <c>CryptVerifySignature</c>
		/// function, the function will fail and GetLastError will return <c>NTE_BAD_SIGNATURE</c>. This is due to the different byte orders
		/// between the native Win32 API and the .NET Framework API.
		/// </para>
		/// <para>
		/// The native cryptography API uses little-endian byte order while the .NET Framework API uses big-endian byte order. If you are
		/// verifying a signature generated by using a .NET Framework API, you must swap the order of signature bytes before calling the
		/// <c>CryptVerifySignature</c> function to verify the signature.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// For an example that uses the <c>CryptVerifySignature</c> function, see Example C Program: Signing a Hash and Verifying the Hash Signature.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptverifysignaturea BOOL CryptVerifySignatureA(
		// HCRYPTHASH hHash, const BYTE *pbSignature, DWORD dwSigLen, HCRYPTKEY hPubKey, LPCSTR szDescription, DWORD dwFlags );
		[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("wincrypt.h", MSDNShortId = "3119eabc-90ff-42c6-b3fa-e8be625f6d1e")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptVerifySignature(HCRYPTHASH hHash, [In] IntPtr pbSignature, uint dwSigLen, HCRYPTKEY hPubKey, [Optional, MarshalAs(UnmanagedType.LPTStr)] string szDescription, CryptSignFlags dwFlags);

		private static TRet CryptGetValue<THandle, TEnum, TRet>(CryptGetValueMethod<THandle, TEnum> func, THandle hKey, TEnum dwParam, uint dwFlags = 0) where THandle : struct where TEnum : Enum
		{
			var len = 0U;
			if (!func(hKey, dwParam, default, ref len, dwFlags))
				Win32Error.ThrowLastError();
			using var mem = new SafeHGlobalHandle(len);
			if (!func(hKey, dwParam, mem, ref len, dwFlags))
				Win32Error.ThrowLastError();
			return mem.DangerousGetHandle().Convert<TRet>(mem.Size);
		}

		/// <summary>
		/// The <c>HMAC_INFO</c> structure specifies the hash algorithm and the inner and outer strings that are to be used to calculate the
		/// HMAC hash.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-hmac_info typedef struct _HMAC_Info { ALG_ID HashAlgid;
		// BYTE *pbInnerString; DWORD cbInnerString; BYTE *pbOuterString; DWORD cbOuterString; } HMAC_INFO, *PHMAC_INFO;
		[PInvokeData("wincrypt.h", MSDNShortId = "0c9a9b60-077d-48c0-a5a6-01640cfc0c4e")]
		[StructLayout(LayoutKind.Sequential)]
		public struct HMAC_INFO
		{
			/// <summary>Specifies the hash algorithm to be used.</summary>
			public ALG_ID HashAlgid;

			/// <summary>
			/// A pointer to the inner string to be used in the HMAC calculation. The default inner string is defined as the byte 0x36
			/// repeated 64 times.
			/// </summary>
			public IntPtr pbInnerString;

			/// <summary>
			/// The count of bytes in <c>pbInnerString</c>. The CSP uses the default inner string if <c>cbInnerString</c> is equal to zero.
			/// </summary>
			public uint cbInnerString;

			/// <summary>
			/// A pointer to the outer string to be used in the HMAC calculation. The default outer string is defined as the byte 0x5C
			/// repeated 64 times.
			/// </summary>
			public IntPtr pbOuterString;

			/// <summary>
			/// The count of bytes in <c>pbOuterString</c>. The CSP uses the default outer string if <c>cbOuterString</c> is equal to zero.
			/// </summary>
			public uint cbOuterString;
		}

		/// <summary>
		/// The <c>PROV_ENUMALGS</c> structure is used with the CryptGetProvParam function when the <c>PP_ENUMALGS</c> parameter is retrieved to
		/// contain information about an algorithm supported by a cryptographic service provider (CSP).
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-prov_enumalgs
		// typedef struct _PROV_ENUMALGS { ALG_ID aiAlgid; DWORD dwBitLen; DWORD dwNameLen; CHAR szName[20]; } PROV_ENUMALGS;
		[PInvokeData("wincrypt.h", MSDNShortId = "8301d07f-88aa-49b4-9091-8f515b585c57")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct PROV_ENUMALGS
		{
			/// <summary>One of the ALG_ID values that identifies the algorithm.</summary>
			public ALG_ID aiAlgid;

			/// <summary>The default key length, in bits, of the algorithm.</summary>
			public uint dwBitLen;

			/// <summary>The length, in <c>CHAR</c>s, of the <c>szName</c> string. This length includes the terminating null character.</summary>
			public uint dwNameLen;

			/// <summary>A null-terminated ANSI string that contains the name of the algorithm.</summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
			public string szName;
		}

		/// <summary>
		/// The <c>PROV_ENUMALGS_EX</c> structure is used with the CryptGetProvParam function when the <c>PP_ENUMALGS_EX</c> parameter is
		/// retrieved to contain information about an algorithm supported by a cryptographic service provider (CSP).
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-prov_enumalgs_ex typedef struct _PROV_ENUMALGS_EX {
		// ALG_ID aiAlgid; DWORD dwDefaultLen; DWORD dwMinLen; DWORD dwMaxLen; DWORD dwProtocols; DWORD dwNameLen; CHAR szName[20]; DWORD
		// dwLongNameLen; CHAR szLongName[40]; } PROV_ENUMALGS_EX;
		[PInvokeData("wincrypt.h", MSDNShortId = "239dbc6f-c3fa-4f97-aa9a-4993fe726a98")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct PROV_ENUMALGS_EX
		{
			/// <summary>One of the ALG_ID values that identifies the algorithm.</summary>
			public ALG_ID aiAlgid;
			/// <summary>The default key length, in bits, of the algorithm.</summary>
			public uint dwDefaultLen;
			/// <summary>The minimum key length, in bits, of the algorithm.</summary>
			public uint dwMinLen;
			/// <summary>The maximum key length, in bits, of the algorithm.</summary>
			public uint dwMaxLen;
			/// <summary>
			/// Zero or a combination of one or more of the Protocol Flags values that identifies the protocols supported by the algorithm.
			/// </summary>
			public uint dwProtocols;
			/// <summary>The length, in <c>CHAR</c> s, of the <c>szName</c> string. This length includes the terminating null character.</summary>
			public uint dwNameLen;
			/// <summary>A null-terminated ANSI string that contains the name of the algorithm.</summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
			public string szName;
			/// <summary>The length, in <c>CHAR</c> s, of the <c>szLongName</c> string. This length includes the terminating null character.</summary>
			public uint dwLongNameLen;
			/// <summary>A null-terminated ANSI string that contains the long name of the algorithm.</summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
			public string szLongName;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HCRYPTHASH"/> that is disposed using <see cref="CryptDestroyHash"/>.</summary>
		public class SafeHCRYPTHASH : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHCRYPTHASH"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeHCRYPTHASH(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeHCRYPTHASH"/> class.</summary>
			private SafeHCRYPTHASH() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeHCRYPTHASH"/> to <see cref="HCRYPTHASH"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HCRYPTHASH(SafeHCRYPTHASH h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => CryptDestroyHash(handle);
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HCRYPTPROV"/> that is disposed using <see cref="CryptReleaseContext"/>.</summary>
		public class SafeHCRYPTPROV : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHCRYPTPROV"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeHCRYPTPROV(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeHCRYPTPROV"/> class.</summary>
			private SafeHCRYPTPROV() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeHCRYPTPROV"/> to <see cref="HCRYPTPROV"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HCRYPTPROV(SafeHCRYPTPROV h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => CryptReleaseContext(handle);
		}

		/// <summary>
		/// The following cryptographic service provider (CSP) names are defined in Wincrypt.h. These constants are used with the
		/// <c>CryptAcquireContext</c> and <c>CryptSetProvider</c> functions.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/seccrypto/cryptographic-provider-names
		[PInvokeData("wincrypt.h", MSDNShortId = "97e9a708-83b5-48b3-9d16-f7b54367dc4e")]
		public static class CryptProviderName
		{
			/// <summary>The Microsoft DSS and Diffie-Hellman/Schannel Cryptographic Provider.</summary>
			public const string MS_DEF_DH_SCHANNEL_PROV = "Microsoft DH Schannel Cryptographic Provider";

			/// <summary>The Microsoft Base DSS and Diffie-Hellman Cryptographic Provider.</summary>
			public const string MS_DEF_DSS_DH_PROV = "Microsoft Base DSS and Diffie-Hellman Cryptographic Provider";

			/// <summary>The Microsoft DSS Cryptographic Provider.</summary>
			public const string MS_DEF_DSS_PROV = "Microsoft Base DSS Cryptographic Provider";

			/// <summary>The Microsoft Base Cryptographic Provider.</summary>
			public const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";

			/// <summary>The Microsoft RSA/Schannel Cryptographic Provider.</summary>
			public const string MS_DEF_RSA_SCHANNEL_PROV = "Microsoft RSA Schannel Cryptographic Provider";

			/// <summary>The Microsoft RSA Signature Cryptographic Provider is not supported.</summary>
			public const string MS_DEF_RSA_SIG_PROV = "Microsoft RSA Signature Cryptographic Provider";

			/// <summary>The Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider.</summary>
			public const string MS_ENH_DSS_DH_PROV = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider";

			/// <summary>
			/// The Microsoft AES Cryptographic Provider.
			/// <para>**Windows XP: **"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"</para>
			/// </summary>
			public const string MS_ENH_RSA_AES_PROV = "Microsoft Enhanced RSA and AES Cryptographic Provider";

			/// <summary>The Microsoft Enhanced Cryptographic Provider.</summary>
			public const string MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0";

			/// <summary>The Microsoft Base Smart Card Cryptographic Service Provider.</summary>
			public const string MS_SCARD_PROV = "Microsoft Base Smart Card Crypto Provider";

			/// <summary>The Microsoft Strong Cryptographic Provider.</summary>
			public const string MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider";
		}
	}
}