You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NCrypt在TPM创建密钥时遇安全描述符结构无效错误

在TPM中创建受限访问密钥时出现安全描述符无效错误

我在Windows系统中尝试用NCrypt库在TPM里创建密钥,希望只让我的C++程序能访问,但遇到错误:The security descriptor structure is invalid(安全描述符结构无效)。

为提升可读性,代码已移除所有错误控制逻辑

// 获取应用SID
DWORD pid = GetCurrentProcessId();
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);

HANDLE hToken;
OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);

DWORD bufferSize = 0;
GetTokenInformation(hToken, TokenUser, NULL, 0, &bufferSize);

PTOKEN_USER tokenUser = reinterpret_cast<PTOKEN_USER>(malloc(bufferSize));

// 我猜测tokenUser->User.Sid关联的是当前登录用户,但找不到其他能跨多次执行保持一致的进程标识符
GetTokenInformation(hToken, TokenUser, tokenUser, bufferSize, &bufferSize);

EXPLICIT_ACCESS ea[1];
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = WRITE_OWNER;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
ea[0].Trustee.ptstrName = (LPTSTR)tokenUser->User.Sid;

PACL pACL = NULL;
SetEntriesInAcl(1, ea, NULL, &pACL);

PSECURITY_DESCRIPTOR pSD = NULL;
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);

SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;

NCryptSetProperty(hKey, NCRYPT_SECURITY_DESCR_PROPERTY, reinterpret_cast<PBYTE>(&sa), sizeof(SECURITY_ATTRIBUTES), NCRYPT_PERSIST_FLAG | DACL_SECURITY_INFORMATION);

我也试过CodeGuru论坛里提到的方法,想请教:NCRYPT_SECURITY_DESCR_PROPERTY这个标志是不是还没被支持?


问题分析与解决

1. 核心错误:安全描述符传递类型错误

NCRYPT_SECURITY_DESCR_PROPERTY要求直接传入**PSECURITY_DESCRIPTOR类型的安全描述符指针**,但你代码里传递的是SECURITY_ATTRIBUTES结构体的地址,这完全不符合API参数要求,直接导致了“安全描述符结构无效”的错误。

修正后的代码行:

// 直接传递安全描述符pSD,而非SECURITY_ATTRIBUTES
NCryptSetProperty(hKey, NCRYPT_SECURITY_DESCR_PROPERTY, 
                  reinterpret_cast<PBYTE>(pSD), 
                  GetSecurityDescriptorLength(pSD), 
                  NCRYPT_PERSIST_FLAG | DACL_SECURITY_INFORMATION);

2. 权限设置不足

当前只赋予了WRITE_OWNER权限,这无法满足程序对密钥的正常访问需求。需替换为密钥操作的完整权限:

ea[0].grfAccessPermissions = NCRYPT_ALL_KEY_ACCESS;

如果需要更细粒度的控制,也可以使用细分权限组合,比如NCRYPT_READ_CONTROL | NCRYPT_EXECUTE | NCRYPT_WRITE_KEY。

3. 进程标识的误区

你想通过进程相关标识限制访问,但TokenUser获取的是当前用户SID,并非进程专属标识。Windows没有原生的“进程SID”,要实现仅自己程序可访问,更可靠的方案包括:

  • 使用程序的数字签名哈希构建ACL规则
  • 结合用户SID与程序路径设置ACL(需注意路径篡改风险)
  • 调用GetApplicationSid获取应用专属SID,以此构建权限规则

关于NCRYPT_SECURITY_DESCR_PROPERTY的支持情况

该标志在Windows 8及以上系统中是完全支持的,TPM驱动也兼容此属性。之前的错误并非标志不支持,而是参数传递类型错误导致的。


内容的提问来源于stack exchange,提问作者matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 01:03:11