Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import private key in PEM format using WinCrypt and C++?

I'm trying to use the WinCrypt API in C++.

My application need to cipher, decipher, sign and verify files, and I know how to do that once I have the correct keys. But my problem is actually that that is NOT the same application which generates those keys.

What I have is public and private keys in files in PEM format :

-----BEGIN RSA PRIVATE KEY-----
[Base64 encoded]
-----END RSA PRIVATE KEY-----

And :

-----BEGIN RSA PUBLIC KEY-----
[Base64 encoded]
-----END RSA PUBLIC KEY-----

After some research, I have found how to import the public key : here and here, using the following methods :

  • CreateFile & ReadFile to read the file content
  • CryptStringToBinary, with CRYPT_STRING_BASE64HEADER to convert from PEM format to DER format (remove header and footer and decode from base64)
  • CryptDecodeObjectEx with X509_PUBLIC_KEY_INFO
  • CryptImportPublicKeyInfo, to import the key

But now, my problem is to do the same thing whith the private key. Any help would be really really appreciated :) Thank you.

like image 551
nikloskoda Avatar asked Dec 07 '11 09:12

nikloskoda


2 Answers

A PEM private key can be imported into CAPI by using CryptDecodeObjectEx with PKCS_RSA_PRIVATE_KEY and then calling CryptImportKey.

I have written a sample that shows how to use a PEM encoded RSA private key for signing data using CAPI. Here is a link to it : http://www.idrix.fr/Root/Samples/capi_pem.cpp

I hope this will help.

like image 193
Mounir IDRASSI Avatar answered Sep 23 '22 17:09

Mounir IDRASSI


I ran into this problem with an encrypted private key in PEM format. Here is the process I followed to decrypt and import it:

  1. Decode the PEM using CryptStringToBinaryA with CRYPT_STRING_BASE64HEADER
  2. Decode the ASN.1 data using CryptDecodeObject with PKCS_7_ASN_ENCODING and PKCS_ENCRYPTED_PRIVATE_KEY_INFO
    • This produces some information about how the key is encrypted and the actual encrypted data. In my case, the key came from OpenSSL, and the encryption is described by RFC 8018, Appendix A.4.
    • I had to manually write some code to parse out this structure as it's not natively supported by CryptDecodeObject. You can find that code here.
  3. Once you have the encryption of the private key and the information about how to derive the symmetric key and which algorithm to decrypt it (in my case PBKDF2 and AES-256-CBC):
    1. Use BCryptDeriveKeyPBKDF2 to derive the encryption key from the password
    2. Use BCryptDecrypt to decrypt the private key using the symmetric key derived from the password.
  4. Use CryptDecodeObject with PKCS_7_ASN_ENCODING and PKCS_PRIVATE_KEY_INFO
  5. Use CryptDecodeObject with PKCS_7_ASN_ENCODING and PKCS_RSA_PRIVATE_KEY on the PrivateKey data member produced in the previous step.

The output of this last step is an RSA Private Key BLOB. This can be imported with BCryptImportKeyPair and LEGACY_RSAPRIVATE_BLOB. Again, code demonstrating all of this can be found here.

like image 20
John Tyner Avatar answered Sep 23 '22 17:09

John Tyner