Proteção de Conteúdo GPU-Based

Este tópico descreve os recursos de proteção de conteúdo de vídeo que um driver de gráficos pode fornecer.

Introdução

O diagrama a seguir mostra uma exibição simplificada de como o conteúdo de vídeo protegido viaja pelo pipeline a ser renderizado.

um diagrama que mostra o conteúdo do vídeo protegido.

Observação

O PMP ( Caminho de Mídia Protegida ) não é representado neste diagrama. O fluxo de dados mostrado aqui pode ocorrer dentro de um processo PMP ou em um processo de aplicativo.

O decodificador recebe dados de vídeo criptografados e compactados de uma fonte externa. Supõe-se também que o decodificador também recebe uma chave criptográfica para descriptografar esses dados. Este tópico não descreve a troca de chaves entre a origem do vídeo e o decodificador, mas o PMP define um mecanismo possível. A GPU não está envolvida nesta fase.

Para decodificação acelerada por hardware, o decodificador de software passa o conteúdo de vídeo compactado para a GPU. Para proteger esse conteúdo, o decodificador criptografa novamente os dados, normalmente usando a AES-CTR, antes de passá-los para o acelerador de hardware. Um mecanismo de troca de chaves é definido entre o decodificador e o driver gráfico.

Os quadros de vídeo decodificados são armazenados na memória de vídeo, geralmente em modo claro. Neste ponto, os quadros são processados e, em seguida, apresentados. Há duas opções de main para apresentação.

  • Os quadros podem ser apresentados usando uma sobreposição de hardware. Para obter mais informações, consulte Suporte à sobreposição de hardware.
  • Os quadros podem ser apresentados pelo DWM (Gerenciamento de Janela da Área de Trabalho) usando uma superfície compartilhada.

A última etapa é exibir o quadro no monitor, o que pode exigir proteção de vínculo entre os elementos gráficos cartão e o dispositivo de exibição. Um exemplo de proteção de link é High-Bandwidth HDCP (Proteção de Conteúdo Digital). A proteção de link é configurada usando o OPM ( Gerenciador de Proteção de Saída ). Este tópico não descreve o OPM; para obter mais informações, consulte Usando o Gerenciador de Proteção de Saída.

Visão geral do processo de decodificação

Durante a decodificação acelerada por hardware, o decodificador de software deve passar dados de vídeo compactados para os elementos gráficos cartão. Para conteúdo premium, esses dados normalmente devem ser criptografados, usando criptografia de chave simétrica, antes de serem enviados para a GPU.

Para criptografar o vídeo para decodificação, o decodificador de software usa as seguintes interfaces:

  • IDirectXVideoDecoder. Representa o dispositivo de decodificador DXVA, também chamado de acelerador.
  • IDirect3DCryptoSession9. Representa uma sessão criptográfica, que fornece a chave de criptografia.
  • IDirect3DAuthenticatedChannel9. Representa um canal autenticado, que permite que o decodificador de software associe a sessão criptográfica ao decodificador DXVA.

um diagrama que mostra as interfaces de decodificação direct3d9.

Todas essas interfaces são obtidas do dispositivo Direct3D, da seguinte maneira:

Interface Criação
IDirectXVideoDecoder Chame IDirectXVideoDecoderService::CreateVideoDecoder. O dispositivo de decodificador DXVA é identificado por um GUID de perfil DXVA.
IDirect3DCryptoSession9 Chame IDirect3DDevice9Video::CreateCryptoSession.
IDirect3DAuthenticatedChannel9 Chame IDirect3DDevice9Video::CreateAuthenticatedChannel.

Observação

Para obter um ponteiro para a interface IDirect3DDevice9Video , chame QueryInterface em um dispositivo D3D9Ex.

O canal autenticado fornece um canal de comunicação confiável entre o decodificador de software e o driver. O canal de comunicação funciona da seguinte maneira:

  • O driver fornece uma cadeia de certificados X.509 cujo certificado raiz é assinado pela Microsoft.
  • O certificado contém uma chave pública RSA para o driver.
  • O decodificador de software usa a chave pública para enviar ao driver uma chave de sessão AES de 128 bits.
  • O decodificador de software envia consultas e comandos para o canal autenticado.
  • A chave de sessão é usada para calcular os MACs (códigos de autenticação de mensagem) para as consultas e comandos. O driver usa os MACs para verificar a integridade dos dados de consulta/comando e o decodificador de software os usa para verificar a integridade dos dados de resposta do driver.

Criptografando buffers de vídeo compactados para o decodificador

Aqui está uma visão geral de alto nível do processo de criptografia e decodificação:

  1. O decodificador de software recebe um fluxo de dados criptografados da fonte de vídeo. O decodificador descriptografa esse fluxo.

  2. O decodificador de software negocia uma chave de sessão com a sessão criptográfica.

  3. O decodificador de software usa o canal autenticado para associar a sessão criptográfica ao dispositivo de decodificador DXVA.

  4. O decodificador de software coloca dados compactados em buffers DXVA que obtém do dispositivo de decodificador DXVA (acelerador). Para conteúdo protegido, o codificador de software criptografa os dados que são colocados nos buffers DXVA, usando a chave de sessão para a criptografia.

    Observação

    Alguns drivers usam uma chave de conteúdo, em vez da chave de sessão, para criptografia. A chave de conteúdo pode mudar de um quadro para outro.

  5. O decodificador envia os buffers compactados criptografados para o acelerador. Para AES-CTR, o decodificador também passa o vetor de inicialização. Se uma chave de conteúdo for usada, o decodificador passará a chave de conteúdo, criptografada usando a chave de sessão.

O Direct3D tem suporte padrão para AES-CTR de 128 bits, mas foi projetado para se estender a tipos de criptografia adicionais.

As próximas cinco seções fornecem etapas mais detalhadas.

1. Consultar os recursos de proteção de conteúdo do driver

Antes de tentar aplicar a criptografia, obtenha os recursos de proteção de conteúdo do driver.

  1. Obtenha um ponteiro para o dispositivo Direct3D 9.
  2. Chame QueryInterface para a interface IDirect3DDevice9Video .
  3. Chame IDirect3DDevice9Video::GetContentProtectionCaps. Esse método preenche uma estrutura D3DCONTENTPROTECTIONCAPS com os recursos de proteção de conteúdo do driver.

Em particular, procure os seguintes recursos:

  • Se o membro Caps contiver o sinalizador D3DCPCAPS_SOFTWARE ou D3DCPCAPS_HARDWARE , o driver poderá executar a criptografia.
  • O membro KeyExchangeType especifica como executar a troca de chaves para a chave de sessão.
  • Se o membro Caps contiver o sinalizador D3DCPCAPS_CONTENTKEY , o driver usará uma chave de conteúdo separada para criptografia. Isso é importante quando você gera a chave de sessão.

Recursos adicionais são indicados no membro Caps .

2. Configurar o Canal Autenticado

A próxima etapa é configurar o canal autenticado.

  1. Chame IDirect3DDevice9Video::CreateAuthenticatedChannel para criar o canal autenticado. Para o parâmetro ChannelType , especifique um tipo de canal que corresponda aos recursos do driver.

    • O tipo de canal D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE corresponde a D3DCPCAPS_SOFTWARE.
    • O tipo de canal D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE corresponde a D3DCPCAPS_HARDWARE.

    O método CreateAuthenticatedChannel retorna um ponteiro para a interface IDirect3DAuthenticatedChannel9 juntamente com um identificador para o canal. O identificador é usado posteriormente para associar a sessão criptográfica ao canal autenticado.

  2. Chame IDirect3DAuthenticatedChannel9::GetCertificateSize para obter o tamanho do certificado X.509 do driver. Aloque um buffer do tamanho necessário.

  3. Chame IDirect3DAuthenticatedChannel9::GetCertificate para obter o certificado. O método copia o certificado para o buffer alocado na etapa anterior.

  4. Verifique se o certificado do driver foi assinado pela Microsoft e se não foi revogado.

  5. Obtenha a chave pública do certificado.

  6. Gere uma chave de sessão RSA aleatória. Essa chave de sessão é usada para assinar dados enviados para o canal autenticado. Criptografe a chave de sessão usando a chave pública do driver.

  7. Chame IDirect3DAuthenticatedChannel9::NegotiateKeyExchange para enviar a chave de sessão criptografada para o driver.

  8. Inicialize o canal seguro da seguinte maneira:

    1. Preencha uma estrutura D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE conforme descrito na documentação.
    2. Envie o comando D3DAUTHENTICATEDCONFIGURE_INITIALIZE chamando IDirect3DAuthenticatedChannel9::Configure conforme descrito na seção Enviando comandos de canal autenticado. Esse comando contém os números de sequência inicial para os comandos e consultas que são enviados para o canal autenticado.
  9. Verifique o tipo de canal enviando uma consulta D3DAUTHENTICATEDQUERY_CHANNELTYPE para o canal autenticado, conforme descrito na seção Enviando consultas de canal autenticado. Verifique se o tipo de canal corresponde ao que você especificou no método CreateAuthenticatedChannel .

3. Configurar a sessão criptográfica

Em seguida, configure a sessão criptográfica e estabeleça a chave de sessão.

  1. Chame IDirect3DDevice9Video::CreateCryptoSession para criar a sessão criptográfica. Esse método retorna um ponteiro para a interface IDirect3DCryptoSession9 e juntamente com um identificador para a sessão criptográfica.
  2. Chame IDirect3DCryptoSession9::GetCertificateSize para obter o tamanho do certificado X.509 do driver. Aloque um buffer do tamanho necessário.
  3. Chame IDirect3DCryptoSession9::GetCertificate para obter o certificado. O método copia o certificado para o buffer alocado na etapa anterior.
  4. Verifique se o certificado do driver foi assinado pela Microsoft e se não foi revogado.
  5. Obtenha a chave pública do certificado.
  6. Gere uma chave de sessão RSA aleatória. Essa é uma chave de sessão separada da chave de sessão do canal autenticado. Criptografe a chave de sessão usando a chave pública do driver.
  7. Chame IDirect3DCryptoSession9::NegotiateKeyExchange para enviar a chave de sessão criptografada para o driver.
  8. Se os recursos de proteção de conteúdo incluírem D3DCPCAPS_CONTENTKEY, crie uma chave de conteúdo RSA aleatória. Isso será usado posteriormente no processo de decodificação.

4. Obter um identificador para o dispositivo de decodificador DXVA

Para a próxima etapa, você precisará de um identificador para o dispositivo de decodificador DXVA. Para obter esse identificador, preencha uma estrutura DXVA2_DecodeExecuteParams da seguinte maneira:

HANDLE hDecodeDeviceHandle;

DXVA2_DecodeExecuteParams execParams = {0};
DXVA2_DecodeExtensionData ExtensionExecute = {0};
    
execParams.NumCompBuffers = 0;
execParams.pCompressedBuffers = NULL;
execParams.pExtensionData = &ExtensionExecute;

ExtensionExecute.Function = DXVA2_DECODE_GET_DRIVER_HANDLE;
ExtensionExecute.pPrivateInputData = NULL;
ExtensionExecute.PrivateInputDataSize = 0;
ExtensionExecute.pPrivateOutputData = &hDecodeDeviceHandle;
ExtensionExecute.PrivateOutputDataSize = sizeof(HANDLE);

Defina o membro pExtensionData da estrutura DXVA2_DecodeExecuteParams como o endereço de uma estrutura DXVA2_DecodeExtensionData .

Na estrutura DXVA2_DecodeExtensionData , defina o membro Function como DXVA2_DECODE_GET_DRIVER_HANDLE. Defina pPrivateOutputData como o endereço de um buffer grande o suficiente para armazenar um valor HANDLE . (No exemplo anterior, esse buffer é a variável hDecodeDeviceHandle .)

Em seguida, chame IDirectXVideoDecoder::Execute e passe o endereço da estrutura DXVA2_DecodeExecuteParams . O identificador para o decodificador DXVA é retornado em pPrivateOutputData.

5. Associar o decodificador DXVA à Sessão Criptográfica

Em seguida, associe o dispositivo de decodificador DXVA ao dispositivo Direct3D e à sessão criptográfica, da seguinte maneira:

  1. Obtenha um identificador para o dispositivo de decodificador DXVA, conforme descrito na seção anterior.
  2. Obtenha um identificador para o dispositivo Direct3D enviando uma consulta D3DAUTHENTICATEDQUERY_DEVICEHANDLE para o canal autenticado.
  3. Preencha uma estrutura D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION com as seguintes informações:
    • Defina o membro DXVA2DecodeHandle como o identificador para o dispositivo decodificador DXVA.
    • Defina o membro CryptoSessionHandle como o identificador para a sessão criptográfica. Esse identificador é retornado pelo método IDirect3DDevice9Video::CreateCryptoSession .
    • Defina o membro DeviceHandle como o identificador de dispositivo Direct3D.
  4. Chame IDirect3DAuthenticatedChannel9::Configure para enviar um comando D3DAUTHENTICATEDCONFIGURE_CRYPTOSESSION para o canal autenticado.

O diagrama a seguir ilustra a troca de identificadores:

um diagrama que mostra como o decodificador dxva está associado à sessão criptográfica.

O decodificador de software agora pode usar a chave de sessão criptográfica para criptografar os buffers de vídeo compactados. Cada buffer compactado terá seu próprio vetor de inicialização (IV) especificado no membro pvPVPState da estrutura DXVA2_DecodeBufferDesc .

Enviando comandos de canal autenticado

Um conjunto de comandos é definido para configurar o canal autenticado e definir várias proteções de conteúdo. Para obter uma lista de comandos, consulte Comandos de Proteção de Conteúdo.

Para enviar um comando para o canal autenticado, execute as etapas a seguir.

  1. Preencha a estrutura de dados de entrada. Essa estrutura de dados é sempre uma estrutura D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT seguida por campos adicionais. Preencha a estrutura D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT conforme mostrado na tabela a seguir.
Membro Descrição
omac Ignore este campo por enquanto.
ConfigureType GUID que identifica o comando. Para obter uma lista de comandos, consulte Comandos de Proteção de Conteúdo.
hChannel O identificador para o canal autenticado.
SequenceNumber O número de sequência. O primeiro número de sequência é especificado enviando um comando D3DAUTHENTICATEDCONFIGURE_INITIALIZE . Cada vez que você enviar outro comando, incremente esse número em 1. O número de sequência protege contra ataques de repetição. Nota: Dois números de sequência separados são usados, um para comandos e outro para consultas.
  1. Calcule a marca OMAC para o bloco de dados que aparece após o membro omac da estrutura de entrada. Em seguida, copie esse valor de marca para o membro omac .
  2. Chame IDirect3DAuthenticatedChannel9::Configure.
  3. O driver coloca a saída do comando na estrutura D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT .
  4. Calcule a marca OMAC para o bloco de dados que aparece após o membro omac da estrutura de saída. Compare isso com o valor do membro omac . Falhar se eles não corresponderem.
  5. Compare os valores dos membros ConfigureType, hChannel e SequenceNumber na estrutura de saída com os valores desses membros. Falhar se eles não corresponderem.
  6. Incremente o número de sequência para o próximo comando.

Enviando consultas de canal autenticado

Um conjunto de consultas é definido para recuperar informações sobre o canal autenticado. Para obter uma lista de consultas, consulte Consultas de Proteção de Conteúdo.

Para enviar um comando para o canal autenticado, execute as etapas a seguir.

  1. Preencha a estrutura de dados de entrada. Essa estrutura de dados é sempre uma estrutura D3DAUTHENTICATEDCHANNEL_QUERY_INPUT , possivelmente seguida por campos adicionais. Preencha a estrutura D3DAUTHENTICATEDCHANNEL_QUERY_INPUT conforme mostrado na tabela a seguir.
Membro Descrição
QueryType GUID que identifica a consulta. Para obter uma lista de consultas, consulte Consultas de Proteção de Conteúdo.
hChannel O identificador para o canal autenticado.
SequenceNumber O número de sequência. O primeiro número de sequência é especificado enviando um comando D3DAUTHENTICATEDCONFIGURE_INITIALIZE . Cada vez que você enviar outra consulta, incremente esse número em 1. O número de sequência protege contra ataques de repetição. Nota: Dois números de sequência separados são usados, um para comandos e outro para consultas.
  1. Chame IDirect3DAuthenticatedChannel9::Query.
  2. O driver coloca a saída da consulta em uma estrutura D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT . Essa estrutura é seguida por campos adicionais, dependendo do tipo de consulta.
  3. Calcule a marca OMAC para o bloco de dados que aparece após o membro omac da estrutura de saída. Compare isso com o valor do membro omac . Falhar se eles não corresponderem.
  4. Compare os valores dos membros ConfigureType, hChannel e SequenceNumber na estrutura de saída com os valores desses membros. Falhar se eles não corresponderem.
  5. Incremente o número de sequência para a próxima consulta.

APIs de vídeo do Direct3D 9