使用 D3D11 视频 GPU-Based 内容保护

本主题介绍图形驱动程序可以提供的视频内容保护功能。

简介

下图显示了受保护的视频内容如何通过管道进行呈现的简化视图。

显示受保护视频内容的示意图。

注意

此图中未描述 受保护的媒体路径 (PMP) 。 此处显示的数据流可能发生在 PMP 进程或应用程序进程中。

 

解码器从外部源接收加密的压缩视频数据。 此外,假定解码器还接收加密密钥来解密此数据。 本主题不介绍视频源和解码器之间的密钥交换,但 PMP 定义了一种可能的机制。 此阶段不涉及 GPU。

对于硬件加速解码,软件解码器将压缩的视频内容传递到 GPU。 为了保护此内容,解码器通常会使用 AES-CTR 重新加密数据,然后再将其传递给硬件加速器。 解码器和图形驱动程序之间定义了密钥交换机制。

解码的视频帧存储在视频内存中,通常存储在明文中。 此时,将处理帧,然后呈现。 有两个用于演示main选项。

  • 使用 D3D9 API 时,可以使用硬件覆盖来呈现帧。 D3D11 不支持硬件。 有关详细信息,请参阅 硬件覆盖支持
  • 使用共享图面的桌面窗口管理 (DWM) 可以呈现帧。

最后一步是在监视器上显示帧,这可能需要图形卡和显示设备之间的链接保护。 链接保护的一个示例是 High-Bandwidth 数字内容保护 (HDCP) 。 链接保护是使用 输出保护管理器 (OPM) 配置的。 本主题不介绍 OPM;有关详细信息,请参阅 使用输出保护管理器

解码过程概述

在硬件加速解码期间,软件解码器必须将压缩的视频数据传递到图形卡。 对于高级内容,通常必须使用对称密钥加密对此数据进行加密,然后才能将其发送到 GPU。

为了加密视频进行解码,软件解码器使用以下接口:

显示 direct3d9 解码接口的关系图。

所有这些接口都是从 Direct3D11 设备获取的,如下所示:

接口 创建
ID3D11VideoDecoder 调用 ID3D11VideoDevice::CreateVideoDecoder。 解码器类型由配置文件 GUID 标识。
ID3D11CryptoSession 调用 ID3D11VideoDevice::CreateCryptoSession
ID3D11AuthenticatedChannel 调用 ID3D11VideoDevice::CreateAuthenticatedChannel

 

注意

若要获取指向 ID3D11VideoDevice 接口的指针,请在 ID3D11Device 接口上调用 QueryInterface

 

经过身份验证的通道在软件解码器和驱动程序之间提供受信任的信道。 通信通道的工作方式如下:

  • 驱动程序提供根证书由 Microsoft 签名的 X.509 证书链。
  • 证书包含驱动程序的 RSA 公钥。
  • 软件解码器使用公钥向驱动程序发送 128 位 AES 会话密钥。
  • 软件解码器将查询和命令发送到经过身份验证的通道。
  • 会话密钥用于计算查询和命令 (MAC) 的消息身份验证代码。 驱动程序使用 MAC 验证查询/命令数据的完整性,软件解码器使用它们来验证驱动程序响应数据的完整性。

加密解码器的压缩视频缓冲区

下面是加密和解码过程的高级概述:

  1. 软件解码器从视频源接收加密数据流。 解码器解密此流。

  2. 软件解码器与加密会话协商会话密钥。

  3. 软件解码器使用经过身份验证的通道将加密会话与解码器设备相关联。

  4. 软件解码器将压缩数据放入从解码器设备 (加速器) 获取的缓冲区中。 对于受保护的内容,软件编码器使用用于加密的会话密钥对放入缓冲区的数据进行加密。

    注意

    某些驱动程序使用内容密钥而不是会话密钥进行加密。 内容键可能会从一个帧更改为下一个帧。

     

  5. 解码器将加密的压缩缓冲区提交到加速器。 对于 AES-CTR,解码器还会传递初始化向量。 如果使用内容密钥,则解码器会传递内容密钥,该密钥使用会话密钥进行加密。

Direct3D11 具有对 128 位 AES-CTR 的标准支持,但旨在扩展到其他加密类型。

接下来的五个部分提供了更详细的步骤。

1. 查询驱动程序的内容保护功能

在尝试应用加密之前,请获取驱动程序的内容保护功能。

  1. 获取指向 ID3D11Device 接口的指针。
  2. 调用 ID3D11VideoDevice 接口的 QueryInterface
  3. 调用 ID3D11VideoDevice::GetContentProtectionCaps。 此方法使用驱动程序的内容保护功能填充 D3D11_VIDEO_CONTENT_PROTECTION_CAPS 结构。

具体而言,请查找以下功能:

  • 如果 Caps 成员包含 D3D11_CONTENT_PROTECTION_CAPS_SOFTWARED3D11_CONTENT_PROTECTION_CAPS_HARDWARE 标志,驱动程序可以执行加密。
  • 如果 Caps 成员包含 D3D11_CONTENT_PROTECTION_CAPS_CONTENT_KEY 标志,驱动程序将使用单独的内容密钥进行解密。
  • 调用 ID3D11VideoDevice::CheckCryptoKeyExchange 以确定驱动程序支持用于生成会话密钥的密钥交换类型。

Caps 成员中指示了其他功能。

2.配置经过身份验证的通道

下一步是配置经过身份验证的通道。

  1. 调用 ID3D11VideoDevice::CreateAuthenticatedChannel 以创建经过身份验证的通道。 对于 ChannelType 参数,请指定与驱动程序的功能匹配的通道类型。

    • D3D11_AUTHENTICATED_CHANNEL_DRIVER_SOFTWARE通道类型对应于D3D11_CONTENT_PROTECTION_CAPS_SOFTWARE
    • D3D11_AUTHENTICATED_CHANNEL_DRIVER_HARDWARE通道类型对应于D3D11_CONTENT_PROTECTION_CAPS_HARDWARE

    CreateAuthenticatedChannel 方法返回指向 ID3D11AuthenticatedChannel 接口的指针。

  2. 调用 ID3D11AuthenticatedChannel::GetCertificateSize 以获取驱动程序的 X.509 证书的大小。 分配所需大小的缓冲区。

  3. 调用 ID3D11AuthenticatedChannel::GetCertificate 获取证书。 方法将证书复制到上一步中分配的缓冲区中。

  4. 验证驱动程序的证书是否由 Microsoft 签名且尚未吊销。

  5. 从证书获取公钥。

  6. 生成随机 RSA 会话密钥。 此会话密钥用于对发送到经过身份验证的通道的数据进行签名。 使用驱动程序的公钥加密会话密钥。

  7. 调用 ID3D11VideoContext::NegotiateAuthenticatedChannelKeyExchange 将加密的会话密钥发送到驱动程序。

  8. 初始化安全通道,如下所示:

    1. 如文档中所述,填写 D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE_INPUT 结构。
    2. 如发送 经过身份验证的 通道命令部分所述,通过调用 ID3D11VideoContext::ConfigureAuthenticatedChannel 发送 D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE_INPUT命令。 此命令包含发送到经过身份验证的通道的命令和查询的起始序列号。
  9. 通过向经过身份验证的通道发送 D3D11_AUTHENTICATED_QUERY_CHANNEL_TYPE 查询来验证通道类型,如 发送经过身份验证的通道查询部分所述。 检查通道类型是否与 在 CreateAuthenticatedChannel 方法中指定的类型匹配。

3.配置加密会话

接下来,配置加密会话并建立会话密钥。

  1. 调用 ID3D11VideoDevice::CreateCryptoSession 以创建加密会话。 此方法返回指向 ID3D11CryptoSession 接口的 指针。
  2. 调用 ID3D11CryptoSession::GetCertificateSize 以获取驱动程序的 X.509 证书的大小。 分配所需大小的缓冲区。
  3. 调用 ID3D11CryptoSession::GetCertificate 获取证书。 方法将证书复制到上一步中分配的缓冲区中。
  4. 验证驱动程序的证书是否由 Microsoft 签名且尚未吊销。
  5. 从证书获取公钥。
  6. 生成随机 RSA 会话密钥。 这是与经过身份验证的通道会话密钥不同的会话密钥。 使用驱动程序的公钥加密会话密钥。
  7. 调用 ID3D11VideoContext::NegotiateCryptoSessionKeyExchange 将加密的会话密钥发送到驱动程序。
  8. 如果内容保护功能包括 3D11_CONTENT_PROTECTION_CAPS_CONTENT_KEY,请创建随机 RSA 内容密钥。 稍后将在解码过程中使用它。

4. 将解码器与加密会话相关联

接下来,将解码器设备与 Direct3D11 设备和加密会话相关联,如下所示:

  1. 通过将 D3D11_AUTHENTICATED_QUERY_DEVICE_HANDLE 查询发送到经过身份验证的通道,获取 Direct3D11 设备的句柄。
  2. D3D11_AUTHENTICATED_CONFIGURE_CRYPTO_SESSION_INPUT 结构中填写以下信息:
  3. 调用 ID3D11VideoContext::ConfigureAuthenticatedChannelD3D11_AUTHENTICATED_CONFIGURE_CRYPTO_SESSION 命令发送到经过身份验证的通道。

下图演示了句柄的交换:

显示 dxva 解码器如何与加密会话关联的关系图。

软件解码器现在可以使用加密会话密钥来加密压缩的视频缓冲区。 每个压缩缓冲区都有自己的初始化向量 (IV) 在 D3D11_VIDEO_DECODER_BUFFER_DESC 结构的 pIV 成员中指定。

发送经过身份验证的通道命令

定义了一组命令,用于配置经过身份验证的通道和设置各种内容保护。 有关命令的列表,请参阅 内容保护命令

若要将命令发送到经过身份验证的通道,请执行以下步骤。

  1. 填写输入数据结构。 此数据结构始终是后跟其他字段 的D3D11_AUTHENTICATED_CONFIGURE_INPUT 结构。 填写 D3D11_AUTHENTICATED_CONFIGURE_INPUT 结构,如下表所示。
成员 说明
omac 暂时跳过此字段。
ConfigureType 标识命令的 GUID。 有关命令的列表,请参阅 内容保护命令
hChannel 经过身份验证的通道的句柄。
SequenceNumber 序列号。 第一个序列号是通过发送 D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE 命令指定的。 每次发送另一个命令时,将此数字递增 1。 序列号可防范重播攻击。 注意: 使用两个单独的序列号,一个用于命令,另一个用于查询。
  1. 计算在输入结构的 omac 成员之后显示的数据块的 OMAC 标记。 然后将此标记值复制到 omac 成员中。
  2. 调用 ID3D11VideoContext::ConfigureAuthenticatedChannel
  3. 驱动程序将 命令的输出放置在 D3D11_AUTHENTICATED_CONFIGURE_OUTPUT 结构中。
  4. 计算输出结构的 omac 成员之后出现的数据块的 OMAC 标记。 将此值与 omac 成员的值进行比较。 如果不匹配,则失败。
  5. 将输出结构中 ConfigureTypehChannelSequenceNumber 成员的值与这些成员的值进行比较。 如果不匹配,则失败。
  6. 递增下一个命令的序列号。

发送经过身份验证的通道查询

定义了一组查询,用于检索有关经过身份验证的通道的信息。 有关查询的列表,请参阅 内容保护查询

若要将命令发送到经过身份验证的通道,请执行以下步骤。

  1. 填写输入数据结构。 此数据结构始终是 D3D11_AUTHENTICATED_QUERY_INPUT 结构,可能后跟其他字段。 填写 D3D11_AUTHENTICATED_QUERY_INPUT 结构,如下表所示。
成员 说明
QueryType 标识查询的 GUID。 有关查询的列表,请参阅 内容保护查询
hChannel 经过身份验证的通道的句柄。
SequenceNumber 序列号。 第一个序列号是通过发送 D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE 命令指定的。 每次发送另一个查询时,请将此数字递增 1。 序列号可防止重播攻击。 注意: 使用两个单独的序列号,一个用于命令,一个用于查询。
  1. 调用 ID3D11VideoContext::QueryAuthenticatedChannel
  2. 驱动程序将查询的输出置于 D3D11_AUTHENTICATED_QUERY_OUTPUT 结构中。 此结构后跟其他字段,具体取决于查询类型。
  3. 计算在输出结构的 omac 成员之后显示的数据块的 OMAC 标记。 将此值与 omac 成员的值进行比较。 如果不匹配,则失败。
  4. 将输出结构中 ConfigureTypehChannelSequenceNumber 成员的值与这些成员的值进行比较。 如果不匹配,则失败。
  5. 递增下一个查询的序列号。

Direct3D 11 视频 API