Como usar o Gerenciador de Proteção de Saída

Este tópico descreve como usar o Gerenciador de Proteção de Saída (OPM) para proteger o conteúdo do vídeo enquanto percorre um conector físico até um dispositivo de exibição. Este tópico contém as seguintes seções:

O conteúdo de vídeo Premium costuma ser criptografado para ficar protegido contra a duplicação não autorizada. É claro que o vídeo precisa ser descriptografado antes de ser exibido. Os quadros descriptografados e descompactados precisam, a seguir, percorrer um conector físico até o dispositivo de exibição. Os provedores de conteúdo podem requerer que os quadros de vídeo estejam protegidos nesse ponto, enquanto viajam pelo conector físico.

Existem vários mecanismos de proteção para essa finalidade, incluindo a Proteção de Conteúdo Digital em Alta Largura de Banda (HDCP) e a Proteção de Conteúdo DisplayPort (DPCP) para saídas digitais, além do Sistema de Gerenciamento de Geração de Cópias — Analógico (CGMS-A) para saídas analógicas. De modo geral, esses mecanismos envolvem criptografar ou embaralhar o sinal antes que seja enviado para a tela.

O OPM permite que um aplicativo implemente mecanismos de proteção de conteúdo na saída de vídeo. Usando o OPM, o aplicativo envia comandos e solicitações de status para o driver de vídeo por meio de um canal confiável e seguro. O OPM habilita um aplicativo a:

  • Verificar se um driver de vídeo foi assinado pela Microsoft.
  • Configurar um canal de comunicação confiável com o driver.
  • Implementar mecanismos de proteção de conteúdo na saída física.

O OPM substitui o Protocolo de Proteção de Saída Certificado (COPP) e usa uma API semelhante. Para compatibilidade com versões anteriores, a interface do OPM pode emular a interface do COPP. As diferenças entre o OPM e o COPP incluem as seguintes:

  • O OPM usa certificados X.509, enquanto o COPP usa um formato de certificado proprietário.
  • O OPM dá suporte a repetidores de HDCP.
  • Os aplicativos que usam o OPM não precisam analisar as mensagens de renovabilidade do sistema (SRMs) de HDCP.
  • O OPM pode ser usado quando a tela de vídeo estiver usando o modo de clonagem. O COPP não dá suporte ao modo de clonagem.

Se o seu aplicativo usar o caminho de mídia protegido (PMP) para reproduzir conteúdo de vídeo, você não precisará usar a API do OPM, porque o PMP faz todas as chamadas ao OPM necessárias. A API do OPM está disponível para aplicativos que não usam o PMP.

O OPM está disponível no Windows Vista e posterior, mas a API só foi disponibilizada ao público no Windows 7. Para usar o OPM em um aplicativo, você precisa ter os cabeçalhos e os arquivos de biblioteca do SDK do Windows 7. Você não precisa redistribuir nenhuma DLL para usar o OPM no Windows Vista ou no Windows Server 2008.

Saídas de vídeo

Uma placa de vídeo pode ter mais de uma saída física, cada uma com seus próprios recursos. Antes de reproduzir o conteúdo protegido, um aplicativo precisa definir os mecanismos de proteção apropriados em cada saída de vídeo associada à placa gráfica que exibirá o vídeo. A escolha de quais mecanismos de proteção aplicar vai depender das regras de uso do conteúdo.

Cada saída de vídeo é representada por uma instância da interface de IOPMVideoOutput. Você pode usar um dispositivo Direct3D ou monitorar identificadores para obter as saídas de vídeo.

Usando um dispositivo Direct3D:

  1. Obtenha o ponteiro IDirect3DDevice9 para o dispositivo Direct3D que seu aplicativo usará para criar superfícies que conterão os quadros do vídeo.
  2. Chame a função OPMGetVideoOutputsFromIDirect3DDevice9Object. Essa função aloca uma matriz de ponteiros de IOPMVideoOutput, um para cada saída.

Usando identificadores do monitor:

  1. Chame EnumDisplayMonitors para obter os identificadores HMONITOR que correspondem à janela do vídeo. Vários monitores podem ser associados à mesma janela, então você pode obter vários identificadores HMONITOR.
  2. Para cada identificador de monitor, chame um OPMGetVideoOutputsFromHMONITOR. Essa função aloca uma matriz de ponteiros de IOPMVideoOutput, um para cada saída.

Como inicializar uma sessão do OPM

Antes de enviar comandos ou solicitações de status do OPM, o aplicativo precisa verificar se a saída de vídeo é confiável e estabelecer uma chave de sessão. A chave de sessão é usada para assinar os dados que são trocados entre o aplicativo e o driver de vídeo.

A API do OPM define um handshake que estabelece confiança e define a chave de sessão. Você precisa executar esse handshake para cada instância da interface de IOPMVideoOutput, como se segue:

  1. Chame IOPMVideoOutput::StartInitialization. Esse método recupera dois itens de dados:

    • Um número aleatório, gerado pelo driver. Você vai usar esse número para executar o handshake.
    • A cadeia do certificado X.509 do driver.
  2. Verifique se a cadeia de certificados foi assinada pela Microsoft.

    Observação

    A revogação do certificado está fora do escopo do OPM.

     

  3. Obtenha a chave pública do driver da cadeia de certificados.

  4. Gere uma chave de sessão AES de 128 bits.

  5. Gere dois números aleatórios de 32 bits:

    • O número de sequência inicial para as solicitações de status do OPM.
    • O número da sequência inicial para os comandos do OPM.

    Esses números devem ser gerados usando um gerador de números pseudoaleatório criptograficamente seguro, como CryptGenRandom.

  6. Copie o número aleatório do driver (obtido na etapa 1), a chave de sessão e os dois números de sequência em uma estrutura OPM_ENCRYPTED_INITIALIZATION_PARAMETERS, conforme descrito em IOPMVideoOutput::FinishInitialization.

  7. Criptografe a estrutura OPM_ENCRYPTED_INITIALIZATION_PARAMETERS com RSAES-OAEP usando a chave pública do driver, que pode ser encontrada no certificado do driver.

  8. Chame IOPMVideoOutput::FinishInitialization.

Como enviar solicitações de status do OPM

As solicitações de status do OPM retornam informações sobre a saída de vídeo, como o tipo de conector físico e o nível de proteção atual. Para obter uma lista de tipos de solicitação, consulte Solicitações de Status do OPM.

Para enviar uma solicitação de status, execute as etapas a seguir.

  1. Inicialize uma estrutura OPM_GET_INFO_PARAMETERS conforme mostrado na tabela a seguir.

    Membro Descrição
    omac Ignore esse campo por enquanto.
    rnRandomNumber Um número aleatório de 128 bits protegido criptograficamente. Sempre que você fizer uma solicitação de status, não deixe de gerar um novo número aleatório, mesmo que esteja fazendo a mesma solicitação. Armazene o número em uma variável, porque você vai precisar mencioná-lo mais tarde.
    guidInformation Um GUID que identifica a solicitação de status. Para obter uma lista de solicitações de status, consulte Solicitações de Status do OPM.
    ulSequenceNumber O número de sequência. Para a primeira solicitação de status, use o número de sequência inicial que você especificou no método IOPMVideoOutput::FinishInitialization (etapa 5 de Como inicializar uma sessão do OPM). Sempre que você fizer outra solicitação de status, aumente esse número com um incremento de 1.
    abParameters Uma matriz de bytes que contém dados de entrada adicionais para a solicitação. O formato dos dados de entrada está listado no tópico de referência para cada solicitação de status.
    cbParametersSize O tamanho dos dados válidos na matriz abParameters. O conteúdo do restante da matriz é indefinido.

     

  2. Calcule o CBC MAC de uma chave (OMAC-1) para calcular um hash para o bloco de dados que aparece após o membro omac e, em seguida, defina o membro omac para esse valor. Consulte o Exemplo de Código do OPM.

  3. Chame o método IOPMVideoOutput::GetInformation. Repasse um ponteiro para a estrutura OPM_GET_INFO_PARAMETERS e um ponteiro para uma estrutura OPM_REQUESTED_INFORMATION. A resposta do driver é gravada na estrutura OPM_REQUESTED_INFORMATION.

    • O membro omac dessa estrutura contém um OMAC computado para os dados que seguem esse membro.
    • O membro abRequestedInformation é uma matriz de bytes que contém dados de saída para a resposta. O formato dos dados de saída está listado no tópico de referência para cada solicitação de status.
  4. Calcule um OMAC para a estrutura OPM_REQUESTED_INFORMATION, sem incluir o membro omac. Verifique se o OMAC corresponde ao valor no membro omac.

  5. Certifique-se de que o membro cbRequestedInformationSize da estrutura OPM_REQUESTED_INFORMATION fornece o tamanho correto para os dados de saída. Por exemplo, os dados de saída da consulta OPM_GET_CONNECTOR_TYPE são uma estrutura OPM_STANDARD_INFORMATION e, portanto, o valor de cbRequestedInformationSize deve ser sizeof(OPM_STANDARD_INFORMATION).

  6. Converta o membro abRequestedInformation da estrutura OPM_REQUESTED_INFORMATION para a estrutura de dados de saída correta. Por exemplo, se a solicitação de status for OPM_GET_CONNECTOR_TYPE, converta abRequestedInformation em uma estrutura OPM_STANDARD_INFORMATION.

  7. Certifique-se de que o membro rnRandomNumber da estrutura de dados de saída corresponde ao valor do rnRandomNumber da etapa 1.

  8. Verifique o membro ulStatusFlags da estrutura de dados de saída, conforme descrito em Como lidar com uma saída de vídeo desabilitada.

Se alguma das verificações nas etapas 5 a 8 falhar, o aplicativo precisará parar de mostrar o conteúdo protegido.

Como enviar comandos do OPM

Os comandos do OPM são usados para definir o nível de proteção e outras configurações na saída do vídeo. O envio de um comando do OPM é semelhante ao envio de uma solicitação de status, com a exceção de que não haverá dados de resposta do driver. Para obter uma lista de comandos, confira Comandos do OPM.

Para enviar um comando do OPM, execute as etapas a seguir.

  1. Preencha uma estrutura OPM_CONFIGURE_PARAMETERS conforme mostrado na tabela a seguir.

    Membro Descrição
    omac Ignore esse campo por enquanto.
    guidSetting Um GUID que identifica o comando. Para obter uma lista de comandos, confira Comandos do OPM.
    ulSequenceNumber O número de sequência. Para o primeiro comando, use o número de sequência inicial que você especificou no método IOPMVideoOutput::FinishInitialization (etapa 5 de Como inicializar uma sessão do OPM). A cada vez que você enviar outro comando, aumente esse número com um incremento de 1.
    abParameters Uma matriz de bytes que contém dados de entrada adicionais para o comando. O formato dos dados de entrada está listado no tópico de referência para cada comando.
    cbSettingDataSize O tamanho dos dados válidos na matriz abParameters. O conteúdo do restante da matriz é indefinido.

     

  2. Calcule um OMAC para o bloco de dados que aparece após o membro omac e defina o membro omac para esse valor.

  3. Chame IOPMVideoOutput::Configure.

Para a maioria dos comandos, existe uma solicitação de status correspondente que retorna o status do comando. Por exemplo, o comando OPM_SET_PROTECTION_LEVEL define o nível de proteção e o comando OPM_GET_VIRTUAL_PROTECTION_LEVEL obtém o nível de proteção atual.

Como lidar com uma saída de vídeo desabilitada

Uma saída de vídeo pode se autodesabilitar a qualquer momento para impedir o uso não autorizado do conteúdo de vídeo. Isso pode ocorrer porque um mecanismo de proteção parou de funcionar, porque o driver detectou uma adulteração ou porque a tela foi desconectada do conector físico. Enquanto uma saída de vídeo estiver desabilitada, nenhum quadro de vídeo será exibido.

Embora a proteção de conteúdo esteja habilitada, um aplicativo deve executar periodicamente (pelo menos uma vez a cada 2 segundos) as etapas a seguir.

  1. Chamar IOPMVideoOutput::GetInformation para enviar as solicitações de status OPM_GET_ACTUAL_PROTECTION_LEVEL ou OPM_GET_VIRTUAL_PROTECTION_LEVEL. Os dados de retorno para ambos os comandos são uma estrutura OPM_STANDARD_INFORMATION.
  2. Verificar o membro ulInformation da estrutura OPM_STANDARD_INFORMATION. Esse membro contém um sinalizador que indica se a proteção de conteúdo ainda está habilitada. Se a proteção de conteúdo estiver desativada, pare de reproduzir o vídeo imediatamente.
  3. Se a proteção de conteúdo estiver ativada, verifique o membro ulStatusFlags da estrutura OPM_STANDARD_INFORMATION. Se nenhum sinalizador for definido, a saída do vídeo está funcionando corretamente. Caso contrário, a saída do vídeo será desabilitada.

Os sinalizadores a seguir são definidos para ulStatusFlags.

Sinalizador Descrição
OPM_STATUS_LINK_LOST A proteção de saída parou de funcionar por algum motivo, por exemplo, o dispositivo de exibição pode estar desconectado do conector. Pare a reprodução e desative todos os mecanismos de proteção de saída.
OPM_STATUS_RENEGOTIATION_REQUIRED O aplicativo precisa restabelecer a sessão do OPM. Responda da seguinte maneira:
  1. Interrompe a reprodução.
  2. Desative todos os mecanismos de proteção.
  3. Libere a interface de IOPMVideoOutput.
  4. Recrie todas as superfícies de vídeo.
  5. Crie um novo objeto do OPM e tente restabelecer a proteção do conteúdo. Se essa tentativa falhar, exiba uma mensagem de erro para o usuário. Não reproduza mais conteúdo de vídeo.
OPM_STATUS_REVOKED_HDCP_DEVICE_ATTACHED Esse sinalizador só se aplica quando a HDCP é usada e indica a presença de um dispositivo de HDCP revogado. Pare a reprodução e desative todos os mecanismos de proteção nessa saída de vídeo. Quando esse sinalizador é definido, o sinalizadorOPM_STATUS_LINK_LOST também é definido.
OPM_STATUS_REVOKED_HDCP_DEVICE_ATTACHED O driver detectou uma adulteração. Pare a reprodução e não reproduza mais nenhum vídeo usando essa saída de vídeo. Também é uma boa ideia parar de usar outras saídas de vídeo porque o sistema pode estar comprometido.

 

Como usar a HDCP para proteger conteúdo

Essa seção descreve como habilitar a proteção de saída de HDCP usando o OPM. Aqui temos uma descrição geral das etapas que o aplicativo precisa executar. Os detalhes são fornecidos posteriormente nessa seção.

  1. O aplicativo pode precisar fornecer uma SRM para a saída do vídeo. O mecanismo para receber SRMs está fora do escopo da interface do OPM. Por exemplo, as SRMs podem ser entregues como parte de um fluxo de transmissão.
  2. O aplicativo habilita a proteção de saída HDCP.
  3. O aplicativo reproduz o conteúdo de vídeo. Periodicamente, o aplicativo sonda o driver para garantir que a HDCP esteja ativada.
  4. Quando a reprodução é concluída, o aplicativo desativa a HDCP.

Como configurar a SRM

Para configurar a SRM, execute as etapas a seguir.

  1. Inicialize uma estrutura OPM_SET_HDCP_SRM_PARAMETERS com o número de versão da SRM.
  2. Armazene a SRM em uma variável.
  3. Envie um comando OPM_SET_HDCP_SRM para a saída do vídeo. Use o procedimento descrito em Como enviar comandos do OPM.
  4. Envie uma solicitação de status OPM_GET_CURRENT_HDCP_SRM_VERSION para a saída do vídeo. Use o procedimento descrito em Como enviar solicitações de status do OPM. Essa solicitação de status não tem dados de entrada e, portanto, o conteúdo do membro abParameters da estrutura OPM_GET_INFO_PARAMETERS é indefinido.
  5. Quando o método IOPMVideoOutput::GetInformation é retornado, a matriz abRequestedInformation na estrutura OPM_REQUESTED_INFORMATION contém uma estrutura OPM_STANDARD_INFORMATION. O membro ulInformation dessa estrutura contém o número de versão da SRM atual. Esse valor precisa ser igual ao valor da etapa 2.

Como habilitar a HDCP

Para habilitar a HDCP, execute as etapas a seguir.

  1. Inicialize uma estrutura OPM_SET_PROTECTION_LEVEL_PARAMETERS com os seguintes valores:
    • ulProtectionType = OPM_PROTECTION_TYPE_HDCP
    • ulProtectionLevel = OPM_HDCP_ON
    • Reserved = 0
    • Reserved2 = 0
  2. Enviar um comando OPM_SET_PROTECTION_LEVEL. Os dados de entrada na matriz abParameters são a estrutura OPM_SET_PROTECTION_LEVEL_PARAMETERS.
  3. Envie uma solicitação de status OPM_GET_VIRTUAL_PROTECTION_LEVEL para verificar se a HDCP está habilitada. Os primeiros 4 bytes do membro abParameters da estrutura OPM_GET_INFO_PARAMETERS contêm o valor OPM_PROTECTION_TYPE_HDCP.

Quando o método GetInformation é retornado, a matriz abRequestedInformation na estrutura OPM_REQUESTED_INFORMATION contém uma estrutura OPM_STANDARD_INFORMATION. O membro ulInformation dessa estrutura contém um valor da enumeração OPM_HDCP_PROTECTION_LEVEL. Se o valor for igual a OPM_HDCP_ON, isso significa que a HDCP está habilitada. Caso contrário, repita as etapas 1 e 2 até que a HDCP esteja habilitada ou ocorra um erro. (Lembre-se de incrementar o número da sequência e gerar um novo número aleatório a cada vez.)

Costuma levar entre 100 e 200 milissegundos para habilitar a HDCP, mas pode demorar mais. Não pressuponha que a HDCP esteja habilitada antes de ter verificado.

Quando o aplicativo terminar de reproduzir um conteúdo protegido, desative a HDCP. As etapas são as mesmas que para habilitar a HDCP, mas, na etapa 1, configure ulProtectionLevel como OPM_HDCP_OFF.

Observação

Não habilite a HDCP se o tipo de conector for OPM_CONNECTOR_TYPE_DISPLAYPORT_EMBEDDED. (Confira Sinalizadores do Tipo Conector do OPM.)

 

Gerenciador de Proteção de Saída