This section illustrates the code needed on the receiver 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.
#include <wincrypt.h>
HCRYPTPROV hProv = 0;
#define NAME_SIZE 256
BYTE pbDestName[NAME_SIZE];
DWORD dwDestNameLen;
BYTE pbSendName[NAME_SIZE];
DWORD dwSendNameLen;
HCRYPTKEY hSendPubKey = 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 pbSendHash[HASH_SIZE];
DWORD dwSendHashLen;
HCRYPTHASH hHash = 0;
// Get a handle to the default provider.
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
// Obtain the sender's exchange public key. Import it into the
// CSP and place a handle to it in 'hSendPubKey'.
...
// Obtain the sender's name. This is usually done at the
// same time the public key was obtained. Place this in
// 'pbSendName' and set 'dwSendNameLen' to the number of bytes in
// the name.
...
// Place the receiver's name in 'pbDestName' and set
// 'dwDestNameLen' to the number of bytes in the name.
...
// Receive a key blob containing session key A from the sender
// and place it in 'pbKeyBlob'. Set 'dwBlobLen' to the number of
// bytes in the key blob.
...
// Import the key blob into the CSP.
CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyA);
// Create a random session key (session key B). Because this key is
// going to be used solely for key exchange and not encryption, it
// does not matter which algorithm you specify here.
CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyB);
// Export session key B into a simple key blob.
dwBlobLen = BLOB_SIZE;
CryptExportKey(hKeyB, hSendPubKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen);
// Transmit the key blob containing session key B to the sender.
...
//
// Compute the hash value and transmit it to the sender.
//
// Create the 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);
// Transmit the hash value to the sender.
...
// Wait for the sender to respond.
...
// Receive a hash value from the sender and place it in
// 'pbSendHashValue'. Set 'dwSendHashLen' to the number of bytes in
// the hash value.
...
//
// Verify the hash value received from the sender.
//
// 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));
//
// Compare the hash value received from the sender with the
// hash value that we just computed. If they do not match, then
// terminate the protocol.
//
if(dwHashLen!=dwSendHashLen || memcmp(pbHash, pbSendHash, dwHashLen)) {
printf("Key exchange protocol failed in phase 3!\n");
printf("Aborting protocol!\n");
return;
}
//
// Use session key B to encrypt messages sent to the sender.
// Use session key A to decrypt messages received from the sender.
//
...
// Destroy the session keys.
CryptDestroyKey(hKeyA);
CryptDestroyKey(hKeyB);
// Destroy the handle to sender's public key.
CryptDestroyKey(hSharedKey);
// Release the provider handle.
CryptReleaseContext(hProv, 0);