CryptoNextGeneration : Storing a key in the TPM
Asked Answered
P

2

3

I am currently working on a small sample program using Crypto Next Generation (Windows Crypto API) to generate a key, store it in the TPM on my computer, encrypt some data and then retrieve it and decrypt the data.

My choice of RSA encryption is because it is the only algorithm my TPM supports.

I understand I can access the TPM as a provider using:

// Open handle to TPM
if (FAILED(secStatus = NCryptOpenStorageProvider(
    &hProv,
    MS_PLATFORM_CRYPTO_PROVIDER,
    0)))
{
    wprintf(L"**** Error 0x%x returned by NCryptOpenStorageProvider\n", secStatus);
    goto Cleanup;
}

And that I can generate the key (which documentation states should save this in my provider):

    // Create a persistent key
    if (FAILED(secStatus = NCryptCreatePersistedKey(
        hProv,
        &hKey,
        NCRYPT_RSA_ALGORITHM,
        L"RSAKey0",
        0,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptCreatePersistedKey\n", secStatus);
        goto Cleanup;
    }

(and then set length, finalize, etc)

And it appears my data is encrypted by running:

    // Encrypt Data
    if (!NT_SUCCESS(status = NCryptEncrypt(
        hKey,                    // hKey
        InputData,               // pbInput
        InputDataSize,           // cbInput
        NULL,                    // pPaddingInfo
        encryptedBuffer,         // pbOutput
        encryptedBufferSize,     // cbOutput
        &encryptedBufferSize,    // pcbResult
        NCRYPT_PAD_PKCS1_FLAG))) // dwFlags
    {
        wprintf(L"**** Failed to encrypt data. Error 0x%x returned by NCryptEncrypt\n", status);
        goto Cleanup;
    }

This appears to work alright with no errors and the data looks encrypted. (I fear I may be misunderstanding the function usage here with RSA encryption and generating a persistent key as opposed to a key pair, but because I am not looking to need to share a public key, I assume this should work)

But, when trying to retrieve the key using:

    // Get key from TPM
    if (FAILED(secStatus = NCryptOpenKey(
        hProv,
        &hKey,
        L"RSAKey0",
        0,
        0)))
    {
        wprintf(L"**** Error 0x%x returned by NCryptOpenKey\n", secStatus);
        goto Cleanup;
    }

I receive an error of NTE_BAD_KEYSET. Which indicates the key was not found.

Potentially, the only function I see that I may be missing is NCryptExportKey, but if I understand it right that exports the key to a blob of memory and not to the TPM (which should have been saved upon CreatePersistedKey).

Am I missing a step to ensure the key is stored in my TPM?

Also, I am using NCryptDeleteKey as cleanup of my encryption function, but the documentation states that this just frees the key handle and not the actual stored key. How do you delete a key from the TPM after storing it there?

Perretta answered 15/4, 2020 at 1:7 Comment(1)
I've migrated to SO because this is an implementation specific issue. Please make sure that other users can fully understand how your answer solves the issue when self-answering.Quathlamba
P
1

NCryptDeleteKey does delete the key from your TPM as well as cleaning up the handle.

This was discovered through experimentation with enum and listing keys.

Perretta answered 16/4, 2020 at 0:30 Comment(0)
B
2

NCryptCreatePersistedKey needs to be followed up by a call to NCryptFinalizeKey() or it is never actually stored to the TPM. That's where the actual magic happens. For instance, if you are not elevated / admin it will fail with E_ACCESS here.

Bugaboo answered 1/10, 2021 at 20:25 Comment(0)
P
1

NCryptDeleteKey does delete the key from your TPM as well as cleaning up the handle.

This was discovered through experimentation with enum and listing keys.

Perretta answered 16/4, 2020 at 0:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.