CNG を使用したデータの署名
データ署名によってデータは保護されません。 データの整合性が検証されるだけです。 送信者は、そのデータをハッシュし、秘密キーを使用してハッシュに署名 (暗号化) します。 対象の受信者は、受信したデータのハッシュを作成し、署名を復号して元のハッシュを取得し、2 つのハッシュを比較することで検証を実行します。
データに署名するとき、送信者はハッシュ値を作成し、秘密キーを使用してハッシュに署名 (暗号化) します。 その後、この署名はデータに添付され、受信者にメッセージで送信されます。 署名の作成に使用されたハッシュ アルゴリズムは、受信者に事前に知らされているか、メッセージで識別されている必要があります。 これを行う方法は、メッセージ プロトコルによって異なります。
署名を確認するために、受信者はメッセージからデータと署名を抽出します。 次に、受信者はデータから別のハッシュ値を作成し、送信者の公開キーを使用して署名されたハッシュを復号し、2 つのハッシュ値を比較します。 値が同じ場合、署名の検証を経て、データは変更されていないと見なされます。
CNG を使用して署名を作成するには
- CNG ハッシュ関数を使用して、データのハッシュ値を作成します。 ハッシュの作成の詳細については、「CNG を使用したハッシュの作成」を参照してください。
- ハッシュに署名するための非対称キーを作成します。 CNG キー ストレージ関数を使用して永続的キーを作成するか、CNG 暗号化プリミティブ関数を使用してエフェメラル キーを作成することができます。
- NCryptSignHash または BCryptSignHash 関数を使用して、ハッシュ値に署名 (暗号化) します。 この関数は、非対称キーを使用してハッシュ値に署名します。
- データと署名を組み合わせて、対象の受信者に送信できるメッセージにします。
CNG を使用して署名を検証するには
- メッセージからデータと署名を抽出します。
- CNG ハッシュ関数を使用して、データのハッシュ値を作成します。 使用するハッシュ アルゴリズムは、ハッシュの署名に使用されたのと同じアルゴリズムである必要があります。
- ハッシュの署名に使用された非対称キー ペアの公開部分を取得します。 このキーを取得する方法は、キーが作成および永続化された方法によって異なります。 キーが CNG キー ストレージ関数で作成または読み込まれた場合は、NCryptOpenKey 関数を使用して永続化されたキーを読み込みます。 キーがエフェメラル キーである場合は、キー BLOB に保存されている必要があります。 このキー BLOB を BCryptImportKeyPair または NCryptImportKey 関数に渡す必要があります。
- 新しいハッシュ値、署名、キー ハンドルを NCryptVerifySignature または BCryptVerifySignature 関数に渡します。 これらの関数は、公開キーを使用して署名を復号し、復号したハッシュを手順 2 で計算したハッシュと比較することで検証を実行します。 BCryptVerifySignature 関数は、署名がハッシュと一致する場合は STATUS_SUCCESS を返し、署名がハッシュと一致しない場合は STATUS_INVALID_SIGNATURE を返します。 NCryptVerifySignature 関数は、署名がハッシュと一致する場合は STATUS_SUCCESS を返し、署名がハッシュと一致しない場合は NTE_BAD_SIGNATURE を返します。
データの署名と検証の例
次の例では、暗号化プリミティブ API を使用して、永続化されたキーでデータに署名し、エフェメラル キーを使用して署名を検証する方法を示します。
// 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 ECDSA 256 signing using CNG
Example for use of BCrypt/NCrypt API
Persisted key for signing and ephemeral key for verification
--*/
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#include <ncrypt.h>
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
static const BYTE rgbMsg[] =
{
0x04, 0x87, 0xec, 0x66, 0xa8, 0xbf, 0x17, 0xa6,
0xe3, 0x62, 0x6f, 0x1a, 0x55, 0xe2, 0xaf, 0x5e,
0xbc, 0x54, 0xa4, 0xdc, 0x68, 0x19, 0x3e, 0x94,
};
void __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
NCRYPT_PROV_HANDLE hProv = NULL;
NCRYPT_KEY_HANDLE hKey = NULL;
BCRYPT_KEY_HANDLE hTmpKey = NULL;
SECURITY_STATUS secStatus = ERROR_SUCCESS;
BCRYPT_ALG_HANDLE hHashAlg = NULL,
hSignAlg = NULL;
BCRYPT_HASH_HANDLE hHash = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbData = 0,
cbHash = 0,
cbBlob = 0,
cbSignature = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL,
pbBlob = NULL,
pbSignature = NULL;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(wargv);
//open an algorithm handle
if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hHashAlg,
BCRYPT_SHA1_ALGORITHM,
NULL,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hSignAlg,
BCRYPT_ECDSA_P256_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(
hHashAlg,
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(
hHashAlg,
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(
hHashAlg,
&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;
}
//open handle to KSP
if(FAILED(secStatus = NCryptOpenStorageProvider(
&hProv,
MS_KEY_STORAGE_PROVIDER,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptOpenStorageProvider\n", secStatus);
goto Cleanup;
}
//create a persisted key
if(FAILED(secStatus = NCryptCreatePersistedKey(
hProv,
&hKey,
NCRYPT_ECDSA_P256_ALGORITHM,
L"my ecc key",
0,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptCreatePersistedKey\n", secStatus);
goto Cleanup;
}
//create key on disk
if(FAILED(secStatus = NCryptFinalizeKey(hKey, 0)))
{
wprintf(L"**** Error 0x%x returned by NCryptFinalizeKey\n", secStatus);
goto Cleanup;
}
//sign the hash
if(FAILED(secStatus = NCryptSignHash(
hKey,
NULL,
pbHash,
cbHash,
NULL,
0,
&cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
goto Cleanup;
}
//allocate the signature buffer
pbSignature = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbSignature);
if(NULL == pbSignature)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if(FAILED(secStatus = NCryptSignHash(
hKey,
NULL,
pbHash,
cbHash,
pbSignature,
cbSignature,
&cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptSignHash\n", secStatus);
goto Cleanup;
}
if(FAILED(secStatus = NCryptExportKey(
hKey,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
NULL,
NULL,
0,
&cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
goto Cleanup;
}
pbBlob = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbBlob);
if(NULL == pbBlob)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if(FAILED(secStatus = NCryptExportKey(
hKey,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
NULL,
pbBlob,
cbBlob,
&cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by NCryptExportKey\n", secStatus);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptImportKeyPair(
hSignAlg,
NULL,
BCRYPT_ECCPUBLIC_BLOB,
&hTmpKey,
pbBlob,
cbBlob,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptVerifySignature(
hTmpKey,
NULL,
pbHash,
cbHash,
pbSignature,
cbSignature,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
goto Cleanup;
}
wprintf(L"Success!\n");
Cleanup:
if(hHashAlg)
{
BCryptCloseAlgorithmProvider(hHashAlg,0);
}
if(hSignAlg)
{
BCryptCloseAlgorithmProvider(hSignAlg,0);
}
if (hHash)
{
BCryptDestroyHash(hHash);
}
if(pbHashObject)
{
HeapFree(GetProcessHeap(), 0, pbHashObject);
}
if(pbHash)
{
HeapFree(GetProcessHeap(), 0, pbHash);
}
if(pbSignature)
{
HeapFree(GetProcessHeap(), 0, pbSignature);
}
if(pbBlob)
{
HeapFree(GetProcessHeap(), 0, pbBlob);
}
if (hTmpKey)
{
BCryptDestroyKey(hTmpKey);
}
if (hKey)
{
NCryptDeleteKey(hKey, 0);
}
if (hProv)
{
NCryptFreeObject(hProv);
}
}