Protection de contenu GPU-Based

Cette rubrique décrit les fonctionnalités de protection du contenu vidéo qu’un pilote graphique peut fournir.

Introduction

Le diagramme suivant montre une vue simplifiée de la façon dont le contenu vidéo protégé transite par le pipeline à afficher.

a diagram that shows protected video content.

Notes

Le chemin d’accès du média protégé (PMP) n’est pas représenté dans ce diagramme. Le flux de données affiché ici peut se produire dans un processus PMP ou dans un processus d’application.

Le décodeur reçoit des données vidéo chiffrées et compressées à partir d’une source externe. Il est supposé également que le décodeur reçoit également une clé de chiffrement pour déchiffrer ces données. Cette rubrique ne décrit pas l’échange de clés entre la source vidéo et le décodeur, mais le PMP définit un mécanisme possible. Le GPU n’est pas impliqué à ce stade.

Pour le décodage accéléré par le matériel, le décodeur logiciel transmet du contenu vidéo compressé au GPU. Pour protéger ce contenu, le décodeur rechiffre les données, généralement à l’aide d’AES-CTR, avant de le transmettre à l’accélérateur matériel. Un mécanisme d’échange de clés est défini entre le décodeur et le pilote graphique.

Les images vidéo décodées sont stockées en mémoire vidéo, généralement en clair. À ce stade, les images sont traitées, puis présentées. Il existe deux options principales pour la présentation.

  • Les images peuvent être présentées à l’aide d’une superposition matérielle. Pour plus d’informations, consultez Prise en charge des superpositions matérielles.
  • Les cadres peuvent être présentés par la fenêtre de bureau Gérer (DWM) à l’aide d’une surface partagée.

La dernière étape consiste à afficher le cadre sur le moniteur, ce qui peut nécessiter une protection de liaison entre la carte graphique et l’appareil d’affichage. Un exemple de protection des liens est High-Bandwidth protection de contenu numérique (HDCP). La protection des liens est configurée à l’aide du Gestionnaire de protection de sortie (OPM). Cette rubrique ne décrit pas opm; Pour plus d’informations, consultez Utilisation du Gestionnaire de protection de sortie.

Vue d’ensemble du processus de décodage

Pendant le décodage accéléré par le matériel, le décodeur logiciel doit passer des données vidéo compressées à la carte graphique. Pour le contenu Premium, ces données doivent généralement être chiffrées, à l’aide du chiffrement à clé symétrique, avant d’être envoyées au GPU.

Pour chiffrer la vidéo pour le décodage, le décodeur logiciel utilise les interfaces suivantes :

a diagram that shows the direct3d9 decoding interfaces.

Toutes ces interfaces sont obtenues à partir de l’appareil Direct3D, comme suit :

Interface Création
IDirectXVideoDecoder Appelez IDirectXVideoDecoderService::CreateVideoDecoder. L’appareil décodeur DXVA est identifié par un GUID de profil DXVA.
IDirect3DCryptoSession9 Appelez IDirect3DDevice9Video::CreateCryptoSession.
IDirect3DAuthenticatedChannel9 Appelez IDirect3DDevice9Video::CreateAuthenticatedChannel.

Notes

Pour obtenir un pointeur vers l’interface IDirect3DDevice9Video , appelez QueryInterface sur un appareil D3D9Ex.

Le canal authentifié fournit un canal de communication approuvé entre le décodeur logiciel et le pilote. Le canal de communication fonctionne comme suit :

  • Le pilote fournit une chaîne de certificats X.509 dont le certificat racine est signé par Microsoft.
  • Le certificat contient une clé publique RSA pour le pilote.
  • Le décodeur logiciel utilise la clé publique pour envoyer au pilote une clé de session AES 128 bits.
  • Le décodeur logiciel envoie des requêtes et des commandes au canal authentifié.
  • La clé de session est utilisée pour calculer les codes d’authentification des messages pour les requêtes et les commandes. Le pilote utilise les contrôleurs de domaine pour vérifier l’intégrité des données de requête/commande, et le décodeur logiciel les utilise pour vérifier l’intégrité des données de réponse du pilote.

Chiffrement des mémoires tampons vidéo compressées pour le décodeur

Voici une vue d’ensemble générale du processus de chiffrement et de décodage :

  1. Le décodeur logiciel reçoit un flux de données chiffrées à partir de la source vidéo. Le décodeur déchiffre ce flux.

  2. Le décodeur logiciel négocie une clé de session avec la session de chiffrement.

  3. Le décodeur logiciel utilise le canal authentifié pour associer la session de chiffrement à l’appareil décodeur DXVA.

  4. Le décodeur logiciel place des données compressées dans des mémoires tampons DXVA qu’il obtient à partir de l’appareil de décodeur DXVA (accélérateur). Pour le contenu protégé, l’encodeur logiciel chiffre les données qui sont placées dans les mémoires tampons DXVA, à l’aide de la clé de session pour le chiffrement.

    Notes

    Certains pilotes utilisent une clé de contenu, au lieu de la clé de session, pour le chiffrement. La clé de contenu peut passer d’une image à l’autre.

  5. Le décodeur envoie les mémoires tampons compressées chiffrées à l’accélérateur. Pour AES-CTR, le décodeur transmet également le vecteur d’initialisation. Si une clé de contenu est utilisée, le décodeur transmet la clé de contenu, chiffrée à l’aide de la clé de session.

Direct3D offre une prise en charge standard pour AES-CTR 128 bits, mais elle est conçue pour s’étendre à des types de chiffrement supplémentaires.

Les cinq sections suivantes fournissent des étapes plus détaillées.

1. Interroger les fonctionnalités de protection du contenu du pilote

Avant d’essayer d’appliquer le chiffrement, obtenez les fonctionnalités de protection du contenu du pilote.

  1. Obtenez un pointeur vers l’appareil Direct3D 9.
  2. Appelez QueryInterface pour l’interface IDirect3DDevice9Video .
  3. Appelez IDirect3DDevice9Video::GetContentProtectionCaps. Cette méthode remplit une structure D3DCONTENTPROTECTIONCAPS avec les fonctionnalités de protection du contenu du pilote.

En particulier, recherchez les fonctionnalités suivantes :

  • Si le membre Caps contient l’indicateur D3DCPCAPS_SOFTWARE ou D3DCPCAPS_HARDWARE , le pilote peut effectuer le chiffrement.
  • Le membre KeyExchangeType spécifie comment effectuer un échange de clés pour la clé de session.
  • Si le membre Caps contient l’indicateur D3DCPCAPS_CONTENTKEY , le pilote utilise une clé de contenu distincte pour le chiffrement. Cela est important lorsque vous générez la clé de session.

Des fonctionnalités supplémentaires sont indiquées dans le membre Caps .

2. Configurer le canal authentifié

L’étape suivante consiste à configurer le canal authentifié.

  1. Appelez IDirect3DDevice9Video::CreateAuthenticatedChannel pour créer le canal authentifié. Pour le paramètre ChannelType , spécifiez un type de canal qui correspond aux fonctionnalités du pilote.

    • Le type de canal D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE correspond à D3DCPCAPS_SOFTWARE.
    • Le type de canal D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE correspond à D3DCPCAPS_HARDWARE.

    La méthode CreateAuthenticatedChannel retourne un pointeur vers l’interface IDirect3DAuthenticatedChannel9 , ainsi qu’un handle vers le canal. Le handle est utilisé ultérieurement pour associer la session de chiffrement au canal authentifié.

  2. Appelez IDirect3DAuthenticatedChannel9::GetCertificateSize pour obtenir la taille du certificat X.509 du pilote. Allouez une mémoire tampon de la taille requise.

  3. Appelez IDirect3DAuthenticatedChannel9::GetCertificate pour obtenir le certificat. La méthode copie le certificat dans la mémoire tampon allouée à l’étape précédente.

  4. Vérifiez que le certificat du pilote a été signé par Microsoft et n’a pas été révoqué.

  5. Obtenez la clé publique à partir du certificat.

  6. Générez une clé de session RSA aléatoire. Cette clé de session est utilisée pour signer les données envoyées au canal authentifié. Chiffrez la clé de session à l’aide de la clé publique du pilote.

  7. Appelez IDirect3DAuthenticatedChannel9::NegotiateKeyExchange pour envoyer la clé de session chiffrée au pilote.

  8. Initialisez le canal sécurisé comme suit :

    1. Renseignez une structure D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE , comme décrit dans la documentation.
    2. Envoyez la commande D3DAUTHENTICATEDCONFIGURE_INITIALIZE en appelant IDirect3DAuthenticatedChannel9::Configure comme décrit dans la section Envoi de commandes de canal authentifié. Cette commande contient les numéros de séquence de départ pour les commandes et les requêtes envoyées au canal authentifié.
  9. Vérifiez le type de canal en envoyant une requête D3DAUTHENTICATEDQUERY_CHANNELTYPE au canal authentifié, comme décrit dans la section Envoi de requêtes de canal authentifié. Vérifiez que le type de canal correspond à ce que vous avez spécifié dans la méthode CreateAuthenticatedChannel .

3. Configurer la session de chiffrement

Ensuite, configurez la session de chiffrement et établissez la clé de session.

  1. Appelez IDirect3DDevice9Video::CreateCryptoSession pour créer la session de chiffrement. Cette méthode retourne un pointeur vers l’interface IDirect3DCryptoSession9 , ainsi qu’un handle vers la session de chiffrement.
  2. Appelez IDirect3DCryptoSession9::GetCertificateSize pour obtenir la taille du certificat X.509 du pilote. Allouez une mémoire tampon de la taille requise.
  3. Appelez IDirect3DCryptoSession9::GetCertificate pour obtenir le certificat. La méthode copie le certificat dans la mémoire tampon allouée à l’étape précédente.
  4. Vérifiez que le certificat du pilote a été signé par Microsoft et n’a pas été révoqué.
  5. Obtenez la clé publique à partir du certificat.
  6. Générez une clé de session RSA aléatoire. Il s’agit d’une clé de session distincte de la clé de session de canal authentifiée. Chiffrez la clé de session à l’aide de la clé publique du pilote.
  7. Appelez IDirect3DCryptoSession9::NegotiateKeyExchange pour envoyer la clé de session chiffrée au pilote.
  8. Si les fonctionnalités de protection du contenu incluent D3DCPCAPS_CONTENTKEY, créez une clé de contenu RSA aléatoire. Cette opération sera utilisée ultérieurement dans le processus de décodage.

4. Obtenir un handle sur l’appareil décodeur DXVA

Pour l’étape suivante, vous aurez besoin d’un handle pour l’appareil décodeur DXVA. Pour obtenir cette poignée, renseignez une structure DXVA2_DecodeExecuteParams comme suit :

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);

Définissez le membre pExtensionData de la structure DXVA2_DecodeExecuteParams sur l’adresse d’une structure DXVA2_DecodeExtensionData .

Dans la structure DXVA2_DecodeExtensionData , définissez le membre function sur DXVA2_DECODE_GET_DRIVER_HANDLE. Définissez pPrivateOutputData sur l’adresse d’une mémoire tampon suffisamment grande pour stocker une valeur HANDLE . (Dans l’exemple précédent, cette mémoire tampon est la variable hDecodeDeviceHandle .)

Appelez ensuite IDirectXVideoDecoder::Execute et transmettez l’adresse de la structure DXVA2_DecodeExecuteParams . Le handle du décodeur DXVA est retourné dans pPrivateOutputData.

5. Associer le décodeur DXVA à la session de chiffrement

Ensuite, associez l’appareil décodeur DXVA à l’appareil Direct3D et à la session de chiffrement, comme suit :

  1. Obtenez un handle sur l’appareil de décodeur DXVA, comme décrit dans la section précédente.
  2. Obtenez un handle sur l’appareil Direct3D en envoyant une requête D3DAUTHENTICATEDQUERY_DEVICEHANDLE au canal authentifié.
  3. Renseignez une structure D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION avec les informations suivantes :
    • Définissez le membre DXVA2DecodeHandle sur le handle sur l’appareil décodeur DXVA.
    • Définissez le membre CryptoSessionHandle sur le handle sur la session de chiffrement. Ce handle est retourné par la méthode IDirect3DDevice9Video::CreateCryptoSession .
    • Définissez le membre DeviceHandle sur le handle d’appareil Direct3D.
  4. Appelez IDirect3DAuthenticatedChannel9::Configure pour envoyer une commande D3DAUTHENTICATEDCONFIGURE_CRYPTOSESSION au canal authentifié.

Le diagramme suivant illustre l’échange de handles :

a diagram that shows how the dxva decoder is associated with the cryptographic session.

Le décodeur logiciel peut désormais utiliser la clé de session de chiffrement pour chiffrer les mémoires tampons vidéo compressées. Chaque mémoire tampon compressée aura son propre vecteur d’initialisation (IV) spécifié dans le membre pvSEEState de la structure DXVA2_DecodeBufferDesc .

Envoi de commandes de canal authentifié

Un ensemble de commandes est défini pour configurer le canal authentifié et définir différentes protections de contenu. Pour obtenir la liste des commandes, consultez Commandes de protection du contenu.

Pour envoyer une commande au canal authentifié, procédez comme suit.

  1. Renseignez la structure des données d’entrée. Cette structure de données est toujours une structure D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT suivie de champs supplémentaires. Renseignez la structure D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT comme indiqué dans le tableau suivant.
Membre Description
omac Ignorez ce champ pour l’instant.
ConfigureType GUID qui identifie la commande. Pour obtenir la liste des commandes, consultez Commandes de protection du contenu.
hChannel Handle vers le canal authentifié.
SequenceNumber Numéro séquentiel. Le premier numéro de séquence est spécifié en envoyant une commande D3DAUTHENTICATEDCONFIGURE_INITIALIZE . Chaque fois que vous envoyez une autre commande, incrémentez ce nombre de 1. Le numéro de séquence protège contre les attaques par relecture.
[! Remarque]
Deux numéros de séquence distincts sont utilisés, un pour les commandes et un pour les requêtes.


  1. Calculez la balise OMAC pour le bloc de données qui apparaît après le membre omac de la structure d’entrée. Copiez ensuite cette valeur de balise dans le membre omac .
  2. Appelez IDirect3DAuthenticatedChannel9::Configure.
  3. Le pilote place la sortie de la commande dans la structure D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT .
  4. Calculez la balise OMAC pour le bloc de données qui apparaît après le membre omac de la structure de sortie. Comparez-le à la valeur du membre omac . Échoue si elles ne correspondent pas.
  5. Comparez les valeurs des membres ConfigureType, hChannel et SequenceNumber dans la structure de sortie par rapport à vos valeurs pour ces membres. Échoue si elles ne correspondent pas.
  6. Incrémentez le numéro de séquence de la commande suivante.

Envoi de requêtes de canal authentifié

Un ensemble de requêtes est défini pour récupérer des informations sur le canal authentifié. Pour obtenir la liste des requêtes, consultez Requêtes de protection du contenu.

Pour envoyer une commande au canal authentifié, procédez comme suit.

  1. Renseignez la structure des données d’entrée. Cette structure de données est toujours une structure D3DAUTHENTICATEDCHANNEL_QUERY_INPUT , éventuellement suivie de champs supplémentaires. Renseignez la structure D3DAUTHENTICATEDCHANNEL_QUERY_INPUT , comme illustré dans le tableau suivant.
Membre Description
QueryType GUID qui identifie la requête. Pour obtenir la liste des requêtes, consultez Requêtes de protection du contenu.
hChannel Handle vers le canal authentifié.
SequenceNumber Numéro séquentiel. Le premier numéro de séquence est spécifié en envoyant une commande D3DAUTHENTICATEDCONFIGURE_INITIALIZE . Chaque fois que vous envoyez une autre requête, incrémentez ce nombre par 1. Le numéro de séquence protège contre les attaques de relecture.
[! Remarque]
Deux numéros de séquence distincts sont utilisés, un pour les commandes et un pour les requêtes.


  1. Appelez IDirect3DAuthenticatedChannel9::Query.
  2. Le pilote place la sortie de la requête dans une structure D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT . Cette structure est suivie de champs supplémentaires, selon le type de requête.
  3. Calculez la balise OMAC pour le bloc de données qui apparaît après le membre omac de la structure de sortie. Comparez-le à la valeur du membre omac . Échouez s’ils ne correspondent pas.
  4. Comparez les valeurs des membres ConfigureType, hChannel et SequenceNumber dans la structure de sortie par rapport à vos valeurs pour ces membres. Échouez s’ils ne correspondent pas.
  5. Incrémentez le numéro de séquence pour la requête suivante.

API vidéo Direct3D 9