Exchanging Diffie-Hellman/Schannel Keys

The Diffie-Hellman algorithm makes it possible for two or more hosts to create and share an identical, secret encryption key, by simply sharing information over an insecure network. The information shared over the network is in the form of a couple of constant values and a D-H public key. The process used by two key-exchange participants is as follows:

    To prepare a Diffie-Hellman/Schannel public key for transmission
  1. Get a handle to the Diffie-Hellman provider. Do this by calling CryptAcquireContext to get a pointer to the Microsoft DH Schannel Cryptographic Provider.
  2. Get a handle to a D-H key. Do this by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. Get the memory length (in bytes) needed to hold a D-H key by calling CryptExportKey, passing NULL for the pbData parameter. The key length will be returned in pcbData.
  4. Allocate memory for the key.
  5. Create a D-H public-key blob by calling CryptExportKey, passing PUBLICKEYBLOB in the dwBlobType parameter and the handle to the D-H key in the hKey parameter. This function call calculates the public key value, (G^X) mod P. If all the preceding function calls were successful, the D-H public key is now ready to be encoded and transmitted.
    To import a Diffie-Hellman/Schannel public key and calculate the agreed (secret) key
  1. Get a handle to the Diffie-Hellman provider. Do this by calling CryptAcquireContext to get a pointer to the Microsoft DH Schannel Cryptographic Provider.
  2. Get a handle to a D-H key. Do this by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. To import the key into the CSP, call CryptImportKey, passing a pointer to the public key blob in the pbData parameter, the length of the blob in the dwDataLen parameter, and the handle to the D-H key in the hImpKey parameter. This call to CryptImportKey causes the calculation, (Y^X) mod P, to be performed thus creating the shared, secret key and completing the key exchange. This function call returns a handle to the new, secret, bulk-encryption key in the hKey parameter.
  4. Convert the shared, secret key to the appropriate ALG_ID, bulk-encryption key type, by calling CryptSetKeyParam with dwParam set to KP_ALGID (See CPSetKeyParam Diffie-Hellman/Schannel Extensions), and with pbData set to a pointer to CALG_CYLINK_MEK. This step must be done before using the shared key in CryptEncrypt or CryptDecrypt. Calls made to either of these functions prior to calling CryptSetKeyParam will fail.

    If a call to CryptGetKeyParam is made on the key handle returned from the call to CryptImportKey and prior to calling CryptSetKeyParam (as described in this step), the ALG_ID returned by the call to CryptGetKeyParam will be CALG_AGREEDKEY_ANY. If all the preceding function calls were successful, the agreed key is now ready to be used for encryption or decryption.

    The SSL 3.0 or TLS 1.0 key length is 48 bytes. To obtain the required length, take the 384 Least Significant Bits of the returned HCRYPTKEY for this agreed key.

  5. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.