使用 CNG 建立雜湊
雜湊是在資料區塊上執行的一種方式作業,可建立代表資料內容的唯一雜湊值。 不論何時執行雜湊,在相同資料上執行的相同 雜湊演算法 一律會產生相同的雜湊值。 如果有任何資料變更,雜湊值將會適當地變更。
雜湊不適用於加密資料,因為它們不是用來從雜湊值重現原始資料。 雜湊最適合用來驗證與非對稱簽署演算法搭配使用的資料完整性。 例如,如果您已雜湊文字訊息、簽署雜湊,並將已簽署的雜湊值包含在原始訊息中,收件者可以驗證已簽署的雜湊、建立已接收訊息的雜湊值,然後將此雜湊值與原始訊息隨附的已簽署雜湊值進行比較。 如果兩個雜湊值相同,收件者可以合理地確定原始郵件尚未修改。
特定雜湊演算法的雜湊值大小是固定的。 這表示無論資料區塊的大小或小數為何,雜湊值一律會是相同的大小。 例如,SHA256 雜湊演算法的雜湊值大小為 256 位。
建立雜湊物件
若要使用 CNG 建立雜湊,請執行下列步驟:
開啟支援所需演算法的演算法提供者。 典型的雜湊演算法包括 MD2、MD4、MD5、SHA-1 和 SHA256。 呼叫 BCryptOpenAlgorithmProvider 函 式,並在 pszAlgId 參數中指定適當的演算法識別碼。 函式會傳回提供者的控制碼。
執行下列步驟來建立雜湊物件:
- 呼叫 BCryptGetProperty 函式來擷取 BCRYPT_OBJECT_LENGTH 屬性,以取得物件的大小。
- 配置記憶體來保存雜湊物件。
- 呼叫 BCryptCreateHash 函式來建立物件。
雜湊資料。 這牽涉到呼叫 BCryptHashData 函式一或多次。 每個呼叫都會將指定的資料附加至雜湊。
執行下列步驟以取得雜湊值:
- 呼叫 BCryptGetProperty 函式以取得 BCRYPT_HASH_LENGTH 屬性,以擷取值的大小。
- 配置記憶體來保存值。
- 呼叫 BCryptFinishHash 函式來擷取雜湊值。 呼叫此函式之後,雜湊物件就不再有效。
若要完成此程式,您必須執行下列清除步驟:
將雜湊控制碼傳遞至 BCryptDestroyHash 函式,以關閉雜湊物件。
釋放您為雜湊物件配置的記憶體。
如果您不會再建立任何雜湊物件,請將提供者控制碼傳遞至 BCryptCloseAlgorithmProvider 函 式來關閉演算法提供者。
如果您要建立更杜哈希物件,建議您重複使用演算法提供者,而不是多次建立和終結相同類型的演算法提供者。
當您完成使用雜湊值記憶體時,請釋放它。
下列範例示範如何使用 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來重新建立一樣。 執行下列步驟來建立可重複使用的雜湊物件:
開啟支援所需雜湊演算法的演算法提供者。 呼叫BCryptOpenAlgorithmProvider函式,並在pszAlgId參數中指定適當的演算法識別碼,並在dwFlags參數中指定BCRYPT_HASH_REUSABLE_FLAG。 函式會傳回提供者的控制碼。
執行下列步驟來建立雜湊物件:
- 呼叫 BCryptGetProperty 函式來擷取 BCRYPT_OBJECT_LENGTH 屬性,以取得物件的大小。
- 配置記憶體來保存雜湊物件。
- 呼叫 BCryptCreateHash 函式來建立物件。 在dwFlags參數中指定BCRYPT_HASH_REUSABLE_FLAG。
呼叫 BCryptHashData 函 式來雜湊資料。
執行下列步驟以取得雜湊值:
- 呼叫 BCryptGetProperty 函式以取得 BCRYPT_HASH_LENGTH 屬性,以取得雜湊值的大小。
- 配置記憶體來保存值。
- 呼叫 BCryptFinishHash以取得雜湊值。
若要重複使用具有新資料的雜湊物件,請移至步驟 3。
若要完成此程式,您必須執行下列清除步驟:
- 將雜湊控制碼傳遞至 BCryptDestroyHash 函式,以關閉雜湊物件。
- 釋放您為雜湊物件配置的記憶體。
- 如果您不會再建立任何雜湊物件,請將提供者控制碼傳遞至 BCryptCloseAlgorithmProvider 函 式來關閉演算法提供者。
- 當您完成使用雜湊值記憶體時,請釋放它。
複製雜湊物件
在某些情況下,雜湊一些常見的資料量,然後從一般資料建立兩個不同的雜湊物件可能會很有用。 您不需要建立兩個不同的雜湊物件,並雜湊一般資料兩次才能完成此作業。 您可以建立單一雜湊物件,並將所有通用資料新增至雜湊物件。 然後,您可以使用 BCryptDuplicateHash 函式來建立原始雜湊物件的複本。 重複的雜湊物件包含與原始相同的狀態資訊和雜湊資料,但它是完全獨立的雜湊物件。 您現在可以將唯一的資料新增至每個雜湊物件,並取得雜湊值,如範例所示。 當雜湊可能大量的常見資料時,這項技術很有用。 您只需要一次將一般資料新增至原始雜湊,然後您可以複製雜湊物件來取得唯一的雜湊物件。