window显示驱动开发—可选内容保护 DDI 函数

驱动程序可以选择性地支持以下内容保护 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 加密引擎未初始化
相关推荐
逻极13 小时前
AI 规范驱动开发“三剑客”深度对比:Spec-Kit、Kiro 与 OpenSpec 实战指南
人工智能·驱动开发·ai·agent
逻极13 小时前
Claude Code 实战:Spec-Kit、Kiro、OpenSpec 规范驱动开发三剑客
ide·人工智能·驱动开发·ai·自动化
范纹杉想快点毕业1 天前
100道关于STM32的问题解答共十万字回答,适用入门嵌入式软件初级工程师,筑牢基础,技术积累,校招面试。
驱动开发·单片机·嵌入式硬件·fpga开发·硬件工程
进击大厂的小白2 天前
35.linux的定时器使用
驱动开发
winner88812 天前
嵌入式Linux驱动开发全流程:工具协作+核心概念拆解(从入门到理解)
linux·运维·驱动开发
Evan_ZGYF丶3 天前
深入解析CFS虚拟运行时间:Linux公平调度的核心引擎
linux·驱动开发·嵌入式·bsp
leijiwen3 天前
规则优先:AI 时代的规范驱动开发(SDD)新范式
人工智能·驱动开发
Ghost Face...3 天前
PCI总线驱动开发全解析
驱动开发
贝塔实验室4 天前
Altium Designer 6.3 PCB LAYOUT教程(四)
驱动开发·嵌入式硬件·硬件架构·硬件工程·信息与通信·基带工程·pcb工艺
小狗爱吃黄桃罐头4 天前
正点原子【第四期】Linux之驱动开发学习笔记-10.1 Linux 内核定时器实验
linux·驱动开发·学习