This function generates cryptographic keys derived from base data. This function guarantees that all keys generated from the same base data are identical, provided the same cryptographic service provider (CSP) and algorithms are used. The base data can be a password or any other user data.
This function is the same as CryptGenKey, except that the generated session keys are derived from base data instead of being random. Another difference is that the CryptDeriveKey function cannot be used to generate public/private key pairs.
A handle to the session key is returned in phKey. This handle can then be used as needed with any of the other CryptoAPI functions that require key handles.
At a Glance
Header file: | Wincrypt.h |
Windows CE versions: | 2.10 and later |
Syntax
BOOL CRYPTFUNC CryptDeriveKey( HCRYPTPROV hProv,
ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags,
HCRYPTKEY *phKey );
Parameters
hProv
[in] Handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
Algid
[in] Identifier for the algorithm for which the key is to be generated.
The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for a list of common algorithm identifiers.
hBaseData
[in] Handle to a hash object that has been fed the exact base data.
To obtain this handle, an application must first create a hash object with CryptCreateHash and then add the base data to the hash object with CryptHashData. For more information about hashing and digital signatures, see Cryptography.
dwFlags
[in] Specifies the type of key generated. This parameter can be zero, or you can specify one or more of the following flags by using the bitwise OR operator to combine them:
Value | Description |
CRYPT_EXPORTABLE. | If this flag is set, then the session key can be transferred out of the CSP into a key BLOB through the CryptExportKey function. Because keys generally must be exportable, this flag should usually be set. |
If this flag is not set, then the session key will not be exportable. This means the key will be available only within the current session and only the application that created it will be able to use it. | |
This flag does not apply to public/private key pairs | |
CRYPT_CREATE_SALT. | Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value is 128 bits and the session key is 40 bits, there will be 88 bits left over. |
If this flag is set, then the key will be assigned a salt value based on the unused hash value bits. You can retrieve this salt value by using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT. | |
If this flag is not set, then the key will be given a salt value of zero. | |
When keys with nonzero salt values are exported (by using CryptExportKey), the salt value must also be obtained and kept with the key BLOB. | |
CRYPT_NO_SALT. | Specifies that a no salt value gets allocated for a 40-bit symmetric key. |
CRYPT_USER_PROTECTED. | If this flag is set, then the user will be notified through a dialog box or another method when certain actions are attempted by using this key. The precise behavior is specified by the CSP being used. Prior to Microsoft Internet Explorer 4.0, Microsoft Cryptographic Providers ignore this flag. Starting with Microsoft Internet Explorer 4.0, Microsoft Providers support this flag value. |
CRYPT_UPDATE_KEY. | Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called multiple times. |
If this flag is set, a new session key is not generated. Instead, the key specified by phKey is modified. The precise behavior of this flag is dependent on the type of key being generated and on the particular CSP being used. | |
The Microsoft Cryptographic Providers ignore this flag. |
phKey
[out] Address to which the function copies the handle of the newly generated key.
Return Values
TRUE indicates success. FALSE indicates failure. To get extended error information, call GetLastError. Common values for GetLastError are described in the following table. The error values prefaced by "NTE" are generated by the particular CSP you are using.
Value | Description |
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle. |
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer. |
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support. |
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value. |
NTE_BAD_HASH | The hBaseData parameter does not contain a valid handle to a hash object. |
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished." |
NTE_BAD_UID | The hProv parameter does not contain a valid context handle. |
NTE_FAIL | The function failed in some unexpected way. |
Remarks
To generate a key for a symmetric encryption algorithm, use the Algid parameter to specify the algorithm. The algorithms available will most likely be different for each CSP. If you are using the Microsoft Base Cryptographic Provider, use one of the following values to specify the algorithm.
Value | Description |
CALG_RC2 | RC2 block cipher |
CALG_RC4 | RC4 stream cipher |
When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk-encrypting data. To change these parameters, use the CryptSetKeyParam function.
After the CryptDeriveKey function has been called, no more data can be added to the hash object. The CryptDestroyHash function should be called at this point to destroy the hash object.
Example
#include <wincrypt.h>
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
CHAR szPassword[ ] = "apple-camshaft";
DWORD dwLength;
// Get a handle to user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
printf("Error %x during CryptAcquireContext!\n", GetLastError());
goto done;
}
// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
printf("Error %x during CryptCreateHash!\n", GetLastError());
goto done;
}
// Hash the password string.
dwLength = strlen(szPassword);
if(!CryptHashData(hHash, (BYTE *)szPassword, dwLength, 0)) {
printf("Error %x during CryptHashData!\n", GetLastError());
goto done;
}
// Create a block cipher session key based on the hash of the password.
if(!CryptDeriveKey(hProv, CALG_RC2, hHash, CRYPT_EXPORTABLE, &hKey)) {
printf("Error %x during CryptDeriveKey!\n", GetLastError());
goto done;
}
// Use 'hKey' to encrypt or decrypt a message.
...
done:
// Destroy the hash object.
if(hHash != 0) CryptDestroyHash(hHash);
// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);
// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);
See Also
CryptAcquireContext, CryptCreateHash, CryptDestroyHash, CryptDestroykey, CryptExportKey, CryptGenKey, CryptGetKeyParam, CryptHashData, CryptSetKeyParam