CNG を使用したハッシュの作成
ハッシュは、データの内容を表す一意のハッシュ値を作成するためにデータ ブロックに対して実行される一方向の操作です。 ハッシュがいつ実行されても、同じデータに対して同じ ハッシュ アルゴリズム が実行されると、常に同じハッシュ値が生成されます。 いずれかのデータが変更された場合、ハッシュ値は適切に変更されます。
ハッシュは、ハッシュ値から元のデータを再現するために使用されることを意図していないため、データの暗号化には役立ちません。 ハッシュは、非対称署名アルゴリズムで使用する場合にデータの整合性を確認するのに最も役立ちます。 たとえば、テキスト メッセージをハッシュし、ハッシュに署名し、署名されたハッシュ値を元のメッセージと共に含めた場合、受信者は署名されたハッシュを確認し、受信したメッセージのハッシュ値を作成し、このハッシュ値を元のメッセージに含まれる署名付きハッシュ値と比較できます。 2 つのハッシュ値が同じ場合、受信者は元のメッセージが変更されていないことを合理的に確認できます。
ハッシュ値のサイズは、特定のハッシュ アルゴリズムに対して固定されます。 つまり、データ ブロックの大きさや小ささにかかわらず、ハッシュ値は常に同じサイズになります。 たとえば、SHA256 ハッシュ アルゴリズムのハッシュ値サイズは 256 ビットです。
ハッシュ オブジェクトの作成
CNG を使用してハッシュを作成するには、次の手順に従います。
目的のアルゴリズムをサポートするアルゴリズム プロバイダーを開きます。 一般的なハッシュ アルゴリズムには、MD2、MD4、MD5、SHA-1、SHA256 が含まれます。 BCryptOpenAlgorithmProvider 関数を呼び出し、pszAlgId パラメーターに適切なアルゴリズム識別子を指定します。 関数は、プロバイダーにハンドルを返します。
ハッシュ オブジェクトを作成するには、次の手順を実行します。
- BCryptGetProperty 関数を呼び出してオブジェクトのサイズを取得し、BCRYPT_OBJECT_LENGTH プロパティを取得します。
- ハッシュ オブジェクトを保持するためにメモリを割り当てます。
- BCryptCreateHash 関数を呼び出してオブジェクトを作成します。
データをハッシュします。 これには、 BCryptHashData 関数を 1 回以上呼び出す必要があります。 各呼び出しでは、指定したデータがハッシュに追加されます。
ハッシュ値を取得するには、次の手順を実行します。
- 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 ハッシュ アルゴリズム プロバイダーがこのフラグをサポートしています。 このフラグを使用して作成されたハッシュ オブジェクトは、 BCryptCreateHash を呼び出して新しく作成されたかのように、 BCryptFinishHash を呼び出した直後に再利用できます。 再利用可能なハッシュ オブジェクトを作成するには、次の手順を実行します。
目的のハッシュ アルゴリズムをサポートするアルゴリズム プロバイダーを開きます。 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 関数に渡してアルゴリズム プロバイダーを閉じます。
- ハッシュ値メモリの使用が完了したら、解放します。
ハッシュ オブジェクトの複製
状況によっては、ある程度の共通データをハッシュしてから、共通データから 2 つの個別のハッシュ オブジェクトを作成すると便利な場合があります。 これを実現するために、2 つの個別のハッシュ オブジェクトを作成し、共通データを 2 回ハッシュする必要はありません。 1 つのハッシュ オブジェクトを作成し、すべての共通データをハッシュ オブジェクトに追加できます。 次に、 BCryptDuplicateHash 関数を使用して、元のハッシュ オブジェクトの複製を作成できます。 重複するハッシュ オブジェクトには、元と同じ状態情報とハッシュされたデータがすべて含まれますが、完全に独立したハッシュ オブジェクトです。 各ハッシュ オブジェクトに一意のデータを追加し、例に示すようにハッシュ値を取得できるようになりました。 この手法は、大量の共通データをハッシュする場合に便利です。 共通データを元のハッシュに 1 回だけ追加するだけで、ハッシュ オブジェクトを複製して一意のハッシュ オブジェクトを取得できます。