Receiver Code Example

This section illustrates the code needed on the destination user side to implement the three-phase key exchange protocol. The details of the communication between sending user and the destination user 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 handle to the default provider.

CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);

// Obtain the sending user's exchange public key. Import it into the

// CSP and place a handle to it in 'hSendPubKey'.

...

// Obtain the sending user'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 destination user'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 sending user

// 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 key blob containing session key B to the sending user.

...

//

// Compute hash value and transmit it to the sending user.

//

// Create hash object.

CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key A to hash.

CryptHashSessionKey(hHash, hKeyA, 0);

// Add destination user's name to hash.

CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add session key B to hash.

CryptHashSessionKey(hHash, hKeyB, 0);

// Add sending user name to hash.

CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add "phase 2" text to 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 sending user.

...

// Wait for the sending user to respond.

...

// Receive a hash value from the sending user and place it in

// 'pbSendHashValue'. Set 'dwSendHashLen' to the number of bytes in

// the hash value.

...

//

// Verify hash value received from the sending user.

//

// Create hash object.

CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key B to hash.

CryptHashSessionKey(hHash, hKeyB, 0);

// Add sending user's name to hash.

CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add destination user's name to hash.

CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add "phase 3" text to 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 sending user 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 session keys.

CryptDestroyKey(hKeyA);

CryptDestroyKey(hKeyB);

// Destroy handle to sending user's public key.

CryptDestroyKey(hSharedKey);

// Release provider handle.

CryptReleaseContext(hProv, 0);