Udostępnij przez


Tworzenie skrótu za pomocą CNG

skrót to operacja jednokierunkowa przeprowadzana na bloku danych w celu utworzenia unikatowej wartości skrótu, która reprezentuje zawartość danych. Niezależnie od tego, kiedy jest wykonywany skrót, ten sam algorytm tworzenia skrótów wykonywany na tych samych danych zawsze będzie generować tę samą wartość skrótu. Jeśli któraś z danych ulegnie zmianie, wartość skrótu zmieni się odpowiednio.

Skróty nie są przydatne do szyfrowania danych, ponieważ nie są one przeznaczone do odtworzenia oryginalnych danych z wartości skrótu. Skróty są najbardziej przydatne do weryfikowania integralności danych, gdy są używane z asymetrycznym algorytmem podpisywania. Na przykład, w przypadku skrócenia wiadomości SMS, podpisania skrótu i dołączenia podpisanej wartości skrótu do oryginalnej wiadomości, adresat może zweryfikować podpisany skrót, utworzyć wartość skrótu dla odebranej wiadomości, a następnie porównać tę wartość skrótu z podpisaną wartością skrótu dołączoną do oryginalnej wiadomości. Jeśli dwie wartości skrótu są identyczne, odbiorca może być rozsądnie pewien, że oryginalna wiadomość nie została zmodyfikowana.

Rozmiar wartości skrótu jest stały dla określonego algorytmu tworzenia skrótów. Oznacza to, że bez względu na to, jak duży lub mały jest blok danych, wartość skrótu zawsze będzie taka sama. Na przykład algorytm wyznaczania wartości skrótu SHA256 ma rozmiar wartości skrótu 256 bitów.

Tworzenie obiektu haszującego

Aby utworzyć skrót przy użyciu CNG, wykonaj następujące kroki:

  1. Otwórz dostawcę algorytmu, który obsługuje żądany algorytm. Typowe algorytmy wyznaczania wartości skrótu obejmują MD2, MD4, MD5, SHA-1 i SHA256. Wywołaj funkcję BCryptOpenAlgorithmProvider i określ odpowiedni identyfikator algorytmu w parametrze pszAlgId. Funkcja zwraca uchwyt do dostawcy.

  2. Wykonaj następujące kroki, aby utworzyć obiekt tworzenia skrótów:

    1. Uzyskaj rozmiar obiektu, wywołując funkcję BCryptGetProperty w celu pobrania właściwości BCRYPT_OBJECT_LENGTH.
    2. Przydziel pamięć do przechowywania obiektu skrótu.
    3. Utwórz obiekt, wywołując funkcję BCryptCreateHash.
  3. Zahaszuj dane. Obejmuje to wywołanie funkcji BCryptHashData co najmniej raz. Każde wywołanie dołącza zdefiniowane dane do skrótu.

  4. Wykonaj następujące kroki, aby uzyskać wartość skrótu:

    1. Pobierz rozmiar wartości, wywołując funkcję BCryptGetProperty, aby uzyskać właściwość BCRYPT_HASH_LENGTH.
    2. Przydziel pamięć do przechowywania wartości.
    3. Pobierz wartość skrótu, wywołując funkcję BCryptFinishHash. Po wywołaniu tej funkcji obiekt skrótu jest już nieważny.
  5. Aby wykonać tę procedurę, należy wykonać następujące kroki oczyszczania:

    1. Zamknij obiekt skrótu, przekazując uchwyt skrótu do funkcji BCryptDestroyHash.

    2. Zwolnij pamięć przydzieloną dla obiektu skrótu.

    3. Jeśli nie utworzysz więcej obiektów skrótu, zamknij dostawcę algorytmu, przekazując dojście dostawcy do funkcji BCryptCloseAlgorithmProvider.

      Jeśli będziesz tworzyć więcej obiektów skrótu, sugerujemy ponowne wykorzystanie dostawcy algorytmu zamiast tworzenia i niszczenia tego samego rodzaju dostawcy algorytmu wiele razy.

    4. Po zakończeniu korzystania z pamięci wartości skrótu zwolnij ją.

W poniższym przykładzie pokazano, jak utworzyć wartość skrótu przy użyciu 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);
    }

}

Tworzenie obiektu haszowania wielokrotnego użytku

Począwszy od systemów Windows 8 i Windows Server 2012, można utworzyć obiekt tworzenia skrótów wielokrotnego użytku dla scenariuszy, które wymagają obliczenia wielu skrótów lub HMACs w krótkim odstępie czasu. W tym celu należy określić BCRYPT_HASH_REUSABLE_FLAG podczas wywoływania funkcji BCryptOpenAlgorithmProvider. Wszyscy dostawcy algorytmów skrótów firmy Microsoft obsługują tę flagę. Obiekt haszujący utworzony przy użyciu tej flagi można użyć ponownie natychmiast po wywołaniu BCryptFinishHash tak jakby został właśnie utworzony przez wywołanie BCryptCreateHash. Wykonaj następujące kroki, aby utworzyć obiekt skrótu wielokrotnego użytku:

  1. Otwórz dostawcę algorytmów, który obsługuje żądany algorytm tworzenia skrótów. Wywołaj funkcję BCryptOpenAlgorithmProvider i określ odpowiedni identyfikator algorytmu w parametrze pszAlgId i BCRYPT_HASH_REUSABLE_FLAG w parametrze dwFlags. Funkcja zwraca uchwyt do dostawcy.

  2. Aby utworzyć obiekt skrótowania, wykonaj następujące kroki:

    1. Uzyskaj rozmiar obiektu, wywołując funkcję BCryptGetProperty w celu pobrania właściwości BCRYPT_OBJECT_LENGTH.
    2. Przydziel pamięć do przechowywania obiektu skrótu.
    3. Utwórz obiekt, wywołując funkcję BCryptCreateHash. Określ BCRYPT_HASH_REUSABLE_FLAG w parametrze dwFlags.
  3. Haszuj dane przez wywołanie funkcji BCryptHashData.

  4. Wykonaj poniższe kroki, aby otrzymać wartość skrótu:

    1. Aby uzyskać rozmiar wartości skrótu, należy wywołać funkcję BCryptGetProperty w celu uzyskania właściwości BCRYPT_HASH_LENGTH.
    2. Przydziel pamięć do przechowywania wartości.
    3. Pobierz wartość skrótu, wywołując BCryptFinishHash.
  5. Aby ponownie użyć obiektu hashowania z nowymi danymi, przejdź do kroku 3.

  6. Aby wykonać tę procedurę, należy wykonać następujące kroki oczyszczania:

    1. Zamknij obiekt skrótu, przekazując uchwyt skrótu jako argument do funkcji BCryptDestroyHash.
    2. Zwolnij pamięć przydzieloną dla obiektu skrótu.
    3. Jeśli nie będziesz tworzyć więcej obiektów skrótu, zamknij dostawcę algorytmu, przekazując jego dojście do funkcji BCryptCloseAlgorithmProvider.
    4. Po zakończeniu korzystania z pamięci wartości skrótu zwolnij ją.

Duplikowanie obiektu hash

W niektórych okolicznościach warto zhashować pewną ilość wspólnych danych, a następnie utworzyć dwa oddzielne obiekty skrótu z wspólnych danych. Nie trzeba tworzyć dwóch oddzielnych obiektów skrótu i dwa razy haszować wspólne dane. Można utworzyć pojedynczy obiekt skrótu i dodać wszystkie wspólne dane do obiektu skrótu. Następnie możesz użyć funkcji BCryptDuplicateHash, aby utworzyć duplikat oryginalnego obiektu skrótu. Zduplikowany obiekt haszujący zawiera wszystkie te same informacje o stanie i dane skrócone co oryginał, ale stanowi całkowicie niezależny obiekt haszujący. Teraz możesz dodać unikatowe dane do każdego obiektu skrótu i uzyskać wartość skrótu, jak pokazano w przykładzie. Ta technika jest przydatna podczas tworzenia skrótów z ewentualnie dużej ilości typowych danych. Wystarczy dodać wspólne dane do oryginalnego skrótu jeden raz, a następnie zduplikować obiekt skrótu w celu uzyskania unikatowego obiektu skrótu.