I have two programms. One creates a persisted key and saves it to key storage provider, then signs the hash and write the sign to the regedit. Second program opens the key from provider and verifies the sign gotten from the regedit. But my problem is in 2nd program NCryptOpenKey can't find the key in key storage provider! After hours of browsing documentation and internet I still don't know why. Please point me what I am doing wrong. Code example:
Variables and Cleanup procedure:
NCRYPT_PROV_HANDLE hProv = NULL;
NCRYPT_KEY_HANDLE hKey = 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,
cbSignature = 0,
cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL,
pbSignature = NULL;
static const WCHAR* KEY_NAME = TEXT("MyPersistedKey");
void 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 (hKey)
NCryptDeleteKey(hKey, 0);
if (hProv)
NCryptFreeObject(hProv);
}
1st program
// open handle to KSP
if (FAILED(secStatus = NCryptOpenStorageProvider(&hProv, MS_KEY_STORAGE_PROVIDER, 0))) {
Cleanup();
return {};
}
// key doesn't exists. create it
if (FAILED(secStatus = NCryptCreatePersistedKey(hProv, &hKey, NCRYPT_ECDSA_P256_ALGORITHM, KEY_NAME, 0, 0))) {
Cleanup();
return {};
}
// create key on disk
if (FAILED(secStatus = NCryptFinalizeKey(hKey, 0))) {
Cleanup();
return {};
}
// get the length of the signature
if (FAILED(secStatus = NCryptSignHash(hKey, NULL, pbHash, cbHash, NULL, 0, &cbSignature, 0))) {
Cleanup();
return {};
}
// allocate the signature buffer
pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature);
if (NULL == pbSignature) {
Cleanup();
return {};
}
// sign the hash
if (FAILED(secStatus = NCryptSignHash(hKey, NULL, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, 0))) {
Cleanup();
return {};
}
2nd program
// open handle to KSP
if (FAILED(secStatus = NCryptOpenStorageProvider(&hProv, MS_KEY_STORAGE_PROVIDER, 0))) {
Cleanup();
return false;
}
// open key from KSP
if (FAILED(secStatus = NCryptOpenKey(hProv, &hKey, KEY_NAME, 0, 0))) {
Cleanup();
return false;
}
// verify signature with hash
status = NCryptVerifySignature(hKey, NULL, pbHash, cbHash, pbSignature, cbSignature, 0);
switch (status) {
case ERROR_SUCCESS: // hash is verifyied
Cleanup();
return true;
case NTE_BAD_SIGNATURE: // hash isn't verifyied
Cleanup();
return false;
default:
Cleanup();
return false;
}
According to NCryptVerifySignature ,
And you need to export the public key. See Signing Data with CNG and SignHashWithPersistedKeys examples.
To delete the key file on disk, pass the handle to the NCryptDeleteKey function. You have deleted the key in
Cleanup
.