September 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Mastering Windows Mobile Crypto API: The Basics

  • November 8, 2005
  • By Alex Gusev
  • Send Email »
  • More Articles »

You will find quite a lot of various algorithms for generating keys in the SDK docs, but not all of them are supported under Windows CE. You may experiment with different methods of key generation to find the one that best suits your needs. All samples in this article use default or CALC_RC2 algorithms.

After you place a file with the desktop public key on the PDA, a handheld can start encryption:

BOOL CEncryptImpl::EncryptData(CFile& fileKey, CFile& fileIn,
                               CFile& fileOut)
{
   BOOL         bResult = TRUE;
   HCRYPTKEY    hSessionKey = NULL;
   HCRYPTKEY    hExternPublicKey = NULL;
   DWORD        dwKeyBlobLen = 0;
   CByteArray   baKeyBlob;
   DWORD        dwCount = 0;
   BOOL         bEOF = 0;
   BYTE         pBuffer[BUFFER_SIZE];
   //////////////////////////////////////////////////////////////
   // 1. Get Random Session Key
   //////////////////////////////////////////////////////////////
   if(!CryptGenKey(m_hProv, CALG_RC2, CRYPT_EXPORTABLE,
                   &hSessionKey) )
   {
      TRACE(_T("Error during CryptGenKey: %Xn"),GetLastError());
      bResult = FALSE;
      goto CleanUp;
   }
   //////////////////////////////////////////////////////////////
   // 2. Obtain external public key
   //////////////////////////////////////////////////////////////
   if( fileKey.Read(&dwKeyBlobLen,sizeof(DWORD)) != sizeof(DWORD) )
   {
      TRACE(_T("Corrupted key file: %Xn"),GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   baKeyBlob.SetSize(dwKeyBlobLen);
   if ( fileKey.Read(baKeyBlob.GetData(),
        dwKeyBlobLen) != dwKeyBlobLen )
   {
      TRACE(_T("Corrupted key file: %Xn"),GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   if( !CryptImportKey(m_hProv,baKeyBlob.GetData(),dwKeyBlobLen,
                       0,0 ,&hExternPublicKey) )
   {
      TRACE(_T("Error during CryptImportKey: %Xn"),GetLastError ());
      return FALSE;
   }
   //////////////////////////////////////////////////////////////
   // 3. Export Session Key
   //////////////////////////////////////////////////////////////
   if(!CryptExportKey(hSessionKey,hExternPublicKey,SIMPLEBLOB,0,
                      NULL,&dwKeyBlobLen))
   {
      TRACE(_T("Error during CryptExportKey-1: %Xn"),GetLastError());
      bResult = FALSE;
      goto CleanUp;
   }
   baKeyBlob.SetSize(dwKeyBlobLen);
   if(!CryptExportKey(hSessionKey,hExternPublicKey,SIMPLEBLOB,0,
      baKeyBlob.GetData(),&dwKeyBlobLen))
   {
      TRACE(_T("Error during CryptExportKey-2: %Xn"),GetLastError());
      bResult = FALSE;
      goto CleanUp;
   }
   fileOut.Write(&dwKeyBlobLen,sizeof(dwKeyBlobLen));
    fileOut.Write(baKeyBlob.GetData(),dwKeyBlobLen);
   //////////////////////////////////////////////////////////////
   // 4. Encode Data
   //////////////////////////////////////////////////////////////
   memset(pBuffer,0,BUFFER_SIZE);
   do
   {
      dwCount = fileIn.Read(pBuffer, BLOCK_SIZE);
      if(dwCount < BLOCK_SIZE)
         bEOF = FALSE;
      else
         bEOF = TRUE;
      if (!CryptEncrypt (hSessionKey, 0, !bEOF, 0,
                         pBuffer, &dwCount, BUFFER_SIZE) )
      {
         TRACE(_T("Error during CryptEncrypt: %Xn"),GetLastError());
         bResult = FALSE;
         goto CleanUp;
      }
      fileOut.Write (pBuffer, dwCount );
   }
   while (bEOF);
   fileOut.Flush();
   //////////////////////////////////////////////////////////////
   // 5. Clean up
   //////////////////////////////////////////////////////////////
CleanUp:
   if ( hSessionKey )
      CryptDestroyKey (hSessionKey);
   if ( hExternPublicKey )
      CryptDestroyKey (hExternPublicKey);
   return bResult;
}

The desktop's public key is imported into the device's CSP and then the device's session key is exported to the encrypted file. This will allow a receiver to read it at the desktop and import into the desktop's CSP to perform a successful decryption. Please pay attention to the CryptEncrypt function. It takes several parameters that control its behavior. Usually, an encrypted message will require a bigger buffer than the original one, so you have to take care of the appropriate allocations.

The decryption process is similar to encryption:

BOOL CEncryptImpl::DecryptData(CFile& fileIn, CFile& fileOut)
{
   BOOL         bResult = TRUE;
   CRYPTKEY     hSessionKey = NULL;
   HCRYPTKEY    hPublicKey = NULL;
   DWORD        dwKeyBlobLen = 0;
   CByteArray   baKeyBlob;
   DWORD        dwCount = 0;
   BOOL         bEOF = 0;
   BYTE         pBuffer[BUFFER_SIZE];
   //////////////////////////////////////////////////////////////
   // 1. Obtain external public key
   //////////////////////////////////////////////////////////////
   if( fileIn.Read(&dwKeyBlobLen,sizeof(DWORD)) != sizeof(DWORD) )
   {
      TRACE(_T("Corrupted key file: 0x%Xn"),GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   baKeyBlob.SetSize(dwKeyBlobLen);
   if ( fileIn.Read(baKeyBlob.GetData(),
        dwKeyBlobLen) != dwKeyBlobLen )
   {
      TRACE(_T("Corrupted key file: 0x%Xn"),GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   if(!CryptGetUserKey(m_hProv,AT_KEYEXCHANGE,&hPublicKey))
   {
      TRACE(_T("CryptGetUserKey: 0x%Xn"),GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   if( !CryptImportKey(m_hProv,baKeyBlob.GetData(),dwKeyBlobLen,
                       hPublicKey,0,&hSessionKey) )
   {
      TRACE(_T("Error during CryptImportKey: 0x%Xn"),GetLastError ());
      return FALSE;
   }
   // Encrypt the source file and write to the destination file.
   do
   {
      // Read up to BLOCK_SIZE bytes from the source file.
      dwCount = fileIn.Read(pBuffer, BLOCK_SIZE);
      if(dwCount < BLOCK_SIZE)
         bEOF = FALSE;
      else
         bEOF = TRUE;
      // Decrypt the data.
      if ( !CryptDecrypt(hSessionKey, 0, !bEOF, 0,
                         pBuffer, &dwCount) )
      {
         TRACE(_T("Error during CryptDecrypt: 0x%Xn"),GetLastError());
         bResult = FALSE;
         goto CleanUp;
      }
      // Write the data to the destination file.
      fileOut.Write (pBuffer, dwCount );
   }
   while (bEOF);
   fileOut.Flush();
CleanUp:
   if ( hSessionKey )
      CryptDestroyKey (hSessionKey);
   return bResult;
}

All you need to do is to read and import the session key and then perform decryption.

Conclusion

This article very briefly covered the basics of Crypto API. Now, you have a good basis for your own experiments with different encryption techniques. You haven't yet learned how to sign and verify an encrypted message, but hopefully, the next article will deal with signatures and certificates.

Download

Download the accompanying code's zip file here.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.





Page 3 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel