EncryptingDecrypting Data through PFX certificate on Windows Mobile

Some time ago I worked with a colleague of mine, a proud member of the CSS for Developers (Alejandro Campos Magencio) on a case where the developer wanted to encrypt and decrypt data on Windows Mobile 5.0 devices by using PFX certificates enrolled on the device. Crypto APIs are quite limited on this platform, however by using some basic (i.e. supported) APIs we were able to reach a satisfactory solution.

In very few words, PFX certificates contain a pair of public and private key: through the public you can encrypt, through the private you can decrypt. But... first of all, you need to register the certificate on the device's ROOT or Personal store. On Windows Mobile 6, an enroller was added to the platform therefore you can register PFX certificate by simply tapping on it, as it was already with .CER files on previous versions of the OS; but on Windows Mobile 5.0, you can't add a PFX certificate by doing so, nor you can use the documented way to add certificates by using the CertificateStore Configuration Service Provider, because contrarily to CER certificates, you can't export a .PFX to a Base-64 encoded X.509 stream (see Creating a Provisioning XML Document For The Root Certificate).

So, how to add a PFX certificate to the ROOT store of a Windows Mobile 5.0-based device? The answer is: develop your own enroller. Or, find out if anyone else already did it... and a sample 3rd party enroller for .PFX files is the one described by Personal Certificate Import Utility for Pocket PC 2003 and Windows Mobile, which seems to be still valid for 5.0 as well. You can also use directly that 3rd party open-source product if you want, but in case you’ll have problems we couldn’t be able to support as this is not a Microsoft product.

In any case, remember that "[…] Whether a root certificate can be installed on the device depends on how the device was configured by the original equipment manufacturer (OEM) or by the Mobile Operator", in terms of Security Configuration (this was an excerpt from the KB Article How to install root certificates on a Windows Mobile-based device), so if you can't even install the SDK Certificates, for example, then you have a locked device and therefore you should ask you OEM or Mobile Operator how they require you to install new certificates, if they even provide this opportunity.

Recommended readings:

Finally, here it is some pseudo-code (provided 'AS IS', for didactic purposes, no error-checking and no example data included - just look at which Crypto APIs are needed):

- for encrypting:

 // Variables
HCERTSTORE hStoreHandle = NULL;
PCCERT_CONTEXT pSubjectCert = NULL;
HCRYPTKEY hPubKey = NULL;
wchar_t * SubjectName;
DWORD dwEncryptedLen = 0;
BYTE* pbData = NULL;

// Open the certificate store
hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, NULL);

// Get a certificate that matches the search criteria
pSubjectCert = CertFindCertificateInStore(hStoreHandle, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, SubjectName, pSubjectCert);

// Get the CSP
bResult = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

// Get the public key from the certificate
bResult = CryptImportPublicKeyInfoEx(hCryptProv, X509_ASN_ENCODING, &pSubjectCert->pCertInfo->SubjectPublicKeyInfo, CALG_RSA_KEYX, 0, NULL, &hPubKey);

// Get lenght for encrypted data
bResult = CryptEncrypt(hPubKey, NULL, TRUE, 0, NULL, &dwEncryptedLen, 0);

// Create a buffer for encrypted data
pbData = (BYTE *)malloc(pbData, dwEncryptedLen);
    
// Encrypt data
bResult = CryptEncrypt(hPubKey, NULL, TRUE, 0, pbData, &dwEncryptedLen, dwEncryptedLen);

//CertFreeCertificateContext
//CertCloseStore

 

- for decrypting:

 // Variables
HCERTSTORE hStoreHandle = NULL;
PCCERT_CONTEXT pSubjectCert = NULL;
wchar_t * SubjectName;
HCRYPTPROV* phCryptProv = NULL;
DWORD* pdwKeySpec = NULL;
BOOL* pfCallerFreeProv = NULL;
HCRYPTKEY* phPrivateKey;
DWORD dwEncryptedLen = 0;
BYTE* pbData = NULL;

// Open the certificate store
hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, NULL);

// Get a certificate that matches the search criteria
pSubjectCert = CertFindCertificateInStore(hStoreHandle, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, SubjectName, pSubjectCert);

// Acquire the Private Key
bResult = CryptAcquireCertificatePrivateKey(pSubjectCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &phCryptProv, &pdwKeySpec, &pfCallerFreeProv);

// Get Private Key
bResult = CryptGetUserKey(phCryptProv, AT_KEYEXCHANGE, &phPrivateKey);
 
// Decrypt data
bResult = CryptDecrypt(phPrivateKey, 0, TRUE, 0, &pbData, &dwEncryptedLen);


//CertFreeCertificateContext
//CertCloseStore

 

Other sample code is available from MSDN, not specific to PFX Certificates:

 

Cheers,

~raffaele