October 21, 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 »

Encryption and Decryption Using Password

Start with the simplest case: encoding and decoding strings using a password as a base for the encryption key. The following sample illustrates a common working flow during encryption and decryption:

#define ENCRYPT_ALG      CALG_RC4
#define ENCRYPT_KEY      "Dev@@Test"
...
/////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////
BOOL CEncryptImpl::Encrypt(const char* pszInData,
                           char* pszOutData, BOOL bEncrypt)
{
   if (!m_bInitOK)
      return FALSE;
   BOOL         bResult = TRUE;
   HKEY         hRegKey = NULL;
   HCRYPTPROV   hProv = NULL;
   HCRYPTKEY    hKey = NULL;
   HCRYPTKEY    hXchgKey = NULL;
   HCRYPTHASH   hHash = NULL;
   DWORD        dwLength;
   CByteArray arBuffer;
   char         szTemp [1024] = "";
   // Get handle to user default provider.
   if ( !CryptAcquireContext (& hProv, NULL, NULL,
       PROV_RSA_FULL, 0) )
   {
      TRACE(L"CryptAcquireContext returned errorn");
      return FALSE;
   }
   // Create hash object.
   if ( !CryptCreateHash (hProv, CALG_MD5, 0, 0, &hHash) )
   {
      bResult = FALSE;
      goto CleanUp;
   }
   // Hash password string.
   dwLength = sizeof (char) * strlen (ENCRYPT_KEY);
   if ( !CryptHashData(hHash, (BYTE *) ENCRYPT_KEY, dwLength, 0) )
   {
      bResult = FALSE;
      goto CleanUp;
   }
   // Create block cipher session key based on hash of the password.
   if ( !CryptDeriveKey (hProv, ENCRYPT_ALG, hHash,
                         CRYPT_EXPORTABLE, &hKey))
   {
      bResult = FALSE;
      goto CleanUp;
   }
   // Determine number of bytes to encrypt at a time.
   dwLength = sizeof (char) * strlen (pszInData);
   arBuffer.SetSize(dwLength);
   if (arBuffer.GetSize())
   {
      memcpy (arBuffer.GetData(), pszInData, dwLength);
      if ( bEncrypt )
      {
         // Encrypt data
         if ( !CryptEncrypt (hKey, 0, TRUE, 0, arBuffer.GetData(),
                             &dwLength, dwLength) )
         {
            bResult = FALSE;
            goto CleanUp;
         }
         BYTE* pb = (BYTE*) arBuffer.GetData();
         int b;
         for (DWORD i = 0; i < dwLength; i ++)
         {
            b = (*pb & 0xF0) >> 4;
            *pszOutData++ = (b <= 9) ? b + _T('0') : b - 10 +
                             _T('A');
            b = *pb & 0x0F;
            *pszOutData++ = (b <= 9) ? b + _T('0') : b - 10 +
                             _T('A');
         pb++;
         }
         *pszOutData++ = 0;
      }
      else
      {
         strcpy (szTemp, pszInData);
         if (! CryptDecrypt (hKey, 0, TRUE, 0, (BYTE *) szTemp,
             &dwLength))
         {
         bResult = FALSE;
         }
         strcpy (pszOutData, szTemp);
      }
   }
CleanUp:
   if ( hKey )
      CryptDestroyKey (hKey);
   if ( hHash )
      CryptDestroyHash (hHash);
   if ( hProv )
      CryptReleaseContext (hProv, 0);
   return bResult;
}

So, a regular work flow is as follows:

  • Connect to CSP to obtain its handle
  • Create a hash object with given algorithm
  • Fill it in with data based on the provided password
  • Create an encryption session key derived from hash object
  • Perform the actual encryption
  • Optionally, you can convert binary representation into strings as it was done in the sample above
  • Destroy the session key and hash, and release the CSP handle

Thus, if all parts of your application keep the same 'password' to create the session key, you may secure your data easily. The samples above deal with C strings, but you can modify it to work with arbitrary binary data with minimal effort.

Using Public-Key Encryption

This method gives you more flexibility and strength. The main difference from a 'password'-based technique is that you create a pair of keys: public and private for given container. The keys are mathematically linked, so to encrypt/decrypt some data you need both of them.

A typical scenario in this case follows. Suppose you want to create an encrypted message and send it over an unsecured network. Thus, you have a sender and a receiver of the message. The very first thing to do is to generate a pair of public/private keys at the receiver side and export the receiver's public key. This public key will be used later at the sender's side during message encryption. Crypto API allows exporting keys from CSP to to a binary large object (BLOB), so this data can be easily saved and transmitted.

If the sender has a public key of the receiver, it can make an encryption. Thus, data is encrypted by the sender using the receiver's public key (remember that the private and public keys are mathematically linked!) and decrypted by the receiver with its own private key. That's why such an encryption method is called 'asymmetric'. Obviously, they both have to utilize the same crypto provider. In the real world, the sender and the receiver may use asymmetric encoding to transmit the secret key (for 'symmetric' encryption), and then use it for the rest of an interactive session.

Coming back to the code, the very first step is to export public keys. For simplicity, consider a PDA-to-desktop encryption flow, so the desktop part has to export its public key:

BOOL CEncryptImpl::ExportKey(CFile& fileKey)
{
   BOOL         bResult = TRUE;
   HCRYPTKEY    hPublicKey = NULL;
   DWORD        dwKeyBlobLen = 0;
   CByteArray   baKeyBlob;
   if( !CryptGenKey(m_hProv,AT_KEYEXCHANGE,0,&hPublicKey))
   {
      TRACE(_T("Error during CryptGenKey: %Xn"),GetLastError());
      bResult = FALSE;
      goto CleanUp;
   }
   if(!CryptExportKey(hPublicKey,0,PUBLICKEYBLOB,0,NULL,
                      &dwKeyBlobLen))
   {
      TRACE(_T("Error during CryptExportKey-1: %Xn"),
            GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   baKeyBlob.SetSize(dwKeyBlobLen);
   if(!CryptExportKey(hPublicKey,0,PUBLICKEYBLOB,0,
      baKeyBlob.GetData(),&dwKeyBlobLen) )
   {
      TRACE(_T("Error during CryptExportKey-2: %Xn"),
            GetLastError ());
      bResult = FALSE;
      goto CleanUp;
   }
   fileKey.Write(&dwKeyBlobLen,sizeof(dwKeyBlobLen));
   fileKey.Write(baKeyBlob.GetData(),dwKeyBlobLen);
CleanUp:
   if ( hPublicKey )
      CryptDestroyKey (hPublicKey);
   return bResult;
}




Page 2 of 3



Comment and Contribute

 


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

 

 


Sitemap | Contact Us

Rocket Fuel