使用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
相关产品推荐
相关产品推荐

