次の方法で共有


GPU-Based コンテンツ保護

このトピックでは、グラフィックス ドライバーが提供できるビデオ コンテンツ保護機能について説明します。

紹介

次の図は、保護されたビデオ コンテンツがパイプラインを通過してレンダリングされる方法を簡略化したビューを示しています。

保護されたビデオ コンテンツを示す図を します。

手記

保護されたメディア パス (PMP) は、この図には示されていません。 ここに示すデータ フローは、PMP プロセス内またはアプリケーション プロセス内で発生する可能性があります。

デコーダーは、暗号化された圧縮されたビデオ データを外部ソースから受信します。 また、デコーダーは、このデータを復号化するための暗号化キーも受け取ると想定されます。 このトピックでは、ビデオ ソースとデコーダーの間のキー交換について説明しませんが、PMP は 1 つの可能なメカニズムを定義します。 GPU は、この段階では関与しません。

ハードウェア高速化デコードの場合、ソフトウェア デコーダーは、圧縮されたビデオ コンテンツを GPU に渡します。 このコンテンツを保護するために、デコーダーは、データをハードウェア アクセラレータに渡す前に、通常は AES-CTR を使用して再暗号化します。 デコーダーとグラフィックス ドライバーの間でキー交換メカニズムが定義されます。

デコードされたビデオ フレームは、ビデオ メモリに格納されます。通常はクリアです。 この時点で、フレームが処理され、表示されます。 プレゼンテーションには、主に 2 つのオプションがあります。

  • フレームは、ハードウェア オーバーレイを使用して表示できます。 詳細については、「ハードウェア オーバーレイサポート」を参照してください。
  • フレームは、共有サーフェイスを使用してデスクトップ ウィンドウ管理 (DWM) によって表示できます。

最後の手順では、フレームをモニターに表示します。この場合、グラフィックス カードとディスプレイ デバイス間のリンク保護が必要になる場合があります。 リンク保護の例として、High-Bandwidth Digital Content Protection (HDCP) があります。 リンク保護は、Output Protection Manager (OPM) を使用して構成されます。 このトピックでは、OPM について説明しません。詳細については、「Output Protection Manager の使用」を参照してください。

デコード プロセスの概要

ハードウェアアクセラレータによるデコード時に、ソフトウェア デコーダーは圧縮されたビデオ データをグラフィックス カードに渡す必要があります。 Premium コンテンツの場合、通常、このデータは、GPU に送信される前に、対称キー暗号化を使用して暗号化する必要があります。

デコード用のビデオを暗号化するために、ソフトウェア デコーダーは次のインターフェイスを使用します。

  • IDirectXVideoDecoderします。 アクセラレータとも呼ばれる DXVA デコーダー デバイスを表します。
  • IDirect3DCryptoSession9. 暗号化キーを提供する暗号化セッションを表します。
  • IDirect3DAuthenticatedChannel9します。 認証されたチャネルを表します。これにより、ソフトウェア デコーダーは、暗号化セッションを DXVA デコーダーに関連付けることができます。

direct3d9 デコード インターフェイスを示す図です。

これらのインターフェイスはすべて、次のように Direct3D デバイスから取得されます。

インターフェイス 創造
IDirectXVideoDecoder IDirectXVideoDecoderService::CreateVideoDecoder呼び出します。 DXVA デコーダー デバイスは、DXVA プロファイル GUID によって識別されます。
IDirect3DCryptoSession9 IDirect3DDevice9Video::CreateCryptoSession呼び出します。
IDirect3DAuthenticatedChannel9 IDirect3DDevice9Video::CreateAuthenticatedChannelを呼び出します。

手記

IDirect3DDevice9Video インターフェイスへのポインターを取得するには、D3D9Ex デバイス QueryInterface を呼び出します。

認証されたチャネルは、ソフトウェア デコーダーとドライバーの間の信頼された通信チャネルを提供します。 通信チャネルは次のように動作します。

  • ドライバーは、ルート証明書が Microsoft によって署名されている X.509 証明書チェーンを提供します。
  • 証明書には、ドライバーの RSA 公開キーが含まれています。
  • ソフトウェア デコーダーは公開キーを使用して、ドライバーに 128 ビット AES セッション キーを送信します。
  • ソフトウェア デコーダーは、認証されたチャネルにクエリとコマンドを送信します。
  • セッション キーは、クエリとコマンドのメッセージ認証コード (MAC) を計算するために使用されます。 ドライバーは MAC を使用してクエリ/コマンド データの整合性を確認し、ソフトウェア デコーダーはそれらを使用してドライバーからの応答データの整合性を検証します。

デコーダーの圧縮ビデオ バッファーの暗号化

暗号化とデコードプロセスの概要を次に示します。

  1. ソフトウェア デコーダーは、ビデオ ソースから暗号化されたデータのストリームを受信します。 デコーダーは、このストリームを復号化します。

  2. ソフトウェア デコーダーは、暗号化セッションとセッション キーをネゴシエートします。

  3. ソフトウェア デコーダーは、認証されたチャネルを使用して、暗号化セッションを DXVA デコーダー デバイスに関連付けます。

  4. ソフトウェア デコーダーは、DXVA デコーダー デバイス (アクセラレータ) から取得した DXVA バッファーに圧縮データを格納します。 保護されたコンテンツの場合、ソフトウェア エンコーダーは、暗号化にセッション キーを使用して、DXVA バッファーに格納されるデータを暗号化します。

    手記

    一部のドライバーは、セッション キーではなくコンテンツ キーを暗号化に使用します。 コンテンツ キーは、あるフレームから次のフレームに変更される可能性があります。

  5. デコーダーは、暗号化された圧縮バッファーをアクセラレータに送信します。 AES-CTR の場合、デコーダーは初期化ベクトルも渡します。 コンテンツ キーが使用されている場合、デコーダーはセッション キーを使用して暗号化されたコンテンツ キーを渡します。

Direct3D には 128 ビット AES-CTR の標準サポートがありますが、追加の暗号化の種類まで拡張するように設計されています。

次の 5 つのセクションでは、より詳細な手順について説明します。

1. ドライバーのコンテンツ保護機能を照会する

暗号化を適用する前に、ドライバーのコンテンツ保護機能を取得します。

  1. Direct3D 9 デバイスへのポインターを取得します。
  2. IDirect3DDevice9Video インターフェイス QueryInterface を呼び出します。
  3. IDirect3DDevice9Video::GetContentProtectionCaps呼び出します。 このメソッドは、ドライバーのコンテンツ保護機能を D3DCONTENTPROTECTIONCAPS 構造体に格納します。

特に、次の機能を探します。

  • Caps メンバーに D3DCPCAPS_SOFTWARE または D3DCPCAPS_HARDWARE フラグが含まれている場合、ドライバーは暗号化を実行できます。
  • KeyExchangeType メンバーは、セッション キーのキー交換を実行する方法を指定します。
  • Caps メンバーに D3DCPCAPS_CONTENTKEY フラグが含まれている場合、ドライバーは暗号化に別のコンテンツ キーを使用します。 これは、セッション キーを生成するときに重要です。

その他の機能は、Caps メンバーに示されています。

2. 認証済みチャネルを構成する

次の手順では、認証済みチャネルを構成します。

  1. IDirect3DDevice9Video::CreateAuthenticatedChannel呼び出して、認証済みチャネルを作成します。 ChannelType パラメーターには、ドライバーの機能に一致するチャネルの種類を指定します。

    • D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE チャネルの種類は、D3DCPCAPS_SOFTWAREに対応します。
    • D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE チャネルの種類は、D3DCPCAPS_HARDWAREに対応します。

    CreateAuthenticatedChannel メソッドは、チャネルへのハンドルと共に、IDirect3DAuthenticatedChannel9 インターフェイスへのポインターを返します。 このハンドルは、後で暗号化セッションを認証済みチャネルに関連付けるために使用されます。

  2. IDirect3DAuthenticatedChannel9::GetCertificateSize呼び出して、ドライバーの X.509 証明書のサイズを取得します。 必要なサイズのバッファーを割り当てます。

  3. IDirect3DAuthenticatedChannel9::GetCertificate呼び出して証明書を取得します。 このメソッドは、前の手順で割り当てられたバッファーに証明書をコピーします。

  4. ドライバーの証明書が Microsoft によって署名され、取り消されていないことを確認します。

  5. 証明書から公開キーを取得します。

  6. ランダムな RSA セッション キーを生成します。 このセッション キーは、認証されたチャネルに送信されるデータに署名するために使用されます。 ドライバーの公開キーを使用してセッション キーを暗号化します。

  7. IDirect3DAuthenticatedChannel9::NegotiateKeyExchange呼び出して、暗号化されたセッション キーをドライバーに送信します。

  8. セキュリティで保護されたチャネルを次のように初期化します。

    1. ドキュメントの説明に従って、D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE 構造体を入力します。
    2. D3DAUTHENTICATEDCONFIGURE_INITIALIZE コマンドを送信するには、「認証されたチャネル コマンドの送信 」セクションの説明に従って、IDirect3DAuthenticatedChannel9::Configure呼び出します。 このコマンドには、認証済みチャネルに送信されるコマンドとクエリの開始シーケンス番号が含まれます。
  9. 認証されたチャネル クエリの送信 のセクションで説明されているように、D3DAUTHENTICATEDQUERY_CHANNELTYPE クエリを認証済みチャネルに送信して、チャネルの種類確認します。 チャネルの種類が、CreateAuthenticatedChannel メソッドで指定したものと一致することを確認します。

3. 暗号化セッションを構成する

次に、暗号化セッションを構成し、セッション キーを確立します。

  1. IDirect3DDevice9Video::CreateCryptoSession呼び出して、暗号化セッションを作成します。 このメソッドは、IDirect3DCryptoSession9 インターフェイスへのポインターと、暗号化セッションへのハンドルを返します。
  2. IDirect3DCryptoSession9::GetCertificateSize を呼び出して、ドライバーの X.509 証明書のサイズを取得します。 必要なサイズのバッファーを割り当てます。
  3. IDirect3DCryptoSession9::GetCertificate呼び出して証明書を取得します。 このメソッドは、前の手順で割り当てられたバッファーに証明書をコピーします。
  4. ドライバーの証明書が Microsoft によって署名され、取り消されていないことを確認します。
  5. 証明書から公開キーを取得します。
  6. ランダムな RSA セッション キーを生成します。 これは、認証されたチャネル セッション キーとは別のセッション キーです。 ドライバーの公開キーを使用してセッション キーを暗号化します。
  7. IDirect3DCryptoSession9::NegotiateKeyExchange を呼び出して、暗号化されたセッション キーをドライバーに送信します。
  8. コンテンツ保護機能に D3DCPCAPS_CONTENTKEYが含まれている場合は、ランダムな RSA コンテンツ キーを作成します。 これは、デコード プロセスの後半で使用されます。

4. DXVA デコーダー デバイスへのハンドルを取得する

次の手順では、DXVA デコーダー デバイスへのハンドルが必要です。 このハンドルを取得するには、次のようにDXVA2_DecodeExecuteParams構造体を入力します。

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

DXVA2_DecodeExecuteParams 構造体の pExtensionData メンバーを DXVA2_DecodeExtensionData 構造体のアドレスに設定します。

DXVA2_DecodeExtensionData 構造体で、Function メンバーを DXVA2_DECODE_GET_DRIVER_HANDLEに設定します。 pPrivateOutputData HANDLE 値を格納するのに十分な大きさのバッファーのアドレスに設定します。 (前の例では、このバッファーは hDecodeDeviceHandle 変数 です)。

IDirectXVideoDecoder::Execute を呼び出し、DXVA2_DecodeExecuteParams 構造体のアドレスを渡します。 DXVA デコーダーへのハンドルは、pPrivateOutputDataで返されます。

5. DXVA デコーダーを暗号化セッションに関連付ける

次に、次のように、DXVA デコーダー デバイスを Direct3D デバイスと暗号化セッションに関連付けます。

  1. 前のセクションで説明したように、DXVA デコーダー デバイスへのハンドルを取得します。
  2. 認証されたチャネルに D3DAUTHENTICATEDQUERY_DEVICEHANDLE クエリを送信して、Direct3D デバイスへのハンドルを取得します。
  3. D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION 構造体に次の情報を入力します。
    • DXVA2DecodeHandle メンバーを DXVA デコーダー デバイスのハンドルに設定します。
    • CryptoSessionHandle メンバーを暗号化セッションのハンドルに設定します。 このハンドルは、IDirect3DDevice9Video::CreateCryptoSession メソッドによって返されます。
    • DeviceHandle メンバーを Direct3D デバイス ハンドルに設定します。
  4. IDirect3DAuthenticatedChannel9::Configure呼び出して、認証されたチャネルに D3DAUTHENTICATEDCONFIGURE_CRYPTOSESSION コマンドを送信します。

次の図は、ハンドルの交換を示しています。

dxva デコーダーが暗号化セッションにどのように関連付けられているかを示す図を します。

ソフトウェア デコーダーは、暗号化セッション キーを使用して圧縮されたビデオ バッファーを暗号化できるようになりました。 各圧縮バッファーには、DXVA2_DecodeBufferDesc 構造体の pvPVPState メンバーで、独自の初期化ベクトル (IV) が指定されます。

認証済みチャネル コマンドの送信

認証されたチャネルを構成し、さまざまなコンテンツ保護を設定するために、一連のコマンドが定義されています。 コマンドの一覧については、「コンテンツ保護コマンドの」を参照してください。

認証されたチャネルにコマンドを送信するには、次の手順を実行します。

  1. 入力データ構造を入力します。 このデータ構造は、常に D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT 構造であり、その後に追加のフィールドが続きます。 次の表に示すように、D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT 構造体を入力します。
メンバー 形容
omac する ここでは、このフィールドをスキップします。
ConfigureType コマンドを識別する GUID。 コマンドの一覧については、「コンテンツ保護コマンドの」を参照してください。
hChannel 認証済みチャネルへのハンドル。
SequenceNumber シーケンス番号。 最初のシーケンス番号は、D3DAUTHENTICATEDCONFIGURE_INITIALIZE コマンドを送信することによって指定されます。 別のコマンドを送信するたびに、この数を 1 ずつ増やします。 シーケンス番号は、リプレイ攻撃から保護します。 注: コマンド用とクエリ用の 2 つの個別のシーケンス番号が使用されます。
  1. 入力構造体の omac メンバーの後に表示されるデータ ブロックの OMAC タグを計算します。 次に、このタグ値を omac メンバーにコピーします。
  2. IDirect3DAuthenticatedChannel9::Configure呼び出します。
  3. ドライバーは、コマンドからの出力を D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT 構造体に配置します。
  4. 出力構造の omac メンバーの後に表示されるデータ ブロックの OMAC タグを計算します。 これを、omac メンバーの値と比較します。 一致しない場合は失敗します。
  5. 出力構造体の ConfigureTypehChannel、および SequenceNumber メンバーの値をそれらのメンバーの値と比較します。 一致しない場合は失敗します。
  6. 次のコマンドのシーケンス番号をインクリメントします。

認証済みチャネル クエリの送信

認証されたチャネルに関する情報を取得するために、一連のクエリが定義されています。 クエリの一覧については、「コンテンツ保護クエリの」を参照してください。

認証されたチャネルにコマンドを送信するには、次の手順を実行します。

  1. 入力データ構造を入力します。 このデータ構造は常に D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 構造であり、その後に追加のフィールドが続く可能性があります。 次の表に示すように、D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 構造体を入力します。
メンバー 形容
QueryType クエリを識別する GUID。 クエリの一覧については、「コンテンツ保護クエリの」を参照してください。
hChannel 認証済みチャネルへのハンドル。
SequenceNumber シーケンス番号。 最初のシーケンス番号は、D3DAUTHENTICATEDCONFIGURE_INITIALIZE コマンドを送信することによって指定されます。 別のクエリを送信するたびに、この数を 1 ずつ増やします。 シーケンス番号は、リプレイ攻撃から保護します。 注: コマンド用とクエリ用の 2 つの個別のシーケンス番号が使用されます。
  1. IDirect3DAuthenticatedChannel9::Query呼び出します。
  2. ドライバーは、クエリからの出力を D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT 構造に配置します。 この構造体の後には、クエリの種類に応じて追加のフィールドが続きます。
  3. 出力構造の omac メンバーの後に表示されるデータ ブロックの OMAC タグを計算します。 これを、omac メンバーの値と比較します。 一致しない場合は失敗します。
  4. 出力構造体の ConfigureTypehChannel、および SequenceNumber メンバーの値をそれらのメンバーの値と比較します。 一致しない場合は失敗します。
  5. 次のクエリのシーケンス番号をインクリメントします。

Direct3D 9 ビデオ API