Using the CryptoAPI for Public/Private Data Exchange

.

With the proliferation of the Internet and enterprise
applications that communicate over it, security has become a huge issue. SSL
keeps Web pages secure, but how about an application that can’t use SSL? What
methods are available to application developers who want to keep the transfer of
data secure? If you’re looking for a way to keep you application’s
communications secure, the Microsoft CryptoAPI might be just the thing. In this
article I show you how to use it and show a simple example to illustrate the
salient points.

Cryptography Types

Almost all cryptography algorithms fall into one of two
distinct categories: symmetric or public-key cryptography. Because these two
categories encompass the vast majority of cryptography systems in use today, we
should spend some time discussing the differences between the two types of
algorithms.

Symmetric Algorithms

The family of algorithms classified as symmetric
algorithms are the oldest and most common of the two types. In fact, when most
people think of cryptography, they think of symmetric algorithms, whether they
realize it or not. Symmetric algorithms are based on an encryption operation
that allows the ciphertext (data that has been encrypted) to be decrypted by
simply "rolling back" the encryption operation. A simple substitution
scheme illustrates this.

For the sake of example, let’s assume the following
message needs to be encrypted:

HARRY-GUARDS ARE AT THE CONSULATE. MEET ME AT THE DOCKS
AT 11:45 TONIGHT.

Now let’s assume the encryption key is the number 5. The
algorithm shifts each letter five letters to the right so that the ciphertext
looks like this:

MFWW4-LZFWIX FWJFY YMJ HTSXZQFYJ. RJJY RJ FY YMJ ITHPX
FY 66:90 YTSNLMY.

It doesn’t look much like the original. Because this is
a symmetric algorithm, all that is required to decrypt the data is to roll back
the encryption operation. In this case, all we need do is shift each character
of the ciphertext five letters to the left to recover the data.

The symmetric properties of this algorithm make it very
easy to understand and use. It is this simplicity that also makes substitution
schemes like this very insecure.

Public-Key Cryptography

The other group of widely used algorithms is referred to
as public-key, or asymmetric algorithms. The strength of this  family of
algorithms relies on the fact that the encryption key and decryption key have
nothing in common. In other words, if I possessed both a ciphertext message and
the decryption key, I would not be able to derive the encryption key. This
unique attribute of the encrypt and decrypt keys also makes public-key
cryptography well suited to a number of additional applications besides data
encryption. Public-key cryptography is used to provide digital signatures for
SSL.

Let’s say you possess two keys. One key is kept private
and is used by you to decrypt data. The other key is widely published and can be
used by anyone to encrypt messages that only you can decrypt with you r
privately held key. These keys are commonly referred to as private and public
keys. A private key can only decrypt information that has been encrypted with
its matching public key. No one intercepting the message can decrypt it, and you
don’t have to pass your private key to anyone for then to send you an encrypted
message.

When you send a message, such as an email or Usenet
newsgroup posting, you can "sign" the end of your message by computing
a combination of your private key and the message itself. People who posses a
copy of your public key can use it to determine the validity of the signature.
If they can properly interpret the digital signature, they can be sure the
message came from you and wasn’t altered in transit.

Public-key cryptography is based on some rather complex
mathematics that deal with one-way hash functions. rolling back the operation of
a one-way hash function is extremely difficult. So difficult, in fact, that even
on very powerful computers, such as Cray mainframes, it would take hundreds of
thousands of years to discover the encryption key. The hash function operates in
the "easy" direction when it is encrypting data. We will discuss hash
functions in the next section. For now, just remember that a one-way hash
function is a mathematical operation which is very difficult to roll back. As
the function processes each chunk of plain text, it is generating hash valies.
In order to decrypt the data and roll the operation back, you would need to know
a vital piece of information about the function. This is the private key.

Hash Functions

Let’s move away from our high-level overview and
consider one of the basic building blocks for most secure cryptographic
algorithms: the
hash function. Strictly speaking,
a hash function takes variable length data, such as a text message, and performs
one or more mathematical operations to convert the variable length data into a
fixed length format.

Hash functions are used not only in cryptography, but
also in many other areas of computer science such as checksums and compiler
technology. Hash functions are handy things indeed. Hash functions are so useful
because the function creates a "fingerprint" of the data, or plain
text, it processes. The fingerprint is normally expressed as a number — which
computers are very good at understanding.

As an example, let’s compute a very simple hash
function, using the string "apple". Our function will use the ASCII
values of each character to compute the hash value, as follows:

Character ASCII
Value
ASCII Value
Mod 23
a 97 5
p 112 20
p 112 20
l 108 16
e 101 9

The hash value is computed by taking the ASCII value mod
23. The number 23 was selected because it is a prime number and would produce a
relatively unique hash. The hash value for this string is simply the sum of the
third column. In our example, the hash value is 70. The hash value 70 now
represents the word "apple".

Our simple hash function is not a very good hash
function because it would produce many hash
collisions
. A hash collision is when two different strings produce the same
hash value. Collisions reduce the usefulness and effectiveness of the function
because collisions introduce uncertainty when interpreting the results. A good
hash function is designed to produce a minimal number of collisions.

Researching hash functions is a popular field of study
within the mathematics community. Many mathematicians spend much of their
careers investigating the properties of new and existing hash functions. Part of
the popularity of hash functions can be attributed to their wide range of
applications, including cryptography.

Many of the world’s most secure cryptographic algorithms
rely on very strong hash functions. These functions are so strong that they are
often termed one-way hash functions. This means
there is no easy way to deduce the input value of the function from the output
value, Most functions of this type operate on groups of bits rather than whole
characters. Operating at such a low level allows the hash function to escape
from difficulties such as character-frequency problems.

Microsoft’s CryptoAPI

In an attempt to make cryptography more widespread and
easier for us normal mortals to use in our applications, Microsoft has designed
and released a cryptography API for the Win32 platforms. It is called
CryptoAPI.

CryptoAPI is organized in a modular fashion. Encryption
and decryption services are provided by modules called Cryptographic Service
Providers (CSP). These modules are responsible for implementing different
encryption schemes as well as guaranteeing the security of the
encryption/decryption process. Microsoft has also release a CSP SDK for persons
interested in developing their own CSPs. This information can be accessed at http://www.microsoft.com/security.

For now, let’s look at the structure of CryptoAPI. The
API can be dissected into four discrete sections: key functions,
encryption/decryption functions, hashing functions, and CSP functions. We will
cover the sections of most interst to us: key functions and
encryption/decryption.

Before you can write any code to use the CryptoAPI, you
must establish a set of cryptographic keys for the user and configure a default
CSP. If you skip this step, your calls to CryptoAPI will fail. Microsoft
provides the source code to  utility that sets up the crypto environment.
The utility is called inituser.exe and accompanies MSDN. The following code can
be added to your program to perform the same action as inituser.exe. This may be
better than expecting users to run the inituser.exe utility, especially if this
is an application meant for widespread distribution.


A
function to initialize the crypto settings for a user.

#define _WIN32_WINNT 0x0400
#include "wincrypt.h"
#define ENCRYPT_BLOCK_SIZE 1
#define ENCRYPT_ALGORITHM CALG_RC4

void InitUser( void )
{
 HCRYPTPROV hProv;
 HCRYPTKEY hKey;
 CHAR szUserName[100];
 DWORD dwUserNameLen = sizeof( szUserName );

 // Attempt to acquire a handle to the default key container. 
 if( !CryptAcquireContext( &hProv,
                           NULL,
                           MS_DEF_PROV,
                           PROV_RSA_FULL,
                           0 ) )
 {
  // Some sort of error occured. 

  // Create default key container. 
  if( !CryptAcquireContext( &hProv,
                            NULL,
                            MS_DEF_PROV,
                            PROV_RSA_FULL,
                            CRYPT_NEWKEYSET ) )
   return;

  // Get name of default key container. 
  if( !CryptGetProvParam( hProv,
                          PP_CONTAINER,
                          (unsigned char *) szUserName,
                          &dwUserNameLen, 0 ) )
   // Error getting key container name. 
   szUserName[0] = 0;
 }

 // Attempt to get handle to signature key. 
 if( !CryptGetUserKey( hProv, AT_SIGNATURE, &hKey ) )
 {
  if( GetLastError() == NTE_NO_KEY )
  {
   // Create signature key pair. 
   if( !CryptGenKey( hProv, AT_SIGNATURE, 0, &hKey ) )
    return;
   else
    CryptDestroyKey( hKey );
  }
  else
   return;
 }

 // Attempt to get handle to exchange key. 
 if( !CryptGetUserKey( hProv, AT_KEYEXCHANGE, &hKey ) )
 {
  if( GetLastError() == NTE_NO_KEY )
  {
   // Create key exchange key pair. 

   if( !CryptGenKey( hProv, AT_KEYEXCHANGE, 0, &hKey ) )
    return;
   else
    CryptDestroyKey( hKey );
   }
  else
   return;
 }

 CryptReleaseContext( hProv, 0 );
}

The Demo Application

The demo application is in two parts. One part is an
ISAPI DLL (named CryptoAPI_Auth.dll) that resides on a Web server, and the other
part is an executable program (named ClientDemo.exe) that resides on a client
machine. Note that the DLL compiles to a file named
ApplicationAuth.dll. It was named CryptoAPI_Auth.dll before being copied to the
Web server for this demo just so that the file naming convention on the
sourceDNA.com server would remain consistent.
The DLL contains a
list of three user names and passwords as follows:

User
ID
Password
JOHNPUBLIC MYSELF
JANEDOE COMPUTER
SAMSMITH TENNIS

Ordinarily, user IDs and passwords would be kept in some
sort of database. To keep the demo focused on the topic at hand, I just used an
array of data structures to hold them.

The way the demo works is this:
1. A user runs the client application.
2. The user
types in the User ID and Password.
3. The user clicks on
the Submit button.
4. The client application sends the
User ID to the DLL with an Http request. (The User ID is the public key).
5. The DLL gets the User ID, checks to make sure it’s in
the list, and returns a random number. Normally the random number is saved to a
database for later use. Since there is no database, the random number resides in
the array of data structures in which the User ID and Password exist. The random
numbers are hard-coded for simplicity.
6. The client
application uses the random number it gets from the DLL to encode the User ID
and Password (the private key) and send the encoded data back to the DLL. (The
encrypted value is the hash.) The unencrypted User ID is sent at the same time
to the DLL.
7. The DLL decodes the response by looking
up and using the random number it originally sent.
8.
The decoded response is checked and the validity of the password is verified.
Success or Error are returned. You can see the client application in Figure
1.



Figure 1: The client application after password verticiation.

Conclusion

Now that you have world-class data encryption/decryption
in your arsenal, you’ll be surprised how many times a use for it will arise. And
if you do any contract programming, you’ll be surprised at how many clients will
want you to use the technology.

Microsoft makes it easy to use with the API they’ve
provided. Now all you have to do is supply the imagination to use it in
effective ways.

Downloads

Download demo – 16 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read