The Client Side (Diffie-Hellman)

The protocol engine's client-side code is typically:

HCRYPTPROV hProv      = <protocol engine's key container>;
HCRYPTKEY  hClientDHKey;  // handle to the client's DH key
HCRYPTKEY  hMasterKey;
ALG_ID     Algid;
PBYTE      pbServerPub = <pointer to Server Public Key>;
DWORD      cbServerPub = <size of Server Public Key>;
BYTE       rgbServerBlob[<max blob size>];
DWORD      cbServerBlob;
PBYTE      pbG = <pointer to generator G from Server>;
DWORD      cbG = <size of generator G from Server>;
PBYTE      pbP = <pointer to prime P from Server>;
DWORD      cbP = <size of prime P from Server>;
CRYPT_DATA_BLOB Data;
BYTE       rgbClientPubBlob[size of the client public key blob];
DWORD      cbClientPubBlob;

// generate and set the parameters on the client DH key
CryptGenKey(hProv, CALG_DH_EPHEM, 0, &hClientDHKey);

Data.pbData = pbP;
Data.cbData = cbP;
CryptSetKeyParam(hClientDHKey, KP_P, (BYTE*)&Data, 0);

Data.pbData = pbG;
Data.cbData = cbG;
CryptSetKeyParam(hClientDHKey, KP_G, (BYTE*)&Data, 0);

// actually create the client private DH key
CryptSetKeyParam(hClientDHKey, KP_X, NULL, 0);

// Build PUBLICKEYBLOB around the server's public key
{
     BLOBHEADER *pBlobHeader = (BLOBHEADER *)rgbServerBlob;
     DHPUBKEY   *pDHPubKey   = (DHPUBKEY *)(pBlobHeader + 1);
     BYTE       *pData       = (BYTE *)(pDHPubKey + 1);

     pBlobHeader->bType    = PUBLICKEYBLOB;
     pBlobHeader->bVersion = CUR_BLOB_VERSION;
     pBlobHeader->reserved = 0;
     pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;

     pDHPubKey->magic = 0x31484400;
     pDHPubKey->bitlen = dwServerPub * 8;

     ReverseMemCopy(pData, pbServerPub, cbServerPub);
     cbServerBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + 
       cbServerPub;
}

// import the server's public key and get an agreed key
CryptImportKey(hProv, rgbServerBlob, cbServerBlob, hClientDHKey, 0, 
   &hMasterKey);

// Select the master key type.
switch(<protocol being used>)
{
    case <SSL 3.0>:
        Algid = CALG_SSL3_MASTER;
        break;

    case <TLS 1.0>:
        Algid = CALG_TLS1_MASTER;
        break;
}

// Convert the agreed key to the appropriate master key
CryptSetKeyParam(hMasterKey, KP_ALGID, (BYTE*)&Algid, 0);

// Get the client Diffie-Hellman public key.
cbClientPubBlob = sizeof(rgbClientPubBlob);
CryptExportKey(hClientDHKey, 0, PUBLICKEYBLOB,
               0, rgbClientPubBlob, & cbClientPubBlob);

CryptDestroyKey(hClientDHKey);