Some time ago I've posted a simple code example that will retrieve registered CSPs: Get registered CSPs on the system. The code was updated to provide detailed information about supported algorithms and protocols by particular CSP. Updated version of this code is shipped with my PowerShell PKI module as a Get-CryptographicServiceProvider cmdlet. The output is pretty informative:

PS C:\> $CSP[1]

Name                                          Type                                     SupportedAlgorithms
----                                          ----                                     -------------------
Microsoft Base Cryptographic Provider v1.0    RSA Full (Signature and Key Exchange)    {RC2, RC4, DES, SHA-1...}


PS C:\> $CSP[1].SupportedAlgorithms

Name                 DefaultKeyLength MinKeyLength     MaxKeyLength     Protocols
----                 ---------------- ------------     ------------     ---------
RC2                  40               40               56
RC4                  40               40               56
DES                  56               56               56
SHA-1                160              160              160              {Signing protocol}
MD2                  128              128              128              {Signing protocol}
MD4                  128              128              128              {Signing protocol}
MD5                  128              128              128              {Signing protocol}
SSL3 SHAMD5          288              288              288
MAC                  0                0                0
RSA_SIGN             512              384              16384            {Internet protocol security (IPsec) protocol...
RSA_KEYX             512              384              1024             {Internet protocol security (IPsec) protocol...
HMAC                 0                0                0


PS C:\>

However existing code is limited to legacy CSPs and do not support any CNG (Cryptography Next Generation) CSPs. To address this limitation I wrote another function for CNG providers. As usually the code uses p/invoke to get required information:

$ncryptsignature = @'
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern uint NCryptEnumStorageProviders(
    ref uint pImplCount,
    ref IntPtr ppImplList,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern uint NCryptOpenStorageProvider(
    ref IntPtr phProvider,
    [MarshalAs(UnmanagedType.LPWStr)] string pszProviderName,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern uint NCryptEnumAlgorithms(
    IntPtr hProvider,
    uint dwAlgOperations,
    ref int pdwAlgCount,
    ref IntPtr ppAlgList,
    uint dwFlags
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern uint NCryptFreeBuffer(
    IntPtr pvInput
);
[DllImport("ncrypt.dll", SetLastError = true)]
public static extern uint NCryptFreeObject(
    IntPtr phProvider
);

[StructLayout(LayoutKind.Sequential)]
public struct NCryptProviderName {
    [MarshalAs(UnmanagedType.LPWStr)] public string pszName;
    [MarshalAs(UnmanagedType.LPWStr)] public string pszComment;
};
[StructLayout(LayoutKind.Sequential)]
public struct NCryptAlgorithmName {
    [MarshalAs(UnmanagedType.LPWStr)] public string pszName;
    public uint dwClass;
    public uint dwAlgOperations;
    public uint dwFlags;
};
'@

Add-Type @'
namespace PKI {
    namespace ServiceProviders {
        public class CspCNG {
            public string Name;
            public string Comments;
            public ALG_ID_CNG[] SupportedAlgorithms;
        }
        public class ALG_ID_CNG {
            public string Name;
            public string Interface;
            public string[] Operations;
        }
    }
}
'@
try {Add-Type -MemberDefinition $ncryptsignature -Namespace PKI -Name nCrypt}
catch {$NoCNG = $true; return}

#region enumerations
    $Interface = @{3 = "Asymmetric encryption"; 4 = "Secret agreement";
        5 = "Signature interface"; 0x00010001 = "Key storage interface"; 0x00010002 = "SChannel interface";
        0x00010003 = "SChannel signature interface"}
#endregion

[UInt32]$pImplCount = 0
[IntPtr]$ppImplList = [IntPtr]::Zero
$Return = [PKI.nCrypt]::NCryptEnumStorageProviders([ref]$pImplCount,[ref]$ppImplList,0)
if (!$Return) {
$pvInput = $ppImplList
    $Names = $(for ($n = 0; $n -lt $pImplCount; $n++) {
        [Runtime.InteropServices.Marshal]::PtrToStructure($ppImplList,[Type][PKI.nCrypt+NCryptProviderName])
        [IntPtr]$ppImplList = [int]$ppImplList + [Runtime.InteropServices.Marshal]::SizeOf([Type][PKI.nCrypt+NCryptProviderName])
    }) | %{$_.pszName}
    [void][PKI.nCrypt]::NCryptFreeBuffer($pvInput)
} else {Write-Warning "The handle is invalid."}
foreach ($pszProviderName in $Names) {
    $CSP = New-Object PKI.ServiceProviders.CspCNG
    $CSP.Name = $pszProviderName
    [IntPtr]$phProvider = [IntPtr]::Zero
    $Return = [PKI.nCrypt]::NCryptOpenStorageProvider([ref]$phProvider,$pszProviderName,0)
    if (!$Return) {
        $pdwAlgCount = 0
        $ppAlgList = [IntPtr]::Zero
        $dwAlgOperations = 0x0
        $Return = [PKI.nCrypt]::NCryptEnumAlgorithms($phProvider,$dwAlgOperations,[ref]$pdwAlgCount,[ref]$ppAlgList,0)
        if (!$Return) {
            $pvInput = $ppAlgList
            for ($n = 0; $n -lt $pdwAlgCount; $n++) {
                $AlgID = [Runtime.InteropServices.Marshal]::PtrToStructure($ppAlgList,[Type][PKI.nCrypt+NCryptAlgorithmName])
                $options = 4,8,16 | %{[int]$AlgID.dwAlgOperations -band $_} | ?{$_}
                $Alg = New-Object PKI.ServiceProviders.ALG_ID_CNG -Property @{
                    Name = $AlgID.pszName
                    Interface = $Interface[[int]$AlgID.dwClass]
                    Operations = switch ($options) {
                        4 {"Asymmetric encryption"}
                        8 {"Secret agreement"}
                        16 {"Signature"}
                    }
                }
                $CSP.SupportedAlgorithms += $Alg
                [IntPtr]$ppAlgList = [int]$ppAlgList + [Runtime.InteropServices.Marshal]::SizeOf([Type][PKI.nCrypt+NCryptAlgorithmName])
            }
            $CSP
            [void][PKI.nCrypt]::NCryptFreeBuffer($pvInput)
        } else {Write-Warning "Parameter is incorrect."}
        [void][PKI.nCrypt]::NCryptFreeObject($phProvider)
    } else {Write-Warning "The handle is invalid."}
}

And here is output information:

PS C:\> $CSP = Get-CSP
PS C:\> $CSP

Name                                    Comments                                SupportedAlgorithms
----                                    --------                                -------------------
Microsoft Software Key Storage Provider                                         {RSA, DH, DSA, ECDH_P256...}
Microsoft Smart Card Key Storage Pro...                                         {RSA, ECDH_P256, ECDH_P384, ECDH_P52...

PS C:\> $CSP[0].SupportedAlgorithms

Name                                    Interface                               Operations
----                                    ---------                               ----------
RSA                                     Asymmetric encryption                   {Asymmetric encryption, Signature}
DH                                      Secret agreement                        {Secret agreement}
DSA                                     Signature interface                     {Signature}
ECDH_P256                               Secret agreement                        {Secret agreement, Signature}
ECDH_P384                               Secret agreement                        {Secret agreement, Signature}
ECDH_P521                               Secret agreement                        {Secret agreement, Signature}
ECDSA_P256                              Signature interface                     {Signature}
ECDSA_P384                              Signature interface                     {Signature}
ECDSA_P521                              Signature interface                     {Signature}

PS C:\>

Currently Microsoft provides only 2 CNG crypto providers: Microsoft Software Key Storage Provider and Microsoft Smart Card Key Storage Provider. I'll include this sample to my PS PKI module next release.


Share this article:

Comments:

mluckham

Many thanks for the post, but it didn't work well enough for me - these worked better. C# http://technet.microsoft.com/en-us/library/ff182308(v=ws.10).aspx // Investigating the Advanced Cryptographic Algorithms C++ Equivalent http://msdn.microsoft.com/en-us/library/windows/desktop/bb931371(v=vs.85).aspx // Enumerating Installed Providers

Vadims Podans

Legacy CSPs are discussed here: http://en-us.sysadmins.lv/Lists/Posts/Post.aspx?ID=37 as I have to support Windows Server 2003/XP machines as well, your link won't work for me, as they utilize CertEnroll interfaces which are not available on legacy systems. I will move to CertEnroll once I don't have legacy system support.

Slogmeister Extraordinaire
The script generates the following error in several places: "The specified structure must be blittable or have layout information. Parameter name: structure" The following lines need to be changed as such: [Runtime.InteropServices.Marshal]::PtrToStructure($ppImplList,[PKI.nCrypt+NCryptProviderName]) [System.Runtime.InteropServices.Marshal]::PtrToStructure($ppImplList,[System.Type] [PKI.nCrypt+NCryptProviderName]) [IntPtr]$ppImplList = [int]$ppImplList + [Runtime.InteropServices.Marshal]::SizeOf([PKI.nCrypt+NCryptProviderName]) [IntPtr]$ppImplList = [int]$ppImplList + [Runtime.InteropServices.Marshal]::SizeOf([System.Type] [PKI.nCrypt+NCryptProviderName]) $AlgID = [Runtime.InteropServices.Marshal]::PtrToStructure($ppAlgList,[PKI.nCrypt+NCryptAlgorithmName]) $AlgID = [Runtime.InteropServices.Marshal]::PtrToStructure($ppAlgList,[System.Type] [PKI.nCrypt+NCryptAlgorithmName]) [IntPtr]$ppAlgList = [int]$ppAlgList + [Runtime.InteropServices.Marshal]::SizeOf([PKI.nCrypt+NCryptAlgorithmName]) [IntPtr]$ppAlgList = [int]$ppAlgList + [Runtime.InteropServices.Marshal]::SizeOf([System.Type] [PKI.nCrypt+NCryptAlgorithmName]) A further explanation can be found here: https://support.microsoft.com/en-us/kb/2909958
Vadims Podāns

yes, I''m aware about this change. The code was posted for previous versions of .NET (prior to these changes).


Post your comment:

Please, solve this little equation and enter result below. Captcha