Een hash maken met CNG
Een hash- is een eenrichtingsbewerking die wordt uitgevoerd op een gegevensblok om een unieke hashwaarde te creëren die de inhoud van de gegevens vertegenwoordigt. Ongeacht wanneer de hash wordt uitgevoerd, produceert hetzelfde hash-algoritme uitgevoerd op dezelfde gegevens altijd dezelfde hash-waarde. Als een van de gegevens verandert, wordt de hashwaarde op de juiste manier gewijzigd.
Hashes zijn niet handig voor het versleutelen van gegevens, omdat ze niet zijn bedoeld om de oorspronkelijke gegevens van de hashwaarde te reproduceren. Hashes zijn het handigst om de integriteit van de gegevens te controleren wanneer ze worden gebruikt met een asymmetrisch ondertekeningsalgoritme. Als u bijvoorbeeld een sms-bericht hebt gehasht, de hash hebt ondertekend en de ondertekende hashwaarde hebt opgenomen met het oorspronkelijke bericht, kan de ontvanger de ondertekende hash controleren, de hash-waarde voor het ontvangen bericht maken en deze hashwaarde vergelijken met de ondertekende hashwaarde die is opgenomen in het oorspronkelijke bericht. Als de twee hashwaarden identiek zijn, kan de ontvanger er redelijk zeker van zijn dat het oorspronkelijke bericht niet is gewijzigd.
De grootte van de hashwaarde is vastgezet voor een bepaald hash-algoritme. Dit betekent dat, ongeacht hoe groot of klein het gegevensblok is, de hashwaarde altijd dezelfde grootte heeft. Als voorbeeld heeft het SHA256-hashingalgoritme een hashwaardegrootte van 256 bits.
Een hash-object maken
Voer de volgende stappen uit om een hash te maken met CNG:
Open een algoritmeprovider die ondersteuning biedt voor het gewenste algoritme. Typische hash-algoritmen zijn MD2, MD4, MD5, SHA-1 en SHA256. Roep de BCryptOpenAlgorithmProvider functie aan en geef de juiste algoritme-id op in de parameter pszAlgId. De functie retourneert een verwijzing naar de provider.
Voer de volgende stappen uit om het hashing-object te maken:
- Haal de grootte van het object op door de functie BCryptGetProperty aan te roepen om de eigenschap BCRYPT_OBJECT_LENGTH op te halen.
- Geheugen toewijzen voor het opslaan van het hash-object.
- Maak het object door de functie BCryptCreateHash aan te roepen.
Hash de gegevens. Dit omvat het aanroepen van de BCryptHashData functie een of meer keren. Elke aanroep voegt de opgegeven gegevens toe aan de hash.
Voer de volgende stappen uit om de hashwaarde te verkrijgen:
- Haal de grootte van de waarde op door de functie BCryptGetProperty aan te roepen om de eigenschap BCRYPT_HASH_LENGTH op te halen.
- Wijs geheugen toe om de waarde vast te houden.
- Haal de hashwaarde op door de BCryptFinishHash--functie aan te roepen. Nadat deze functie is aangeroepen, is het hash-object niet meer geldig.
Als u deze procedure wilt voltooien, moet u de volgende opschoonstappen uitvoeren:
Sluit het hash-object door de hash-handle door te geven aan de BCryptDestroyHash functie.
Maak het geheugen vrij dat u hebt toegewezen voor het hash-object.
Als u geen hash-objecten meer gaat maken, sluit u de algoritmeprovider door de providergreep door te geven aan de BCryptCloseAlgorithmProvider functie.
Als u meer hash-objecten gaat maken, raden we u aan de algoritmeprovider opnieuw te gebruiken in plaats van vaak hetzelfde type algoritmeprovider te maken en te vernietigen.
Wanneer u klaar bent met het gebruik van het hash-waardegeheugen, maakt u deze vrij.
In het volgende voorbeeld ziet u hoe u een hash-waarde maakt met behulp van CNG.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) Microsoft. All rights reserved.
/*++
Abstract:
Sample program for SHA 256 hashing using CNG
--*/
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
static const BYTE rgbMsg[] =
{
0x61, 0x62, 0x63
};
void __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
BCRYPT_ALG_HANDLE hAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbData = 0,
cbHash = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(wargv);
//open an algorithm handle
if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
//calculate the size of the buffer to hold the hash object
if(!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbHashObject,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
//allocate the hash object on the heap
pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
if(NULL == pbHashObject)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
//calculate the length of the hash
if(!NT_SUCCESS(status = BCryptGetProperty(
hAlg,
BCRYPT_HASH_LENGTH,
(PBYTE)&cbHash,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
//allocate the hash buffer on the heap
pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
if(NULL == pbHash)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
//create a hash
if(!NT_SUCCESS(status = BCryptCreateHash(
hAlg,
&hHash,
pbHashObject,
cbHashObject,
NULL,
0,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptCreateHash\n", status);
goto Cleanup;
}
//hash some data
if(!NT_SUCCESS(status = BCryptHashData(
hHash,
(PBYTE)rgbMsg,
sizeof(rgbMsg),
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptHashData\n", status);
goto Cleanup;
}
//close the hash
if(!NT_SUCCESS(status = BCryptFinishHash(
hHash,
pbHash,
cbHash,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptFinishHash\n", status);
goto Cleanup;
}
wprintf(L"Success!\n");
Cleanup:
if(hAlg)
{
BCryptCloseAlgorithmProvider(hAlg,0);
}
if (hHash)
{
BCryptDestroyHash(hHash);
}
if(pbHashObject)
{
HeapFree(GetProcessHeap(), 0, pbHashObject);
}
if(pbHash)
{
HeapFree(GetProcessHeap(), 0, pbHash);
}
}
Een herbruikbaar hash-object maken
Vanaf Windows 8 en Windows Server 2012 kunt u een herbruikbaar hash-object maken voor scenario's waarvoor u meerdere hashes of HMAC's snel achter elkaar moet berekenen. Doe dit door de BCRYPT_HASH_REUSABLE_FLAG op te geven bij het aanroepen van de BCryptOpenAlgorithmProvider functie. Alle Providers van Microsoft-hashalgoritmen ondersteunen deze vlag. Een hash-object dat met deze vlag is gemaakt, kan onmiddellijk na het aanroepen van BCryptFinishHash- worden hergebruikt alsof het net is gemaakt door BCryptCreateHash-aan te roepen. Voer de volgende stappen uit om een herbruikbaar hash-object te maken:
Open een algoritmeprovider die ondersteuning biedt voor het gewenste hash-algoritme. Roep de BCryptOpenAlgorithmProvider-functie aan en geef de juiste algoritme-id op in de parameter pszAlgId parameter en BCRYPT_HASH_REUSABLE_FLAG in de parameter dwFlags. De functie retourneert een verwijzing naar de provider.
Voer de volgende stappen uit om het hashing-object te maken:
- Haal de grootte van het object op door de functie BCryptGetProperty aan te roepen om de eigenschap BCRYPT_OBJECT_LENGTH op te halen.
- Geheugen toewijzen voor het opslaan van het hash-object.
- Maak het object door de functie BCryptCreateHash aan te roepen. Geef BCRYPT_HASH_REUSABLE_FLAG op in de dwFlags-parameter.
Hash de gegevens door de functie BCryptHashData aan te roepen.
Voer de volgende stappen uit om de hashwaarde te verkrijgen:
- Haal de grootte van de hash-waarde op door de BCryptGetProperty--functie aan te roepen om de eigenschap BCRYPT_HASH_LENGTH op te halen.
- Wijs geheugen toe om de waarde vast te houden.
- Haal de hash-waarde op door BCryptFinishHash-aan te roepen.
Als u het hash-object opnieuw wilt gebruiken met nieuwe gegevens, gaat u naar stap 3.
Als u deze procedure wilt voltooien, moet u de volgende opschoonstappen uitvoeren:
- Sluit het hash-object door de hash-handle door te geven aan de BCryptDestroyHash functie.
- Maak het geheugen vrij dat u hebt toegewezen voor het hash-object.
- Als u geen hash-objecten meer gaat maken, sluit u de algoritmeprovider door de providergreep door te geven aan de BCryptCloseAlgorithmProvider functie.
- Wanneer u klaar bent met het gebruik van het hash-waardegeheugen, maakt u deze vrij.
Een hash-object dupliceren
In sommige gevallen kan het nuttig zijn om een bepaalde hoeveelheid algemene gegevens te hashen en vervolgens twee afzonderlijke hash-objecten te maken van de algemene gegevens. U hoeft geen twee afzonderlijke hash-objecten te maken en de gemeenschappelijke gegevens tweemaal te hashen om dit te bereiken. U kunt één hash-object maken en alle algemene gegevens toevoegen aan het hash-object. Vervolgens kunt u de functie BCryptDuplicateHash gebruiken om een duplicaat van het oorspronkelijke hash-object te maken. Het dubbele hash-object bevat dezelfde statusinformatie en gehashte gegevens als het origineel, maar het is een volledig onafhankelijk hash-object. U kunt nu de unieke gegevens toevoegen aan elk van de hash-objecten en de hashwaarde verkrijgen, zoals wordt weergegeven in het voorbeeld. Deze techniek is handig bij het hashen van een mogelijk grote hoeveelheid algemene gegevens. U hoeft de algemene gegevens slechts één keer toe te voegen aan de oorspronkelijke hash en vervolgens kunt u het hash-object dupliceren om een uniek hash-object te verkrijgen.