PKCS8 files and Windows Crypto API

Parts of the Windows Crypto API are quite well documented (particularly the original CAPI stuff).  Other parts…..

I’ve been trying to get PKCS8 files working between OpenSSL and Windows.  The Import/Export on Windows is so badly documented I eventually resorted to ASN.1 decodes and header file trawls to find what I needed.

Anyway – if you need a password encrypted (using PBE) PKCS8 file that Windows can read, the best you’ll get is PBE-SHA1-3DES.  So once you’ve generated your RSA key (let’s call it rsa.key) then you need to run openssl as follows:

openssl pkcs8 –in ./rsa.key –topk8 –outform DER –out ./key.pk8 –v1 PBE-SHA1-3DES

If you don’t want to have a password – use –nocrypt

Generating something that can go back the other way is just plain difficult.

You need to use NCryptExportKey (BCryptExportKey doesn’t have the capability).  You also need to specify the algorithm OID, parameters and password in the export parameters.

Some code to demonstrate.  It’s messy and it probably won’t compile immediately as I’ve just done a cut and paste – but hopefully it will be useful to someone.

NCryptBufferDesc params, *pparams;
NCryptBuffer buffers[3];
DWORD pkcs8_blob_sz;
unsigned char * pkcs8_blob;
CRYPT_PKCS12_PBE_PARAMS * pbe_params;
unsigned char * salt;

// Generate the parameters
pbe_params = (CRYPT_PKCS12_PBE_PARAMS *)malloc(sizeof(CRYPT_PKCS12_PBE_PARAMS) + 8);
memset(pbe_params, 0, sizeof(CRYPT_PKCS12_PBE_PARAMS) + 8);
salt = (unsigned char *) pbe_params + sizeof(CRYPT_PKCS12_PBE_PARAMS);

// First some random for the salt
if (!NT_SUCCESS(BCryptGenRandom(amp->amp_bcrypt_rng, salt, 8, 0)))
        /* ERROR STUFF HERE */

// Now the params
pbe_params->cbSalt = 8;
pbe_params->iIterations = 2048;

buffers[2].BufferType = NCRYPTBUFFER_PKCS_ALG_PARAM;
buffers[2].cbBuffer = sizeof(CRYPT_PKCS12_PBE_PARAMS) + 8;
buffers[2].pvBuffer = pbe_params;

buffers[1].BufferType = NCRYPTBUFFER_PKCS_ALG_OID;
buffers[1].pvBuffer = szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES;
buffers[1].cbBuffer = strlen(szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES) + 1; // Terminator needed

buffers[0].BufferType = NCRYPTBUFFER_PKCS_SECRET;
buffers[0].pvBuffer = L”PASSWORD”; // Yes you need to replace this :)
buffers[0].cbBuffer = 12; /* Include bytes for the wchar terminator */

params.cBuffers = 3;
params.pBuffers = buffers;
params.ulVersion = NCRYPTBUFFER_VERSION;

pparams = &params;

/* Do the export */
if (NCryptExportKey(ncrypt_master_key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
        pparams, NULL, 0, &pkcs8_blob_sz, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
        /* ERROR CODE HERE */

pkcs8_blob = (unsigned char *)malloc(pkcs8_blob_sz);
if (NCryptExportKey(ncrypt_master_key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB,
        pparams, pkcs8_blob, pkcs8_blob_sz, &pkcs8_blob_sz, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
        /* ERROR CODE HERE */


Leave a Reply