Mastering Windows Mobile Crypto API: The Basics
Where to Start...
Encryption and decryption is a pretty wide area, so nobody could cover it in one single article. No doubt, it would take a good heavy book to describe all basics of cryptology theory. Fortunately, for day-to-day tasks you don't need to study this in detail; Microsoft has done the hard job for you. So, here comes Crypto API, which is available in both handheld device and desktop versions. Hence, I won't discuss any specific encryption/decryption algorithm but rather dig in into practical scenarios you might face during application development.
There are two common methods I will overview: symmetric and asymmetric (which is also called public-key). The symmetric encryption technique is "the simplest" one. You have to use the same key to both encrypt and decrypt your data. This key is kept secret. Asymmetric encoding uses two keys: public and private. As in the previous case, the private key is not available outside your application, but the public key can be freely distributed among all target parties in question.
A Bit of Terminology
The following tasks can be performed through Crypto API:
- Generate cryptographic keys
- Export cryptographic keys
- Encrypt/Decrypt the data
- Create digital signatures
- Connect to a CSP
Regardless of the given CSP, data encryption itself is done using symmetric algorithms. Windows Mobile SDK documentation provides a lot of detailed info about Crypto API, so I forward you there for additional explanation. You now will move on to samples.
Enumerating Available CSPs
Prior to doing the coding, you should meet CSP face to face. In other words, you need to enumerate all CSPs installed on the device:
void CEncryptionDlg::OnButtonEnum()
{
CFile file;
if ( !file.Open(_T("\Providers.txt"),
CFile::modeCreate | CFile::modeWrite) )
return;
DWORD cbName;
LPTSTR pszName = NULL;
DWORD dwIndex = 0;
DWORD dwType;
DWORD dwErr;
char szInfo[1024];
BOOL bRet = FALSE;
strcpy(szInfo,"Providersrn");
file.Write(szInfo,strlen(szInfo));
while((bRet = CryptEnumProviders(
dwIndex,
NULL,
0,
&dwType,
NULL,
&cbName
)))
{
pszName = new TCHAR[cbName];
if (CryptEnumProviders(
dwIndex++,
NULL,
0,
&dwType,
pszName,
&cbName
))
{
char szName[255];
memset(szName,0,sizeof(szName));
WideCharToMultiByte(CP_ACP,0,pszName,_tcslen(pszName),
szName,sizeof(szName),0,0);
sprintf(szInfo,"Type %4.0d name %srn",dwType, szName);
file.Write(szInfo,strlen(szInfo));
}
else
{
if (ERROR_NO_MORE_ITEMS != (dwErr = GetLastError()))
{
TRACE(_T("Error during CryptEnumProvider"),
GetLastError ());
}
}
delete [] pszName;
}
}
This code snippet enumerates all available CSPs and stores their names in a text file. You can use these names later to identify a specific provider, if you need to.
CSP Providers and Containers
The starting point of any encryption or decryption is obtaining a handle of CSP provider. CryptAcquireContext does all the required job for you. Every CSP provider may have several 'containers' or 'users,' so it's important to specify a correct container name at both the sender and receiver sides to make cryptographic keys exchange successful. A code snippet below tries to get a CSP context and create a new one in case a given container doesn't exist yet:
BOOL CEncryptImpl :: Setup ()
{
// Ensure that the default cryptographic client is set up.
HCRYPTKEY hKey;
// Attempt to acquire a handle to the key container.
if (! CryptAcquireContext(&m_hProv, m_sContainer,
MS_DEF_PROV, PROV_RSA_FULL, 0))
{
// Some sort of error occured, create default key container.
if (! CryptAcquireContext (&m_hProv, m_sContainer, MS_DEF_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
// Error creating key container!
return FALSE;
}
}
// Attempt to get handle to signature key.
if (! CryptGetUserKey (m_hProv, AT_SIGNATURE, &hKey))
{
if (NTE_NO_KEY == GetLastError ())
{
// Create signature key pair.
if (! CryptGenKey (m_hProv, AT_SIGNATURE, 0, &hKey))
{
// Error during CryptGenKey!
return FALSE;
}
else
{
CryptDestroyKey (hKey);
}
}
else
{
// Error during CryptGetUserKey!
return FALSE;
}
}
// Attempt to get handle to exchange key.
if (! CryptGetUserKey (m_hProv, AT_KEYEXCHANGE, &hKey))
{
if (NTE_NO_KEY == GetLastError ())
{
// Create key exchange key pair.
if (! CryptGenKey (m_hProv, AT_KEYEXCHANGE, 0, &hKey))
{
// Error during CryptGenKey!
return FALSE;
}
else
{
CryptDestroyKey (hKey);
}
}
else
{
// Error during CryptGetUserKey!
return FALSE;
}
}
m_bInitOK = TRUE;
return TRUE;
}
As you can see, all it does is query a specified CSP/container pair and create new ones if needed.
Page 1 of 3
