Sender Code Example

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

For purposes of readability, this example and the following one blatantly avoid good programming practice in two major ways:

·No error checking is shown. A working program should always check the returned error codes and perform some appropriate action when an error is encountered.

·Fixed-length buffers are used to store key blobs and hash values. In practice, these buffers should be allocated dynamically, because this data will vary in size depending on the CSP used.

#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 handle to the default provider.

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

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

// the CSP and place a handle to it in 'hDestPubKey'.

...

CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hDestPubKey);

// Obtain the destination user'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 sending user'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 key blob containing session key A to the destination user.

...

// Wait for the destination user to respond.

...

// Receive a key blob containing session key B from the destination

// user and place it in 'pbKeyBlob'. Set 'dwBlobLen' to the number

// of bytes in the key blob.

...

// Receive a hash value from the destination user 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 hash value received from the destination 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's name to hash.

CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add "phase 2" 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 destination user 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 hash to be sent to the destination 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);

// Send the hash value to the destination user.

...

//

// Use session key A to encrypt messages sent to the receiver.

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

//

...

// Destroy session keys.

CryptDestroyKey(hKeyA);

CryptDestroyKey(hKeyB);

// Release provider handle.

CryptReleaseContext(hProv, 0);