Exemple de programme C : création d’un HMAC
Une somme de contrôle d’authentification de message haché (HMAC) est généralement utilisée pour vérifier qu’un message n’a pas été modifié lors du transit. Les deux parties au message doivent avoir une clé secrète partagée. L’expéditeur associe la clé et le message dans une chaîne, crée un condensé de la chaîne à l’aide d’un algorithme tel que SHA-1 ou MD5, et transmet le message et le Digest. Le récepteur combine la clé partagée avec le message, applique l’algorithme approprié et compare le condensé ainsi obtenu avec celui transmis par l’expéditeur. Si les résumés sont exactement les mêmes, le message n’a pas été falsifié.
Cet exemple illustre les tâches et les fonctions CryptoAPI suivantes :
- Acquisition d’un handle vers un fournisseur de services de chiffrement en appelant CryptAcquireContext.
- Dérivation d’une clé symétrique à partir d’une chaîne d’octets en appelant CryptCreateHash, CryptHashDataet CryptDeriveKey.
- Utilisation de la clé symétrique pour créer un objet de hachage HMAC en appelant CryptCreateHash et CryptSetHashParam.
- Hachage d’un message en appelant CryptHashData.
- Récupération du hachage en appelant CryptGetHashParam.
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
int main()
{
//--------------------------------------------------------------------
// Declare variables.
//
// hProv: Handle to a cryptographic service provider (CSP).
// This example retrieves the default provider for
// the PROV_RSA_FULL provider type.
// hHash: Handle to the hash object needed to create a hash.
// hKey: Handle to a symmetric key. This example creates a
// key for the RC4 algorithm.
// hHmacHash: Handle to an HMAC hash.
// pbHash: Pointer to the hash.
// dwDataLen: Length, in bytes, of the hash.
// Data1: Password string used to create a symmetric key.
// Data2: Message string to be hashed.
// HmacInfo: Instance of an HMAC_INFO structure that contains
// information about the HMAC hash.
//
HCRYPTPROV hProv = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHmacHash = NULL;
PBYTE pbHash = NULL;
DWORD dwDataLen = 0;
BYTE Data1[] = {0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64};
BYTE Data2[] = {0x6D,0x65,0x73,0x73,0x61,0x67,0x65};
HMAC_INFO HmacInfo;
//--------------------------------------------------------------------
// Zero the HMAC_INFO structure and use the SHA1 algorithm for
// hashing.
ZeroMemory(&HmacInfo, sizeof(HmacInfo));
HmacInfo.HashAlgid = CALG_SHA1;
//--------------------------------------------------------------------
// Acquire a handle to the default RSA cryptographic service provider.
if (!CryptAcquireContext(
&hProv, // handle of the CSP
NULL, // key container name
NULL, // CSP name
PROV_RSA_FULL, // provider type
CRYPT_VERIFYCONTEXT)) // no key access is requested
{
printf(" Error in AcquireContext 0x%08x \n",
GetLastError());
goto ErrorExit;
}
//--------------------------------------------------------------------
// Derive a symmetric key from a hash object by performing the
// following steps:
// 1. Call CryptCreateHash to retrieve a handle to a hash object.
// 2. Call CryptHashData to add a text string (password) to the
// hash object.
// 3. Call CryptDeriveKey to create the symmetric key from the
// hashed password derived in step 2.
// You will use the key later to create an HMAC hash object.
if (!CryptCreateHash(
hProv, // handle of the CSP
CALG_SHA1, // hash algorithm to use
0, // hash key
0, // reserved
&hHash)) // address of hash object handle
{
printf("Error in CryptCreateHash 0x%08x \n",
GetLastError());
goto ErrorExit;
}
if (!CryptHashData(
hHash, // handle of the hash object
Data1, // password to hash
sizeof(Data1), // number of bytes of data to add
0)) // flags
{
printf("Error in CryptHashData 0x%08x \n",
GetLastError());
goto ErrorExit;
}
if (!CryptDeriveKey(
hProv, // handle of the CSP
CALG_RC4, // algorithm ID
hHash, // handle to the hash object
0, // flags
&hKey)) // address of the key handle
{
printf("Error in CryptDeriveKey 0x%08x \n",
GetLastError());
goto ErrorExit;
}
//--------------------------------------------------------------------
// Create an HMAC by performing the following steps:
// 1. Call CryptCreateHash to create a hash object and retrieve
// a handle to it.
// 2. Call CryptSetHashParam to set the instance of the HMAC_INFO
// structure into the hash object.
// 3. Call CryptHashData to compute a hash of the message.
// 4. Call CryptGetHashParam to retrieve the size, in bytes, of
// the hash.
// 5. Call malloc to allocate memory for the hash.
// 6. Call CryptGetHashParam again to retrieve the HMAC hash.
if (!CryptCreateHash(
hProv, // handle of the CSP.
CALG_HMAC, // HMAC hash algorithm ID
hKey, // key for the hash (see above)
0, // reserved
&hHmacHash)) // address of the hash handle
{
printf("Error in CryptCreateHash 0x%08x \n",
GetLastError());
goto ErrorExit;
}
if (!CryptSetHashParam(
hHmacHash, // handle of the HMAC hash object
HP_HMAC_INFO, // setting an HMAC_INFO object
(BYTE*)&HmacInfo, // the HMAC_INFO object
0)) // reserved
{
printf("Error in CryptSetHashParam 0x%08x \n",
GetLastError());
goto ErrorExit;
}
if (!CryptHashData(
hHmacHash, // handle of the HMAC hash object
Data2, // message to hash
sizeof(Data2), // number of bytes of data to add
0)) // flags
{
printf("Error in CryptHashData 0x%08x \n",
GetLastError());
goto ErrorExit;
}
//--------------------------------------------------------------------
// Call CryptGetHashParam twice. Call it the first time to retrieve
// the size, in bytes, of the hash. Allocate memory. Then call
// CryptGetHashParam again to retrieve the hash value.
if (!CryptGetHashParam(
hHmacHash, // handle of the HMAC hash object
HP_HASHVAL, // query on the hash value
NULL, // filled on second call
&dwDataLen, // length, in bytes, of the hash
0))
{
printf("Error in CryptGetHashParam 0x%08x \n",
GetLastError());
goto ErrorExit;
}
pbHash = (BYTE*)malloc(dwDataLen);
if(NULL == pbHash)
{
printf("unable to allocate memory\n");
goto ErrorExit;
}
if (!CryptGetHashParam(
hHmacHash, // handle of the HMAC hash object
HP_HASHVAL, // query on the hash value
pbHash, // pointer to the HMAC hash value
&dwDataLen, // length, in bytes, of the hash
0))
{
printf("Error in CryptGetHashParam 0x%08x \n", GetLastError());
goto ErrorExit;
}
// Print the hash to the console.
printf("The hash is: ");
for(DWORD i = 0 ; i < dwDataLen ; i++)
{
printf("%2.2x ",pbHash[i]);
}
printf("\n");
// Free resources.
ErrorExit:
if(hHmacHash)
CryptDestroyHash(hHmacHash);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hProv)
CryptReleaseContext(hProv, 0);
if(pbHash)
free(pbHash);
return 0;
}