共用方式為


使用 CNG 建立雜湊

雜湊是在資料區塊上執行的一種方式作業,可建立代表資料內容的唯一雜湊值。 不論何時執行雜湊,在相同資料上執行的相同 雜湊演算法 一律會產生相同的雜湊值。 如果有任何資料變更,雜湊值將會適當地變更。

雜湊不適用於加密資料,因為它們不是用來從雜湊值重現原始資料。 雜湊最適合用來驗證與非對稱簽署演算法搭配使用的資料完整性。 例如,如果您已雜湊文字訊息、簽署雜湊,並將已簽署的雜湊值包含在原始訊息中,收件者可以驗證已簽署的雜湊、建立已接收訊息的雜湊值,然後將此雜湊值與原始訊息隨附的已簽署雜湊值進行比較。 如果兩個雜湊值相同,收件者可以合理地確定原始郵件尚未修改。

特定雜湊演算法的雜湊值大小是固定的。 這表示無論資料區塊的大小或小數為何,雜湊值一律會是相同的大小。 例如,SHA256 雜湊演算法的雜湊值大小為 256 位。

建立雜湊物件

若要使用 CNG 建立雜湊,請執行下列步驟:

  1. 開啟支援所需演算法的演算法提供者。 典型的雜湊演算法包括 MD2、MD4、MD5、SHA-1 和 SHA256。 呼叫 BCryptOpenAlgorithmProvider 函 式,並在 pszAlgId 參數中指定適當的演算法識別碼。 函式會傳回提供者的控制碼。

  2. 執行下列步驟來建立雜湊物件:

    1. 呼叫 BCryptGetProperty 函式來擷取 BCRYPT_OBJECT_LENGTH 屬性,以取得物件的大小。
    2. 配置記憶體來保存雜湊物件。
    3. 呼叫 BCryptCreateHash 函式來建立物件。
  3. 雜湊資料。 這牽涉到呼叫 BCryptHashData 函式一或多次。 每個呼叫都會將指定的資料附加至雜湊。

  4. 執行下列步驟以取得雜湊值:

    1. 呼叫 BCryptGetProperty 函式以取得 BCRYPT_HASH_LENGTH 屬性,以擷取值的大小。
    2. 配置記憶體來保存值。
    3. 呼叫 BCryptFinishHash 函式來擷取雜湊值。 呼叫此函式之後,雜湊物件就不再有效。
  5. 若要完成此程式,您必須執行下列清除步驟:

    1. 將雜湊控制碼傳遞至 BCryptDestroyHash 函式,以關閉雜湊物件。

    2. 釋放您為雜湊物件配置的記憶體。

    3. 如果您不會再建立任何雜湊物件,請將提供者控制碼傳遞至 BCryptCloseAlgorithmProvider 函 式來關閉演算法提供者。

      如果您要建立更杜哈希物件,建議您重複使用演算法提供者,而不是多次建立和終結相同類型的演算法提供者。

    4. 當您完成使用雜湊值記憶體時,請釋放它。

下列範例示範如何使用 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);
    }

}

建立可重複使用的雜湊物件

從Windows 8和Windows Server 2012開始,您可以針對需要快速連續計算多個雜湊或 HMAC 的案例,建立可重複使用的雜湊物件。 呼叫BCryptOpenAlgorithmProvider函式時,請指定BCRYPT_HASH_REUSABLE_FLAG。 所有 Microsoft 雜湊演算法提供者都支援此旗標。 使用這個旗標所建立的雜湊物件可以在呼叫 BCryptFinishHash 之後立即重複使用,就像呼叫 BCryptCreateHash來重新建立一樣。 執行下列步驟來建立可重複使用的雜湊物件:

  1. 開啟支援所需雜湊演算法的演算法提供者。 呼叫BCryptOpenAlgorithmProvider函式,並在pszAlgId參數中指定適當的演算法識別碼,並在dwFlags參數中指定BCRYPT_HASH_REUSABLE_FLAG。 函式會傳回提供者的控制碼。

  2. 執行下列步驟來建立雜湊物件:

    1. 呼叫 BCryptGetProperty 函式來擷取 BCRYPT_OBJECT_LENGTH 屬性,以取得物件的大小。
    2. 配置記憶體來保存雜湊物件。
    3. 呼叫 BCryptCreateHash 函式來建立物件。 在dwFlags參數中指定BCRYPT_HASH_REUSABLE_FLAG
  3. 呼叫 BCryptHashData 函 式來雜湊資料。

  4. 執行下列步驟以取得雜湊值:

    1. 呼叫 BCryptGetProperty 函式以取得 BCRYPT_HASH_LENGTH 屬性,以取得雜湊值的大小。
    2. 配置記憶體來保存值。
    3. 呼叫 BCryptFinishHash以取得雜湊值。
  5. 若要重複使用具有新資料的雜湊物件,請移至步驟 3。

  6. 若要完成此程式,您必須執行下列清除步驟:

    1. 將雜湊控制碼傳遞至 BCryptDestroyHash 函式,以關閉雜湊物件。
    2. 釋放您為雜湊物件配置的記憶體。
    3. 如果您不會再建立任何雜湊物件,請將提供者控制碼傳遞至 BCryptCloseAlgorithmProvider 函 式來關閉演算法提供者。
    4. 當您完成使用雜湊值記憶體時,請釋放它。

複製雜湊物件

在某些情況下,雜湊一些常見的資料量,然後從一般資料建立兩個不同的雜湊物件可能會很有用。 您不需要建立兩個不同的雜湊物件,並雜湊一般資料兩次才能完成此作業。 您可以建立單一雜湊物件,並將所有通用資料新增至雜湊物件。 然後,您可以使用 BCryptDuplicateHash 函式來建立原始雜湊物件的複本。 重複的雜湊物件包含與原始相同的狀態資訊和雜湊資料,但它是完全獨立的雜湊物件。 您現在可以將唯一的資料新增至每個雜湊物件,並取得雜湊值,如範例所示。 當雜湊可能大量的常見資料時,這項技術很有用。 您只需要一次將一般資料新增至原始雜湊,然後您可以複製雜湊物件來取得唯一的雜湊物件。