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 加密引擎未初始化
相关推荐
小狗爱吃黄桃罐头18 小时前
正点原子【第四期】Linux之驱动开发学习笔记-6.1 pinctrl和gpio子系统
linux·驱动开发·学习
每天更新1 天前
linux驱动开发笔记
linux·驱动开发·笔记
sheepwjl1 天前
《嵌入式驱动(二):驱动开发基本概念》
arm开发·驱动开发·单片机·嵌入式硬件·imx6ull·驱动·裸机
fatfishccc1 天前
(四)优雅重构:洞悉“搬移特性”的艺术与实践
java·驱动开发·intellij-idea·软件研发·后端开发·代码重构·搬移
CoderBob2 天前
【easy_tools】一个跨平台裸机工具库,包含任务/堆栈/消息/定时器/日志等实现
c语言·驱动开发·单片机·嵌入式硬件
与你诗画3 天前
为什么单片机的外接晶振要并连两个电容?
c语言·驱动开发·单片机·嵌入式硬件·硬件架构·硬件工程
飞奔的猫3 天前
驱动开发---双机调试搭建支持win11(2025)
驱动开发
zly88653723 天前
驱动开发,为什么需要映射?
驱动开发
cxr82812 天前
SPARC方法论在Claude Code基于规则驱动开发中的应用
人工智能·驱动开发·claude·智能体
sukalot12 天前
window显示驱动开发—显示适配器的子设备
驱动开发