C++ CNG NCrypt: Can't open persisted key from Key Storage Provider

526 Views Asked by At

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;
}
1

There are 1 best solutions below

0
On

According to NCryptVerifySignature ,

The handle of the key must be an identical key(Symmetric keys) or the public key portion of the key pair(Asymmetric keys) used to sign the data with the NCryptSignHash function.

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.