Sdílet prostřednictvím


Vytvoření hodnoty hash pomocí CNG

hash je jednosměrná operace, která se provádí na bloku dat a vytváří jedinečnou hodnotu hash, která představuje obsah dat. Bez ohledu na to, kdy se hash provádí, stejný hashing algoritmus provedený na stejných datech vždy vytvoří stejnou hash hodnotu. Pokud se některá z dat změní, hodnota hash se odpovídajícím způsobem změní.

Hodnoty hash nejsou užitečné pro šifrování dat, protože nejsou určeny k reprodukci původních dat z hodnoty hash. Hodnoty hash jsou nejužitečnější k ověření integrity dat při použití s asymetrickým podpisovým algoritmem. Pokud jste například zahashovali textovou zprávu, podepsali hash a přiložili podepsaný hash k původní zprávě, příjemce může ověřit podepsaný hash, vytvořit hash hodnotu pro přijatou zprávu a pak porovnat tuto hash hodnotu s podepsaným hashem obsaženým v původní zprávě. Pokud jsou dvě hodnoty hash stejné, příjemce může být přiměřeně jistý, že původní zpráva nebyla změněna.

Velikost hodnoty hash je pevná pro konkrétní algoritmus hash. To znamená, že bez ohledu na to, jak velký nebo malý je datový blok, bude hodnota hash vždy stejná. Například hashovací algoritmus SHA256 má velikost hash hodnoty 256 bitů.

Vytvoření objektu hashování

Pokud chcete vytvořit hodnotu hash pomocí CNG, proveďte následující kroky:

  1. Otevřete zprostředkovatele algoritmu, který podporuje požadovaný algoritmus. Mezi typické algoritmy hash patří MD2, MD4, MD5, SHA-1 a SHA256. Zavolejte funkci BCryptOpenAlgorithmProvider a určete příslušný identifikátor algoritmu v parametru pszAlgId. Funkce vrátí zprostředkovateli popisovač.

  2. Pomocí následujících kroků vytvořte objekt hashování:

    1. Získejte velikost objektu voláním funkce BCryptGetProperty k načtení vlastnosti BCRYPT_OBJECT_LENGTH.
    2. Přidělení paměti pro uložení objektu hash.
    3. Vytvořte objekt voláním BCryptCreateHash funkce.
  3. Zahashuj data. To zahrnuje volání BCryptHashData funkce jednou nebo vícekrát. Každé volání připojí zadaná data k hodnotě hash.

  4. Pokud chcete získat hodnotu hash, proveďte následující kroky:

    1. Načtěte velikost hodnoty voláním funkce BCryptGetProperty k získání vlastnosti BCRYPT_HASH_LENGTH.
    2. Přidělte paměť pro uložení hodnoty.
    3. Načtěte hodnotu hash voláním funkce BCryptFinishHash. Po zavolání této funkce už není objekt hash platný.
  5. Chcete-li provést tento postup, musíte provést následující kroky čištění:

    1. Zavřete objekt hash předáním popisovače hash do funkce BCryptDestroyHash.

    2. Uvolněte paměť přidělenou pro objekt hash.

    3. Pokud nebudete vytvářet žádné další objekty hash, zavřete zprostředkovatele algoritmu tak, že funkci BCryptCloseAlgorithmProvider předáte popisovač zprostředkovatele.

      Pokud budete vytvářet více objektů hash, doporučujeme opakovaně používat poskytovatele algoritmu, místo abyste poskytovatele algoritmu stejného typu opakovaně vytvářeli a likvidovali.

    4. Po dokončení použití paměti hodnoty hash ji uvolněte.

Následující příklad ukazuje, jak vytvořit hodnotu hash pomocí 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);
    }

}

Vytvoření opakovaně použitelného objektu hash

Počínaje Windows 8 a Windows Serverem 2012 můžete vytvořit opakovaně použitelný objekt hash pro scénáře, které vyžadují výpočet více hodnot hash nebo HMACs v rychlém sledu. Proveďte to zadáním BCRYPT_HASH_REUSABLE_FLAG při volání BCryptOpenAlgorithmProvider funkce. Tento příznak podporují všichni poskytovatelé hashovacích algoritmů Microsoftu. Objekt hash vytvořený pomocí tohoto příznaku lze znovu použít okamžitě po volání BCryptFinishHash stejně, jako kdyby byl nově vytvořen voláním BCryptCreateHash. Následujícím postupem vytvořte opakovaně použitelný objekt hashování:

  1. Otevřete zprostředkovatele algoritmu, který podporuje požadovaný hashovací algoritmus. Volání funkce BCryptOpenAlgorithm Provider a určení příslušného identifikátoru algoritmu v parametru pszAlg Id a BCRYPT_HASH_REUSABLE_FLAG v parametru dwFlags. Funkce vrátí popisovač poskytovatele.

  2. Pomocí následujících kroků vytvořte objekt hashování:

    1. Získejte velikost objektu voláním funkce BCryptGetProperty k načtení vlastnosti BCRYPT_OBJECT_LENGTH.
    2. Přidělení paměti pro uložení objektu hash.
    3. Vytvořte objekt voláním BCryptCreateHash funkce. V parametru dwFlags zadejte BCRYPT_HASH_REUSABLE_FLAG.
  3. Zatřiďujte data voláním funkce BCryptHashData.

  4. Pokud chcete získat hodnotu hash, proveďte následující kroky:

    1. Získejte velikost hodnoty hash voláním funkce BCryptGetProperty pro získání vlastnosti BCRYPT_HASH_LENGTH.
    2. Přidělte paměť pro uložení hodnoty.
    3. Získejte hodnotu hash voláním BCryptFinishHash.
  5. Pokud chcete znovu použít objekt hashování s novými daty, přejděte ke kroku 3.

  6. Chcete-li provést tento postup, musíte provést následující kroky čištění:

    1. Zavřete objekt hash tak, že předáte popisovač hash funkci BCryptDestroyHash.
    2. Uvolněte paměť přidělenou pro objekt hash.
    3. Pokud nebudete vytvářet žádné další objekty hash, zavřete zprostředkovatele algoritmu předáním popisovače do BCryptCloseAlgorithmProvider funkce.
    4. Po dokončení použití paměti hodnoty hash ji uvolněte.

Duplikování objektu hash

V některých případech může být užitečné hashovat určité množství společných dat a pak vytvořit dva samostatné objekty hash ze společných dat. Abyste toho dosáhli, nemusíte vytvářet dva samostatné objekty hash a zatřiďovat společná data dvakrát. Můžete vytvořit jeden objekt hash a přidat do objektu hash všechna společná data. Potom můžete použít funkci BCryptDuplicateHash k vytvoření duplikátu původního objektu hash. Duplicitní objekt hash obsahuje všechny informace o stavu a hashovaná data jako původní, ale jedná se o zcela nezávislý objekt hash. Teď můžete do každého objektu hash přidat jedinečná data a získat hodnotu hash, jak je znázorněno v příkladu. Tato technika je užitečná při hashování pravděpodobně velkého množství běžných dat. Do původního hashe je nutné přidat pouze společná data, a potom můžete duplikovat hashový objekt, abyste získali unikátní hashový objekt.