title: How to export a password-protected private key using MS CryptoAPI?
body: <p>Using Microsoft CryptoAPI, I've generated a new RSA key pair, and am now trying to export the private key to a PKCS#8 encrypted (password-protected) PEM file.</p>
  
  <p>I first investigated CryptExportPKCS8() and CryptExportPKCS8Ex(), but the former doesn't support encrypting the key, and the latter is <a href="http://microsoft.public.platformsdk.security.narkive.com/7sfErwMZ/where-is-cryptexportpkcs8ex#post5" rel="nofollow">not exported by crypt32.dll</a>. MSDN says that both functions have been deprecated anyway.</p>
  
  <p>My current attempt is to pass a session key derived from the password to CryptExportKey():</p>
  
  <pre><code>HCRYPTPROV provider;
  BOOL result = CryptAcquireContext(&amp;provider, CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT);
  HCRYPTKEY keyPair;
  result = CryptGenKey(provider, CALG_RSA_KEYX, (2048 &lt;&lt; 16) | CRYPT_EXPORTABLE, &amp;keyPair);
  
  HCRYPTHASH hash;
  result = CryptCreateHash(provider, CALG_SHA1, 0, 0, &amp;hash);
  const char *password = "password";
  result = CryptHashData(hash, (const BYTE *)password, strlen(password), 0);
  HCRYPTKEY sessionKey;
  result = CryptDeriveKey(provider, CALG_3DES, hash, CRYPT_EXPORTABLE, &amp;sessionKey);
  
  DWORD blobSize;
  result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, NULL, &amp;blobSize);
  BYTE *blobBytes = new BYTE[blobSize];
  result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, blobBytes, &amp;blobSize);
  
  DWORD derSize;
  // This throws "First-chance exception ... Access violation reading ..." and returns FALSE
  result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, NULL, &amp;derSize);
  // error is 3221225477 (0xC0000005)
  DWORD error = GetLastError();
  BYTE *derBytes = new BYTE[derSize];
  result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, derBytes, &amp;derSize);
  
  // ... CryptBinaryToString() to convert to PEM
  
  // ... Write PEM to file
  </code></pre>
  
  <p>All calls succeed up until the commented CryptEncodeObjectEx().</p>
  
  <p>If I don't pass the session key to CryptExportKey() then I can successfully use CryptEncodeObjectEx() to encode the private key, but obviously it is then plain-text.</p>
  
  <p>How can I export a password-protected private key? Is there something wrong with the way I derive the session key? Is PKCS_RSA_PRIVATE_KEY the wrong encoding type?</p>
  
  <p>I've been testing in Visual Studio 2013 on Windows 7.</p>