驱动程序可以选择性地支持以下内容保护 DDI 函数:
- EncryptionBlt 函数从受保护的图面读取加密数据。
- GetPitch 函数检索受保护图面的间距。
- StartSessionKeyRefresh 函数返回一个随机数,解码器/应用程序和驱动程序/硬件随后可以使用该随机数执行独占 OR 操作, (XOR) 会话密钥。
- FinishSessionKeyRefresh 函数指示来自该时间点的所有缓冲区都将使用更新的会话键值。
- GetEncryptionBltKey 函数返回用于解密驱动程序的 EncryptionBlt 函数返回的数据的密钥。
- DecryptionBlt 函数将数据写入受保护的图面。
1. EncryptionBlt - 受保护图面数据读取
1.1 函数原型
HRESULT APIENTRY EncryptionBlt(
D3DDDIARG_ENCRYPTIONBLT* pEncryptBlt);
1.2 实现要点
HRESULT APIENTRY EncryptionBlt(D3DDDIARG_ENCRYPTIONBLT* pEncryptBlt)
{
// 验证输入参数
if (!pEncryptBlt->hSrcResource || !pEncryptBlt->pEncryptedBlock)
return E_INVALIDARG;
// 检查资源保护状态
if (!IsResourceProtected(pEncryptBlt->hSrcResource))
return D3DDDIERR_INVALIDPROTECT;
// 获取加密密钥句柄
HCRYPTKEY hKey = GetCurrentSessionKey();
// 使用硬件加密引擎
if (FAILED(HW_EncryptSurface(
pEncryptBlt->hSrcResource,
pEncryptBlt->pEncryptedBlock,
pEncryptBlt->EncryptedBlockSize,
hKey))) {
return E_FAIL;
}
return S_OK;
}
安全要求:
必须验证源资源具有D3DUSAGE_PROTECTED标志
加密操作应在安全执行环境(TEE)中完成
输出数据必须使用会话密钥加密
2. GetPitch - 获取受保护图面间距
2.1 典型实现
HRESULT APIENTRY GetPitch(
D3DDDIARG_GETPITCH* pGetPitch)
{
RESOURCE_CTX* pResCtx = (RESOURCE_CTX*)pGetPitch->hResource;
// 保护资源需要特殊对齐
if (pResCtx->Flags.Protected) {
pGetPitch->Pitch = ALIGN_UP(pResCtx->Width, 64);
} else {
pGetPitch->Pitch = pResCtx->Pitch;
}
return S_OK;
}
注意事项:
- 保护图面通常需要64字节或128字节对齐
- 间距值应匹配硬件加密引擎要求
3. 会话密钥刷新机制
3.1 StartSessionKeyRefresh
HRESULT APIENTRY StartSessionKeyRefresh(
D3DDDIARG_STARTSESSIONKEYREFRESH* pKeyRefresh)
{
CRYPTO_SESSION_CTX* pSession =
(CRYPTO_SESSION_CTX*)pKeyRefresh->hCryptoSession;
// 生成安全随机数
BCryptGenRandom(
NULL,
pKeyRefresh->pRandomNumber,
pKeyRefresh->RandomNumberSize,
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
// 保存原始密钥用于过渡期
pSession->PendingKeyRefresh = TRUE;
memcpy(pSession->OldKey, pSession->CurrentKey, KEY_SIZE);
return S_OK;
}
3.2 FinishSessionKeyRefresh
HRESULT APIENTRY FinishSessionKeyRefresh(
D3DDDIARG_FINISHSESSIONKEYREFRESH* pKeyRefresh)
{
CRYPTO_SESSION_CTX* pSession =
(CRYPTO_SESSION_CTX*)pKeyRefresh->hCryptoSession;
if (!pSession->PendingKeyRefresh)
return D3DDDIERR_INVALIDCALL;
// 应用新密钥
XOR_Keys(pSession->CurrentKey, pKeyRefresh->pXORKey);
// 清除过渡状态
pSession->PendingKeyRefresh = FALSE;
SecureZeroMemory(pSession->OldKey, KEY_SIZE);
return S_OK;
}
密钥刷新流程:
4. GetEncryptionBltKey - 获取解密密钥
4.1 安全实现
HRESULT APIENTRY GetEncryptionBltKey(
D3DDDIARG_GETENCRYPTIONBLTKEY* pKeyData)
{
if (!pKeyData->hCryptoSession)
return E_INVALIDARG;
CRYPTO_SESSION_CTX* pSession =
(CRYPTO_SESSION_CTX*)pKeyData->hCryptoSession;
// 密钥必须加密传输
if (FAILED(EncryptKeyForTransport(
pSession->CurrentKey,
pKeyData->pKey,
pKeyData->KeySize))) {
return E_FAIL;
}
return S_OK;
}
保护措施:
- 使用接收方公钥加密传输密钥
- 限制密钥有效时间(通常<2秒)
5. DecryptionBlt - 受保护图面写入
5.1 完整实现
HRESULT APIENTRY DecryptionBlt(
D3DDDIARG_DECRYPTIONBLT* pDecryptBlt)
{
// 参数验证
if (!pDecryptBlt->hDstResource || !pDecryptBlt->pEncryptedBlock)
return E_INVALIDARG;
// 检查目标保护状态
if (!IsResourceProtected(pDecryptBlt->hDstResource))
return D3DDDIERR_INVALIDPROTECT;
// 获取当前会话密钥
HCRYPTKEY hKey = GetCurrentSessionKey();
// 硬件解密操作
if (FAILED(HW_DecryptToSurface(
pDecryptBlt->pEncryptedBlock,
pDecryptBlt->EncryptedBlockSize,
pDecryptBlt->hDstResource,
hKey))) {
return E_FAIL;
}
return S_OK;
}
6. 安全架构设计
6.1 密钥生命周期管理
stateDiagram-v2
[*] --> KeyGen: CreateCryptoSession
KeyGen --> Active: 正常使用
Active --> Refreshing: StartRefresh
Refreshing --> Active: FinishRefresh
Active --> Revoked: 检测到攻击
Revoked --> [*]
6.2 内存保护机制
typedef struct _PROTECTED_RESOURCE {
D3DKMT_HANDLE hAllocation;
BOOL IsEncrypted;
PHYSICAL_ADDRESS SecurePA; // 受保护物理地址
CRYPTO_KEY_HANDLE hKey; // 关联密钥
} PROTECTED_RESOURCE;
7. 性能优化技巧
批量加密操作:
void OptimizedEncryptionBlt()
{
if (SupportsBulkEncrypt()) {
HW_BulkEncrypt(/* 多个表面 */);
} else {
// 回退到单表面处理
}
}
密钥缓存:
class KeyCache {
public:
void CacheKey(HCRYPTOKEY hKey, const BYTE* pKeyData) {
m_cache[hKey] = SecureDuplicateKey(pKeyData);
}
private:
std::map<HCRYPTOKEY, SecureKey> m_cache;
};
8. 认证测试要求
WHQL测试项目:
- 强制密钥刷新测试
- 加密/解密往返验证
- 无效句柄测试
抗攻击测试:
# 伪代码:模拟中间人攻击
def test_key_refresh_attack():
orig_key = get_key()
start_refresh()
inject_fake_key()
assert system_rejects_finish()
9. 错误处理规范
错误码 | 描述 |
---|---|
D3DDDIERR_INVALIDPROTECT | 资源保护状态不匹配 |
D3DDDIERR_KEYEDTOOMANY | 密钥使用次数超限 |
E_CRYPTO_NOT_INIT | 加密引擎未初始化 |