NCryptCreateClaim 函数 (ncrypt.h)

创建密钥证明声明。

语法

SECURITY_STATUS NCryptCreateClaim(
  [in]           NCRYPT_KEY_HANDLE hSubjectKey,
  [in, optional] NCRYPT_KEY_HANDLE hAuthorityKey,
  [in]           DWORD             dwClaimType,
  [in, optional] NCryptBufferDesc  *pParameterList,
  [out]          PBYTE             pbClaimBlob,
  [in]           DWORD             cbClaimBlob,
  [out]          DWORD             *pcbResult,
  [in]           DWORD             dwFlags
);

参数

[in] hSubjectKey

为其创建声明的主题密钥句柄。

[in, optional] hAuthorityKey

声明所基于的颁发机构密钥句柄。

[in] dwClaimType

声明的类型。

[in, optional] pParameterList

可选参数列表。

[out] pbClaimBlob

创建的声明 Blob 的输出。

[in] cbClaimBlob

pbClaimBlob 缓冲区的大小(以字节为单位)。

[out] pcbResult

创建的声明 Blob 的输出。

[in] dwFlags

目前未定义任何标志。 dwFlags 参数应设置为 0

返回值

返回一个状态代码,指示函数的成功或失败。

言论

使用基于虚拟化的安全性保护/证明私钥(VBS)

注意

有关 VBS 标志的信息与预发布产品有关,该产品在商业发布之前可能会进行大幅修改。 Microsoft对此处提供的信息不作任何明示或暗示的保证。

此 API 有助于基于 VBS 密钥保护(用于使用 VBS 保护/证明私钥的 Windows 模块)启用安全密钥的高级证明。 安全密钥的证明证明证明此密钥与定位密钥(即证明密钥)关联。 此功能可以通过限制使用上下文键来提高不同实体之间的通信安全级别。

API 定义新的标志,以支持基于 VBS 密钥保护中的证明密钥创建和验证证明声明。

以下是为 API 定义的 dwClaimType 类型

声明类型 描述
NCRYPT_CLAIM_VBS_ROOT 此类型指示生成的声明是由 VBS 根密钥生成的。
NCRYPT_CLAIM_VBS_IDENTITY 此类型指示生成的声明由 VBS 标识/证明生成。 这意味着声明是由使用证明标志 NCRYPT_ALLOW_KEY_ATTESTATION_FLAG 提升的 VBS 密钥生成的(请参阅下文的详细信息)。

以下是在创建证明声明时在 pParameterList 缓冲区中设置的缓冲区类型:

缓冲区类型 描述
NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_HASH NCryptCreateClaim中创建证明声明时,在参数缓冲区中设置的缓冲区类型。 这是 NCRYPT_CLAIM_VBS_IDENTITY 声明的必需参数类型。

此参数配置要通过证明声明创建使用的哈希函数类型的类型。 此参数的值在 ncrypt.h 中定义(例如 CNG 算法标识符中的常量):

#define NCRYPT_SHA1_ALGORITHM BCRYPT_SHA1_ALGORITHM
#define NCRYPT_SHA256_ALGORITHM BCRYPT_SHA256_ALGORITHM
#define NCRYPT_SHA384_ALGORITHM BCRYPT_SHA384_ALGORITHM
#define NCRYPT_SHA512_ALGORITHM BCRYPT_SHA512_ALGORITHM
NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_SCHEME NCryptCreateClaim中创建证明声明时,在参数缓冲区中设置的缓冲区类型。 如果创建的 NCRYPT_CLAIM_VBS_IDENTITY 声明中的证明密钥是 RSA 密钥,则这是一个必需参数。

此参数配置签名函数类型的填充方案,以便通过证明声明创建使用。 此参数的可选值在 bcrypt.h 中定义(如 NCryptSignHash中的 dwFlags 常量):

#define BCRYPT_PAD_PSS 0x00000008
NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_ALGO NCryptCreateClaim中创建证明声明时,将在参数缓冲区中设置的新缓冲区类型。 如果创建的 NCRYPT_CLAIM_VBS_IDENTITY 声明中的证明密钥是 RSA 密钥,则这是一个必需参数。 该参数是指向以 null 结尾的 Unicode 字符串的指针,该字符串标识用于创建填充的加密算法。 此算法必须是哈希算法。 此参数的值在 ncrypt.h 中定义(例如 CNG 算法标识符中的常量):

#define NCRYPT_SHA1_ALGORITHM BCRYPT_SHA1_ALGORITHM
#define NCRYPT_SHA256_ALGORITHM BCRYPT_SHA256_ALGORITHM
#define NCRYPT_SHA384_ALGORITHM BCRYPT_SHA384_ALGORITHM
#define NCRYPT_SHA512_ALGORITHM BCRYPT_SHA512_ALGORITHM
NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_SALT_SIZE NCryptCreateClaim中创建证明声明时,将在参数缓冲区中设置的新缓冲区类型。 如果创建的 NCRYPT_CLAIM_VBS_IDENTITY 声明中的证明密钥是 RSA 密钥,则这是一个必需参数。

参数表示要用于填充的随机盐的大小(以字节为单位)。
NCRYPTBUFFER_ATTESTATION_STATEMENT_NONCE NCryptCreateClaim中创建证明声明时,在参数缓冲区中设置的缓冲区类型。 此参数是 NCRYPTBUFFER_CLAIM_KEYATTESTATION_NONCE的别名。

例子

此示例说明了新 API 标志 NCRYPT_ALLOW_KEY_ATTESTATION_FLAG的用法。 此外,声明创建的 nonce 值由 NCRYPTBUFFER_ATTESTATION_STATEMENT_NONCE 参数类型设置。

该示例由以下主要步骤组成:

  1. 将创建新的证明密钥。 密钥是专用于使用 API 函数 NCryptSetProperty。 证明的生成基于签名密钥。
  2. 为进一步证明而创建声明。 声明与证明密钥和内置 VBS 密钥相关联。 可以通过提供证明密钥在 NCryptVerifyClaim 中验证声明。
  3. 释放证明密钥对象以避免内存泄漏。
// Create an attestation/identity key. This function is invoked in the main code flow below.
NCRYPT_KEY_HANDLE CreateAttestationKey(NCRYPT_PROV_HANDLE provider)
{

    NCRYPT_KEY_HANDLE attestationKey = NULL;
    HRESULT hr;

    if (FAILED(hr = NCryptCreatePersistedKey(
                    provider,
                    &attestationKey,
                    BCRYPT_RSA_ALGORITHM,
                    L"AttestationKey", // a unique name for the attestation key in the key store
                    0, //dwLegacyKeySpec, not used
                    NCRYPT_REQUIRE_VBS_FLAG/*This flag targets VBS */)))
    {
        wprintf(L"Error creating an Attestation Identity Key with NCryptCreatePersistedKey(): 0x%X\n", hr);
        goto cleanup;
    }

    // This is a new flag. It’s used to enable the capability in an attestation key.
    DWORD keyUsagePolicy = NCRYPT_ALLOW_KEY_ATTESTATION_FLAG;
    if (FAILED(hr = NCryptSetProperty(
                    attestationKey,
                    NCRYPT_KEY_USAGE_PROPERTY,
                    (PUCHAR)&keyUsagePolicy,
                    sizeof(keyUsagePolicy),
                    0 /*dwFlags*/)))
    {
        wprintf(L"Error setting property with NCryptSetProperty (): 0x%X\n", hr);
        goto cleanup;
    }

    DWORD keySizeBits = 2048; // minimum allowed RSA key size
    if (FAILED(hr = NCryptSetProperty(
                    attestationKey,
                    NCRYPT_LENGTH_PROPERTY,
                    (PUCHAR)&keySizeBits,
                    sizeof(keySizeBits),
                    0 /*dwFlags*/)))
    {
        wprintf(L"Error setting property with NCryptSetProperty (): 0x%X\n", hr);
        goto cleanup;
    }
    
    if (FAILED(hr = NCryptFinalizeKey(attestationKey, 0 /*dwFlags*/)))
    {
        wprintf(L"Error finalizing key with NCryptFinalizeKey (): 0x%X\n", hr);
        goto cleanup;
    }

    return attestationKey;
cleanup:
    if (attestationKey != NULL)
    {
        NCryptFreeObject(attestationKey);
    }

    return NULL;
}

HRESULT CreateAttestation()
{
    HRESULT hr = S_OK;
    NCRYPT_PROV_HANDLE provider = NULL;
    
    BYTE nonce[] = "TheSuperSecretNonce";
    // This way of setting parameters is an existent pattern for NCrypt APIs
    NCryptBuffer paramBuffers[] =
    {
        { sizeof(nonce), NCRYPTBUFFER_ATTESTATION_STATEMENT_NONCE, (PBYTE)&nonce },
    };
    NCryptBufferDesc params = { NCRYPTBUFFER_VERSION, ARRAYSIZE(paramBuffers), paramBuffers };
    
    if (FAILED(hr = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0)))
    {
        wprintf(L"Error opening storage provider in NCryptOpenStorageProvider: 0x%X\n", hr);
        goto cleanup;
    }
    
    // Create a VBS attestation key
    NCRYPT_KEY_HANDLE attestationKey = CreateAttestationKey(provider);
    if (attestationKey == NULL)
    {
        hr = E_ABORT;
        goto cleanup;
    }
    
    DWORD bytesWritten = 0;
    
    if (FAILED(hr = NCryptCreateClaim(
                    attestationKey, // key that is being attested here and may attest other keys.
                    NULL, // implies that IDKS (VBS root signing key) will be used.
                    NCRYPT_CLAIM_VBS_ROOT, // used to attest a key with IDKS (VBS root signing key).
                    &params, // parameters list
                    NULL, // getting the size
                    0, // getting the size
                    &bytesWritten,
                    0 /*dwFlags*/)))
    {
        wprintf(L"Error creating claim with NCryptCreateClaim (): 0x%X\n", hr);
        goto cleanup;
    }
    
    DWORD claimBufferSize = bytesWritten;
    
    PBYTE claimBuffer = (PBYTE) HeapAlloc(GetProcessHeap(), 0,claimBufferSize);
    if (NULL == claimBuffer)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        wprintf(L"Error allocating buffer for the claim: 0x%X\n", hr);
        goto cleanup;
    }
    
    bytesWritten = 0;
    if (FAILED(hr = NCryptCreateClaim(
                    attestationKey, // key that is being attested here and may attest other keys.
                    NULL, //implies that IDKS (VBS root signing key) will be used.
                    NCRYPT_CLAIM_VBS_ROOT, // used to attest with IDKS (VBS root signing key).
                    &params, // parameters list
                    claimBuffer,
                    claimBufferSize,
                    &bytesWritten,
                    0)))
    {
        wprintf(L"Error creating claim with NCryptCreateClaim (): 0x%X\n", hr);
        goto cleanup;
    }
    
    wprintf(L"The claim is created successfully. It may be shared with the verifier side.\n");

cleanup:
    if (provider != NULL)
    {
        NCryptFreeObject(provider);
    }
    if (attestationKey != NULL)
    {
        NCryptFreeObject(attestationKey);
    }
    if (claimBuffer)
    {
        HeapFree(GetProcessHeap(), 0, claimBuffer);
    }
    
    return hr;
}

下一个示例演示如何使用新的 API 参数来创建常规用途加密密钥和关联的证明声明。 此常规用途密钥用于生成证明声明。

声明创建的哈希算法类型和填充分别在 NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_HASHNCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_ [SCHEME/ALGO/SALT_SIZE] 参数中设置。

请注意:

  • NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_HASH 参数仅适用于 NCRYPT_CLAIM_VBS_IDENTITY 声明,在其他类型的声明中毫无意义。
  • NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING 参数仅在 RSA 证明密钥的情况下对 NCRYPT_CLAIM_VBS_IDENTITY 声明是必需的。 在其他类型的声明中,这是毫无意义的。

声明使我们能够验证常规用途密钥是否与证明密钥相关联。

//
HRESULT hr = S_OK;
NCRYPT_PROV_HANDLE provider = NULL;

if (FAILED(hr = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0)))
{
    wprintf(L"Error opening storage provider in NCryptOpenStorageProvider: 0x%X\n", hr);
    goto cleanup;
}

NCRYPT_KEY_HANDLE attestationKey = NULL;

// Open the attestation key, created in CreateAttestationKey(), see previous example
if (FAILED(hr = NCryptOpenKey(
                provider,
                &attestationKey,
                L"AttestationKey",
                0, //dwLegacyKeySpec, not used
                0 ,/* dwFlags */)))
{
    wprintf(L"Error openning the attestation key with NCryptOpenKey (): 0x%X\n", hr);
    goto cleanup;
}

NCRYPT_KEY_HANDLE tokenKey = NULL; // Token key that is bound to the security token

// Create VBS token (general purpose) key
if (FAILED(hr = NCryptCreatePersistedKey(
                provider,
                &tokenKey,
                BCRYPT_RSA_ALGORITHM,
                L"TokenKey",
                0, //dwLegacyKeySpec, not used
                NCRYPT_REQUIRE_VBS_FLAG /*This flag targets VBS*/)))
{
    wprintf(L"Error creating an token key with NCryptCreatePersistedKey(): 0x%X\n", hr);
    goto cleanup;
}

DWORD keySizeBits = 2048;
if (FAILED(hr = NCryptSetProperty(
                tokenKey,
                NCRYPT_LENGTH_PROPERTY,
                (PUCHAR)&keySizeBits,
                sizeof(keySizeBits),
                0 /*dwFlags*/)))
{
    wprintf(L"Error setting property with NCryptSetProperty (): 0x%X\n", hr);
    goto cleanup;
}

if (FAILED(hr = NCryptFinalizeKey(tokenKey, 0 /*dwFlags*/)))
{
    wprintf(L"Error finalizing key with NCryptFinalizeKey (): 0x%X\n", hr);
    goto cleanup;
}

DWORD bytesWritten = 0;

DWORD hashAlgoType; // This is a new flag. It’s used to set type of hash algorithm of the claim// Set specific hash function type to produce the claim
wchar_t pHashAlgo[] = NCRYPT_SHA512_ALGORITHM;
// Set specific padding scheme for hash function to produce the claim
ULONG paddingScheme = BCRYPT_PAD_PSS;
wchar_t pPaddingAlgo[] = NCRYPT_SHA256_ALGORITHM;
ULONG paddingSalt = 345;

// This way of setting parameters is an existent pattern for NCrypt APIs
NCryptBuffer paramBuffers[] =
{
    { sizeof(NCRYPT_SHA512_ALGORITHM), NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_HASH, (PBYTE)&pHashAlgo },
    { sizeof(paddingScheme), NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_SCHEME , (PBYTE)&paddingScheme },
    { sizeof(NCRYPT_SHA256_ALGORITHM), NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_ALGO, (PBYTE)&pPaddingAlgo },
    { sizeof(paddingSalt, NCRYPTBUFFER_ATTESTATION_STATEMENT_SIGNATURE_PADDING_SALT_SIZE, (PBYTE)&paddingSalt }
};
NCryptBufferDesc params = { NCRYPTBUFFER_VERSION, ARRAYSIZE(paramBuffers), paramBuffers };

if (FAILED(hr = NCryptCreateClaim(
                tokenKey, // key that is being attested
                attestationKey,
                NCRYPT_CLAIM_VBS_IDENTITY, // attest general-purpose key with an attestation (identity) key.
                &params, // parameters list
                NULL, // getting the size
                0, // getting the size
                &bytesWritten,
                0 /*dwFlags*/)))
{
    wprintf(L"Error creating claim with NCryptCreateClaim (): 0x%X\n", hr);
    goto cleanup;
}

DWORD claimBufferSize = bytesWritten;

PBYTE claimBuffer = (PBYTE) HeapAlloc(GetProcessHeap(), 0,claimBufferSize);
if (NULL == claimBuffer)
{
    hr = HRESULT_FROM_WIN32(GetLastError());
    wprintf(L"Error allocating buffer for the claim: 0x%X\n", hr);
    goto cleanup;
}
bytesWritten = 0;

if (FAILED(hr = NCryptCreateClaim(
                tokenKey, // key that is being attested
                attestationKey, // we assume that it is already initialized
                NCRYPT_CLAIM_VBS_IDENTITY, // attest general-purpose key with an attestation (identity) key
                &params,
                claimBuffer,
                claimBufferSize,
                &bytesWritten,
                0)))
{
    wprintf(L"Error creating claim with NCryptCreateClaim (): 0x%X\n", hr);
    goto cleanup;
}

wprintf(L"The claim is created successfully. It may be shared with the verifier side.\n");

cleanup:
    if (provider != NULL)
    {
    NCryptFreeObject(provider);
    }
    if (tokenKey != NULL)
    {
    NCryptFreeObject(tokenKey);
    }
    if (attestationKey != NULL)
    {
    NCryptDeleteKey(attestationKey);
    }
    if (claimBuffer)
    {
    HeapFree(GetProcessHeap(), 0, claimBuffer);
    }
    
return hr;

要求

要求 价值
最低支持的客户端 Windows 10 [桌面应用 |UWP 应用]
支持的最低服务器 Windows Server 2016 [桌面应用 |UWP 应用]
目标平台 窗户
标头 ncrypt.h
Ncrypt.lib
DLL Ncrypt.dll