Receiver Code Example

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);