diff --git a/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs b/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs
index 7535c6bd..bfe4ae21 100644
--- a/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs
+++ b/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
+using Vanara.Extensions;
using Vanara.InteropServices;
namespace Vanara.PInvoke
@@ -22,11 +24,11 @@ namespace Vanara.PInvoke
// *pvArg, DWORD cProp, DWORD *rgdwPropId, void **rgpvData, DWORD *rgcbData ) {...}
[PInvokeData("wincrypt.h", MSDNShortId = "c4461b79-d216-4d4a-bd5d-9260ec897c14")]
[return: MarshalAs(UnmanagedType.Bool)]
- public delegate bool PFN_CRYPT_ENUM_KEYID_PROP(in CRYPTOAPI_BLOB pKeyIdentifier, [Optional] uint dwFlags, [Optional] IntPtr pvReserved, [Optional] IntPtr pvArg, uint cProp, [In] uint[] rgdwPropId, [In] IntPtr[] rgpvData, [In] uint[] rgcbData);
+ public delegate bool PFN_CRYPT_ENUM_KEYID_PROP([In, Optional] IntPtr pKeyIdentifier, [Optional] uint dwFlags, [Optional] IntPtr pvReserved, [Optional] IntPtr pvArg, uint cProp, [In] uint[] rgdwPropId, [In] IntPtr[] rgpvData, [In] uint[] rgcbData);
/// Blob type specifier for PUBLICKEYSTRUC.
[PInvokeData("wincrypt.h", MSDNShortId = "99d41222-b4ca-40f3-a240-52b0a9b3a9aa")]
- public enum BlobType : byte
+ public enum BlobType : uint
{
/// The BLOB is a key state BLOB.
KEYSTATEBLOB = 0xC,
@@ -411,8 +413,178 @@ namespace Vanara.PInvoke
[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("wincrypt.h", MSDNShortId = "6e57d935-4cfb-44af-b1c6-6c399c959452")]
[return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool CryptEnumKeyIdentifierProperties(in CRYPTOAPI_BLOB pKeyIdentifier, uint dwPropId, CryptKeyIdFlags dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName,
- [Optional] IntPtr pvReserved, [In, Out, Optional] IntPtr pvArg, [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum);
+ public static extern bool CryptEnumKeyIdentifierProperties(in CRYPTOAPI_BLOB pKeyIdentifier, [In, Optional] uint dwPropId, CryptKeyIdFlags dwFlags,
+ [Optional, MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName, [In, Optional] IntPtr pvReserved, [In, Optional] IntPtr pvArg,
+ [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum);
+
+ ///
+ /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier.
+ /// If pKeyIdentifier is NULL, the function enumerates all key identifiers.
+ /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier.
+ /// Indicates the property identifier to be listed.
+ /// If dwPropId is set to zero, this function calls the callback function with all the properties.
+ ///
+ /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that
+ /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped.
+ ///
+ /// Any certificate property identifier can be used.
+ ///
+ /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key
+ /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not
+ /// NULL) is searched. For more information, see pwszComputerName.
+ ///
+ ///
+ /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is
+ /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is
+ /// set to NULL.
+ ///
+ /// Reserved for future use and must be NULL.
+ ///
+ /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and
+ /// initialize a structure or argument to hold any information.
+ ///
+ ///
+ /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input
+ /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP.
+ ///
+ ///
+ ///
+ /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier.
+ /// If pKeyIdentifier is NULL, the function enumerates all key identifiers.
+ /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier.
+ ///
+ ///
+ /// Indicates the property identifier to be listed.
+ /// If dwPropId is set to zero, this function calls the callback function with all the properties.
+ ///
+ /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that
+ /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped.
+ ///
+ /// Any certificate property identifier can be used.
+ ///
+ ///
+ /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key
+ /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not
+ /// NULL) is searched. For more information, see pwszComputerName.
+ ///
+ ///
+ /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is
+ /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is
+ /// set to NULL.
+ ///
+ /// Reserved for future use and must be NULL.
+ ///
+ /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and
+ /// initialize a structure or argument to hold any information.
+ ///
+ ///
+ /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input
+ /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP.
+ ///
+ ///
+ ///
+ /// The CryptEnumKeyIdentifierProperties function repeatedly calls the CRYPT_ENUM_KEYID_PROP callback function until the last
+ /// key identifier is enumerated or the callback function returns FALSE.
+ ///
+ /// If the main function succeeds, the function returns nonzero ( TRUE).
+ /// If the function fails, it returns zero ( FALSE). For extended error information, call GetLastError.
+ /// To continue enumeration, the function returns TRUE.
+ /// To stop enumeration, the function returns FALSE and sets the last error code.
+ ///
+ ///
+ /// A key identifier can have the same properties as a certificate context.
+ /// Examples
+ /// For an example that uses this function, see Example C Program: Working with Key Identifiers.
+ ///
+ // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptenumkeyidentifierproperties BOOL
+ // CryptEnumKeyIdentifierProperties( const CRYPT_HASH_BLOB *pKeyIdentifier, DWORD dwPropId, DWORD dwFlags, LPCWSTR pwszComputerName,
+ // void *pvReserved, void *pvArg, PFN_CRYPT_ENUM_KEYID_PROP pfnEnum );
+ [DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
+ [PInvokeData("wincrypt.h", MSDNShortId = "6e57d935-4cfb-44af-b1c6-6c399c959452")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CryptEnumKeyIdentifierProperties([In, Optional] IntPtr pKeyIdentifier, [In, Optional] uint dwPropId, CryptKeyIdFlags dwFlags,
+ [Optional, MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName, [In, Optional] IntPtr pvReserved, [In, Optional] IntPtr pvArg,
+ [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum);
+
+ ///
+ /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier.
+ /// If pKeyIdentifier is NULL, the function enumerates all key identifiers.
+ /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier.
+ /// Indicates the property identifier to be listed.
+ /// If dwPropId is set to zero, this function calls the callback function with all the properties.
+ ///
+ /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that
+ /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped.
+ ///
+ /// Any certificate property identifier can be used.
+ ///
+ /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key
+ /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not
+ /// NULL) is searched. For more information, see pwszComputerName.
+ ///
+ ///
+ /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is
+ /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is
+ /// set to NULL.
+ ///
+ /// Reserved for future use and must be NULL.
+ ///
+ /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and
+ /// initialize a structure or argument to hold any information.
+ ///
+ ///
+ /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input
+ /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP.
+ ///
+ ///
+ ///
+ /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier.
+ /// If pKeyIdentifier is NULL, the function enumerates all key identifiers.
+ /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier.
+ ///
+ ///
+ /// Indicates the property identifier to be listed.
+ /// If dwPropId is set to zero, this function calls the callback function with all the properties.
+ ///
+ /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that
+ /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped.
+ ///
+ /// Any certificate property identifier can be used.
+ ///
+ ///
+ /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key
+ /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not
+ /// NULL) is searched. For more information, see pwszComputerName.
+ ///
+ ///
+ /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is
+ /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is
+ /// set to NULL.
+ ///
+ /// A sequence of tuples containing the key identifier and an array of property identifiers and values as byte arrays.
+ public static IEnumerable<(byte[] keyId, (uint propId, byte[] data)[] props)> CryptEnumKeyIdentifierProperties(CRYPTOAPI_BLOB? pKeyIdentifier = null,
+ uint dwPropId = 0, CryptKeyIdFlags dwFlags = CryptKeyIdFlags.CRYPT_KEYID_MACHINE_FLAG, string pwszComputerName = null)
+ {
+ List<(byte[] keyId, (uint propId, byte[] data)[] props)> output = new();
+ using SafeCoTaskMemStruct pKeyId = pKeyIdentifier.HasValue ? new(pKeyIdentifier.Value) : SafeCoTaskMemStruct.Null;
+ Win32Error.ThrowLastErrorIfFalse(CryptEnumKeyIdentifierProperties(pKeyId, dwPropId, dwFlags, pwszComputerName, default, default, fn));
+ return output;
+
+ unsafe bool fn(IntPtr pKeyIdentifier, uint dwFlags, IntPtr pvReserved, IntPtr pvArg, uint cProp, uint[] rgdwPropId, IntPtr[] rgpvData, uint[] rgcbData)
+ {
+ try
+ {
+ var id = pKeyIdentifier == IntPtr.Zero ? null : ((CRYPTOAPI_BLOB*)(void*)pKeyIdentifier)->GetBytes();
+ var props = new (uint propId, byte[] data)[(int)cProp];
+ for (uint i = 0; i < cProp; i++)
+ props[i] = (rgdwPropId[i], rgpvData[i].AsReadOnlySpan((int)rgcbData[i]).ToArray());
+ output.Add((id, props));
+ return true;
+ }
+ catch { }
+ return false;
+ }
+ }
///
/// A pointer to the CRYPT_HASH_BLOB that contains the key identifier.
@@ -686,6 +858,8 @@ namespace Vanara.PInvoke
[StructLayout(LayoutKind.Sequential)]
public struct PUBLICKEYSTRUC
{
+ private byte _bType;
+
///
/// Contains the key BLOB type.
///
@@ -731,7 +905,7 @@ namespace Vanara.PInvoke
///
///
///
- public BlobType bType;
+ public BlobType bType { get => (BlobType)_bType; set => _bType = (byte)bType; }
///
/// Contains the version number of the key BLOB format. For example, if the BLOB is a Digital Signature Standard (DSS) version 3