Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I have an application that is creating several keys and storing them in various stores (in this case the Machine store).

How can I enumerate all the keys on a given Windows system?

      CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = containerName + " " + g.ToString() ;
        cspParams.Flags = CspProviderFlags.UseMachineKeyStore;

        // Create a new RSA key and save it in the container.  This key will encrypt
        // a symmetric key, which will then be encryped in the XML document.
        RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
        rsaKey.PersistKeyInCsp = true;
        Console.WriteLine(rsaKey.ToXmlString(false));
        string PublicKeyTest = rsaKey.ToXmlString(false);
share|improve this question
    
Related: these keys may be stored in Client Services Credential Roaming, and may be accessible by LDAP technet.microsoft.com/en-us/library/cc512692 –  makerofthings7 Jun 2 '12 at 14:19

3 Answers 3

up vote 11 down vote accepted

These keys are stored in the locations listed at the bottom of this post. Many network administrators aren't aware of the purpose of these files, and some forum posts on the web incorrectly advise people to delete these files. Of course, the impact of such an action is implementation/application specific. I was not able to read the files using the following code (perhaps some change is needed)

  var files = System.IO.Directory.GetFiles(@"C:\ProgramData\Application Data\Microsoft\Crypto\RSA\MachineKeys\");

        foreach (var f in files)
        {           
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
            var readFile = File.OpenRead(  f.ToString());
            byte[] FileOut = new byte[readFile.Length];
            readFile.Read( FileOut, 0, (int)readFile.Length-1);
            rsaKey.ImportCspBlob(FileOut);

        }

It appears that the tool "User State Migration tool" is required to move this data from one computer to another. In addition some tool will need to expose the keys from CryptoAPI to the CNG after such a move.

I am not aware of any way to view the related files containerName referenced in the CSP.

The Microsoft legacy CryptoAPI CSPs store private keys in the following directories.

User private

%APPDATA%\Microsoft\Crypto\RSA\User SID\ %APPDATA%\Microsoft\Crypto\DSS\User SID\

Local system private

%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\RSA\S-1-5-18\ %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\DSS\S-1-5-18\

Local service private

%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\RSA\S-1-5-19\ %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\DSS\S-1-5-19\

Network service private

%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\RSA\S-1-5-20\ %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\DSS\S-1-5-20\

Shared private

%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\RSA\MachineKeys %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\DSS\MachineKeys

CNG stores private keys in the following directories.

User private
%APPDATA%\Microsoft\Crypto\Keys

Local system private %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\SystemKeys

Local service private %WINDIR%\ServiceProfiles\LocalService

Network service private %WINDIR%\ServiceProfiles\NetworkService

Shared private %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\Keys

Reference:

http://msdn.microsoft.com/en-us/library/bb204778(v=vs.85).aspx

LDAP

These keys are also stored in LDAP if credential roaming is enabled

ldifde.exe -s %LOGONSERVER% -f cscverify.ldf -r "(cn=USERNAME)" -l msPKIAccountCredentials,msPKIRoamingTimeStamp,msPKIDPAPIMasterKeys

Replace the word USERNAME in this command with the user name where credential roaming does not work. To ensure that Active Directory replication was already performed, use the -s option in the command and replace %LOGONSERVER% with the server the user actually logs on to. Make sure that the cscverify.ldf file shows values for the exported attributes.

The size of the LDAP entries is controled by DIMSRoarmingMaxNumTokens and DIMSRoamingMaxTokenSize registry keys (source)

share|improve this answer
3  
There is a tool called KeyPal that will let you view the container names. For example, "KeyPal.exe LM" will show you all the Local Machine key containers. You can download it from jensign.com/KeyPal/index.html –  Jamey Oct 5 '12 at 15:25

The key container name is embedded in the file in ASCII encoding starting at byte 40; its length is stored at byte 8 (but subtract 1). The majority of the files (at least on my system) have a GUID as a container name, in 38-character format including {-}, and have 39 as their 8th byte. The following code will extract the container name from one of these files:

byte[] bytes = File.ReadAllBytes(fileName);<br>
string containerName = Encoding.ASCII.GetString(bytes, 40, bytes[8] - 1);

This container name can then be used to load the details of the key via CspParameters.

share|improve this answer

Some CSP allow for enumerating key containers. You have to do it with native code (C, not C#), and use CryptGetProvParam() with the PP_ENUMCONTAINERS flag. The code looks like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>
#include <wincrypt.h>

static void
usage(void)
{
        fprintf(stderr,
"Usage: enumkeys.exe [ csp ]\n");
        exit(EXIT_FAILURE);
}

static void
failerr(char *funName)
{
        fprintf(stderr, "%s() failed: 0x%08lX\n",
                funName, (unsigned)GetLastError());
        exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
        int size;
        char *csp, buf[1024];
        HCRYPTPROV hprov;
        DWORD flags, buf_len;

        if (argc > 2) {
                usage();
        }
        if (argc > 1) {
                csp = argv[1];
        } else {
                csp = MS_STRONG_PROV_A;
        }
        hprov = 0;
        flags = CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET;
        if (!CryptAcquireContextA(&hprov, NULL, csp, PROV_RSA_FULL, flags)) {
                failerr("CryptAcquireContext");
        }
        buf_len = sizeof buf;
        if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS,
                buf, &buf_len, CRYPT_FIRST))
        {
                if (GetLastError() == ERROR_NO_MORE_ITEMS) {
                        printf("No container.\n");
                        exit(EXIT_SUCCESS);
                } else {
                        failerr("CryptGetProvParam");
                }
        }
        for (;;) {
                printf("Container: '%s'\n", buf);
                buf_len = sizeof buf;
                if (!CryptGetProvParam(hprov, PP_ENUMCONTAINERS,
                        buf, &buf_len, CRYPT_NEXT))
                {
                        if (GetLastError() == ERROR_NO_MORE_ITEMS) {
                                break;
                        }
                        failerr("CryptGetProvParam");
                }
        }
        CryptReleaseContext(hprov, 0);
        return EXIT_SUCCESS;
}

(This code assumes that key container names fit in 1024 bytes; this is not an unreasonable assumption.)

For each key container, you may then want to "open" it and obtain the key type and size; possibly export the public key altogether. This can be done with .NET code (use System.Security.Cryptography.CspParameters to designate a specific key container on a specific CSP).

Important note: not all CSP support such enumeration. In some cases, the set of existing keys is ill-defined, e.g. if the CSP dynamically asks for a user password, and generates a key pair on the fly, with a PRNG seeded from the container name and the password. For such a CSP, the number of "existing" keys (at least in potentia) is virtually infinite, so you won't be able to enumerate them all.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.