Sender Code Example

This section shows the code needed on the sender's side to implement the three-phase key exchange protocol. The details of the communication between the sender and the receiver are not shown, because these will be different for each implementation.

For purposes of readability, this example and the following one, diverge from good programming practice in two major ways.

#include <wincrypt.h>

HCRYPTPROV hProv = 0;

#define NAME_SIZE 256
BYTE pbDestName[NAME_SIZE];
DWORD dwDestNameLen;
BYTE pbSendName[NAME_SIZE];
DWORD dwSendNameLen;

HCRYPTKEY hDestPubKey = 0;
HCRYPTKEY hKeyA = 0;
HCRYPTKEY hKeyB = 0;

#define BLOB_SIZE 256
BYTE pbKeyBlob[BLOB_SIZE];
DWORD dwBlobLen;

#define HASH_SIZE 256
BYTE pbHash[HASH_SIZE];
DWORD dwHashLen;
BYTE pbDestHash[HASH_SIZE];
DWORD dwDestHashLen;
HCRYPTHASH hHash = 0;

// Get a handle to the default provider.
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);

// Obtain the receiver's exchange public key. Import it into
// the CSP and place a handle to it in 'hDestPubKey'.
...
// Obtain the receiver's name. This is usually done at the
// same time as the public key was obtained. Place this in 
// 'pbDestName' and set 'dwDestNameLen' to the number of bytes in 
// the name.
...

// Place the sender's name in 'pbSendName' and set 
// 'dwSendNameLen' to the number of bytes in it.
...

// Create a random session key (session key A). Because this key will
// be used solely for key exchange and not encryption, it 
// does not matter which algorithm you specify here.
CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyA);

// Export session key A into a simple key blob.
dwBlobLen = BLOB_SIZE;
CryptExportKey(hKeyA, hDestPubKey, SIMPLEBLOB, 0, pbKeyBlob,
                 &dwBlobLen);

// Send the key blob containing session key A to the receiver.
...

// Wait for the receiver to respond.
...

// Receive a key blob containing session key B from the 
// receiver and place it in 'pbKeyBlob'. Set 'dwBlobLen' to 
// the number of bytes in the key blob.
...

// Receive a hash value from the receiver and place it in
// 'pbHashValue'. Set 'dwHashLen' to the number of bytes in the hash 
// value.
...

// Import the key blob into the CSP.
CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyB);

//
// Verify the hash value received from the receiver.
//

// Create a hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key A to the hash.
CryptHashSessionKey(hHash, hKeyA, 0);

// Add the receiver's  name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);

// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add "phase 2" text to the hash.
CryptHashData(hHash, "phase 2", 7, 0);

// Complete the hash computation, and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash);

//
// Compare the hash value received from the receiver with 
// the hash value that we just computed. If they do not match, then 
// terminate the protocol.
//

if(dwHashLen!=dwDestHashLen || memcmp(pbHash, pbDestHash, dwHashLen)) {
    printf("Key exchange protocol failed in phase 2!\n");
    printf("Aborting protocol!\n");
    return;
}

//
// Compute the hash to be sent to the receiver.
//

// Create the hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);

// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add the receiver's name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add "phase 3" text to the hash.
CryptHashData(hHash, "phase 3", 7, 0);

// Complete the hash computation and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash);

// Send the hash value to the receiver.
...

//
// Use session key A to encrypt messages sent to the receiver.
// Use session key B to decrypt messages received from the receiver.
//
...

// Destroy the session keys.
CryptDestroyKey(hKeyA);
CryptDestroyKey(hKeyB);

// Release provider handle.
CryptReleaseContext(hProv, 0);