このトピックでは、Output Protection Manager (OPM) を使用して、物理コネクタを介してディスプレイ デバイスに送られるビデオ コンテンツを保護する方法について説明します。 このトピックは、次のセクションで構成されています。
通常、Premium ビデオ コンテンツは、不正に複製されないように暗号化されます。 当然、表示前にビデオの暗号化を解除する必要があります。 暗号化が解除され、圧縮が解除されたフレームは、物理コネクタを介してディスプレイ デバイスに送られる必要があります。 場合によっては、この時点でコンテンツ プロバイダーは、物理コネクタ上を進むビデオ フレームを保護する必要があります。
この目的のために、さまざまな保護メカニズムが存在しています。たとえば、高帯域幅デジタル コンテンツ保護 (HDCP)、デジタル出力用の DisplayPort Content Protection (DPCP)、アナログ出力用の Copy Generation Management System - Analog (CGMS-A) などです。 一般に、これらのメカニズムでは、信号を、ディスプレイへの送信前に暗号化またはスクランブルする必要があります。
OPM を使用すると、アプリケーションでビデオ出力にコンテンツ保護メカニズムを適用できます。 アプリケーションでは、OPM を使用して、セキュリティで保護された信頼できるチャネルを介してグラフィックス ドライバーにコマンドと状態要求を送信します。 OPM を使用すると、アプリケーションで以下が可能になります。
- グラフィックス ドライバーが Microsoft によって署名されていることを確認する。
- ドライバーとの信頼できる通信チャネルを設定する。
- 物理出力にコンテンツ保護メカニズムを適用する。
OPM は Certified Output Protection Protocol (COPP) に代わるものであり、同様の API を使用します。 下位互換性を確保するため、OPM インターフェイスで COPP インターフェイスをエミュレートできます。 OPM と COPP には次のような違いがあります。
- OPM では X.509 証明書が使用され、COPP では独自の証明書形式が使用されます。
- OPM は HDCP リピーターに対応しています。
- OPM を使用するアプリケーションでは、HDCP システム再生可能メッセージ (SRM) を解析する必要がありません。
- OPM は、グラフィックス ディスプレイで複製モードを使用している場合に使用できます。 COPP は複製モードに対応していません。
アプリケーションで、保護されたメディア パス (PMP) を使用してビデオ コンテンツを再生する場合、PMP で必要なすべての OPM 呼び出しが行われるため、OPM API を使用する必要はありません。 OPM API は、PMP を使用していないアプリケーションで使用できます。
OPM は Windows Vista 以降で使用できますが、この API は Windows 7 まで公開されていませんでした。 アプリケーションで OPM を使用するには、Windows 7 SDK のヘッダーとライブラリ ファイルが必要です。 Windows Vista または Windows Server 2008 で OPM を使用するために DLL を再配布する必要はありません。
ビデオ出力
グラフィックス アダプターは、それぞれ独自の機能を備えた複数の物理出力を含む場合があります。 保護されたコンテンツをアプリケーションで再生する前に、ビデオを表示するグラフィックス カードに関連する、すべてのビデオ出力に適切な保護メカニズムを設定する必要があります。 適用する保護メカニズムは、コンテンツの使用規則によって異なります。
各ビデオ出力は、IOPMVideoOutput インターフェイスのインスタンスによって表されます。 ビデオ出力を取得するために、Direct3D デバイスまたはモニター ハンドルを使用できます。
Direct3D デバイスを使用する場合:
- アプリケーションでビデオ フレームを保持するサーフェスの作成に使用する、Direct3D デバイスの IDirect3DDevice9 ポインターを取得します。
- OPMGetVideoOutputsFromIDirect3DDevice9Object 関数を呼び出します。 この関数は、出力ごとに 1 つずつ、IOPMVideoOutput ポインターの配列を割り当てます。
モニター ハンドルを使用する場合:
- EnumDisplayMonitors を呼び出して、ビデオ ウィンドウに対応する HMONITOR ハンドルを取得します。 同じウィンドウに複数のモニターを関連付けることができるため、複数の HMONITOR ハンドルが得られる場合があります。
- モニター ハンドルごとに、OPMGetVideoOutputsFromHMONITOR を呼び出します。 この関数は、出力ごとに 1 つずつ、IOPMVideoOutput ポインターの配列を割り当てます。
OPM セッションを初期化する
アプリケーションでは、OPM コマンドまたは状態要求を送信する前に、ビデオ出力が信頼されていることを確認し、セッション キーを確立する必要があります。 セッション キーは、アプリケーションとグラフィックス ドライバーの間で交換されるデータに署名するために使用されます。
OPM API で、信頼を確立し、セッション キーを設定するハンドシェイクを定義します。 次のように、IOPMVideoOutput インターフェイスのインスタンスごとに、このハンドシェイクを実行する必要があります。
IOPMVideoOutput::StartInitialization を呼び出します。 このメソッドを使って、次の 2 つのデータを取得します。
- ドライバーによって生成される乱数。 この数値を使用してハンドシェイクを完了します。
- ドライバーの X.509 証明書チェーン。
証明書チェーンが Microsoft によって署名されていることを確認します。
Note
証明書の失効は OPM の対象範囲ではありません。
証明書チェーンからドライバーの公開キーを取得します。
128 ビットの AES セッション キーを生成します。
2 つのランダムな 32 ビット数値を生成します。
- OPM 状態要求の開始シーケンス番号。
- OPM コマンドの開始シーケンス番号。
これらの数値は、CryptGenRandom などの、暗号として安全な擬似乱数ジェネレーターを使用して生成する必要があります。
IOPMVideoOutput::FinishInitialization で説明されているように、ドライバーの乱数 (手順 1 で取得)、セッション キー、2 つのシーケンス番号を OPM_ENCRYPTED_INITIALIZATION_PARAMETERS 構造体にコピーします。
ドライバーの証明書にあるドライバーの公開キーを使用して、RSAES-OAEP で OPM_ENCRYPTED_INITIALIZATION_PARAMETERS 構造体を暗号化します。
OPM 状態要求を送信する
OPM 状態要求を送信すると、物理コネクタの種類や現在の保護レベルなど、ビデオ出力に関する情報が返されます。 要求の種類の一覧については、「OPM 状態要求」を参照してください。
状態要求を送信するには、次の手順を実行します。
次の表に示すように、OPM_GET_INFO_PARAMETERS 構造体を初期化します。
メンバー 説明 omac ここでは、このフィールドをスキップします。 rnRandomNumber 暗号として安全な 128 ビット乱数。 状態要求を行うときは、同じ要求を行う場合でも常に新しい乱数を生成します。 その数値は、後で参照する必要があるため、変数に保存します。 guidInformation 状態要求を識別する GUID。 状態要求の一覧については、「OPM 状態要求」を参照してください。 ulSequenceNumber シーケンス番号。 最初の状態要求では、IOPMVideoOutput::FinishInitialization メソッドで指定した開始シーケンス番号 (「OPM を初期化する」セッションの手順 5) を使用します。別の状態要求を行うたびに、この数を 1 ずつ増分します。 abParameters 要求の追加の入力データを含むバイト配列。 入力データの形式は、各状態要求のリファレンス トピックに示されています。 cbParametersSize abParameters 配列内の有効なデータのサイズ。 配列の残りの部分の内容は定義されていません。 1 キー CBC MAC (OMAC-1) を計算して omac メンバーの後にあるデータ ブロックのハッシュを計算し、omac メンバーをこの値に設定します。 「OPM のコード例」を参照してください。
IOPMVideoOutput::GetInformation メソッドを呼び出します。 OPM_GET_INFO_PARAMETERS 構造体へのポインターと、OPM_REQUESTED_INFORMATION 構造体へのポインターを渡します。 ドライバーの応答は、OPM_REQUESTED_INFORMATION 構造体に書き込まれます。
- この構造体の omac メンバーには、このメンバーの後に続くデータに対して計算された OMAC が含まれます。
- abRequestedInformation メンバーは、応答の出力データを含むバイト配列です。 出力データの形式は、各状態要求のリファレンス トピックに示されています。
omac メンバーを含めずに、OPM_REQUESTED_INFORMATION 構造体の OMAC を計算します。 OMAC が omac メンバーの値と一致することを確認します。
OPM_REQUESTED_INFORMATION 構造体の cbRequestedInformationSize メンバーが、出力データの正しいサイズを指定していることを確認します。 たとえば、OPM_GET_CONNECTOR_TYPE クエリの出力データは OPM_STANDARD_INFORMATION 構造体であるため、cbRequestedInformationSize の値は
sizeof(OPM_STANDARD_INFORMATION)になります。OPM_REQUESTED_INFORMATION 構造体の abRequestedInformation メンバーを正しい出力データ構造体にキャストします。 たとえば、状態要求が OPM_GET_CONNECTOR_TYPE である場合は、abRequestedInformation を OPM_STANDARD_INFORMATION 構造体にキャストします。
出力データ構造体の rnRandomNumber メンバーが、手順 1 の rnRandomNumber の値と一致していることを確認します。
「無効になったビデオ出力を処理する」の説明に従って、出力データ構造体の ulStatusFlags メンバーを確認します。
手順 5 から 8 のいずれかの確認が失敗した場合、アプリケーションでは保護されたコンテンツの表示を停止する必要があります。
OPM コマンドを送信する
OPM コマンドは、ビデオ出力の保護レベルやその他の設定値を設定するために使用します。 OPM コマンドを送信することは、ドライバーからの応答データがない点を除き、状態要求を送信することと似ています。 コマンドの一覧については、「OPM コマンド」を参照してください。
OPM コマンドを送信するには、次の手順を実行します。
次の表に示すように、OPM_CONFIGURE_PARAMETERS 構造体に入力します。
メンバー 説明 omac ここでは、このフィールドをスキップします。 guidSetting コマンドを識別する GUID。 コマンドの一覧については、「OPM コマンド」を参照してください。 ulSequenceNumber シーケンス番号。 最初のコマンドでは、IOPMVideoOutput::FinishInitialization メソッドで指定した開始シーケンス番号 (「OPM を初期化する」セッションの手順 5) を使用します。別のコマンドを送信するたびに、この数を 1 ずつ増分します。 abParameters コマンドの追加の入力データを含むバイト配列。 入力データの形式は、各コマンドのリファレンス トピックに示されています。 cbSettingDataSize abParameters 配列内の有効なデータのサイズ。 配列の残りの部分の内容は定義されていません。 omac メンバーの後にあるデータ ブロックの OMAC を計算し、omac メンバーをこの値に設定します。
IOPMVideoOutput::Configure を呼び出します。
ほとんどのコマンドには、コマンドの状態を返す、対応する状態要求があります。 たとえば、OPM_SET_PROTECTION_LEVEL コマンドでは保護レベルを設定し、OPM_GET_VIRTUAL_PROTECTION_LEVEL コマンドでは現在の保護レベルを取得します。
無効になったビデオ出力を処理する
ビデオ出力は、ビデオ コンテンツの不正使用を防ぐために、時を問わず無効になることがあります。 これが起こる理由として考えられるのは、保護メカニズムが動作を停止した、ドライバーが改ざんを検出した、またはディスプレイが物理コネクタから切断されたことです。 ビデオ出力が無効になっている間、ビデオ フレームは表示されません。
コンテンツ保護が有効になっている間、アプリケーションでは定期的に (少なくとも 2 秒に 1 回) 次の手順を実行する必要があります。
- IOPMVideoOutput::GetInformation を呼び出して、OPM_GET_ACTUAL_PROTECTION_LEVEL または OPM_GET_VIRTUAL_PROTECTION_LEVEL のいずれかの状態要求を送信します。 どちらのコマンドの戻りデータも 、OPM_STANDARD_INFORMATION 構造体です。
- OPM_STANDARD_INFORMATION 構造体の ulInformation メンバーを確認します。 このメンバーには、コンテンツ保護がまだ有効かどうかを示すフラグが含まれています。 コンテンツ保護がオフの場合は、すぐにビデオの再生を停止します。
- コンテンツ保護がオンの場合は、OPM_STANDARD_INFORMATION 構造体の ulStatusFlags メンバーを確認します。 設定されたフラグがない場合、ビデオ出力は正しく動作しています。 それ以外の場合、ビデオ出力は無効になります。
ulStatusFlags には、次のフラグが定義されています。
| フラグ | 説明 |
|---|---|
| OPM_STATUS_LINK_LOST | 出力保護が何らかの理由 (たとえば、ディスプレイ デバイスがコネクタから取り外された可能性がある) で動作を停止しました。 再生を停止し、すべての出力保護メカニズムをオフにします。 |
| OPM_STATUS_RENEGOTIATION_REQUIRED | アプリケーションでは OPM セッションを再確立する必要があります。 次のように対応します。
|
| OPM_STATUS_REVOKED_HDCP_DEVICE_ATTACHED | このフラグは、HDCP が使用されている場合にのみ適用され、取り消された HDCP デバイスの存在を示します。 再生を停止し、このビデオ出力のすべての保護メカニズムをオフにします。 このフラグを設定すると、OPM_STATUS_LINK_LOST フラグも設定されます。 |
| OPM_STATUS_REVOKED_HDCP_DEVICE_ATTACHED | ドライバーが改ざんを検出しました。 再生を停止し、このビデオ出力を使用してこれ以上ビデオを再生しないでください。 また、システムが侵害されているおそれがあるため、他のすべてのビデオ出力の使用も停止することをお勧めします。 |
HDCP を使用してコンテンツを保護する
このセクションでは、OPM を使用して HDCP 出力保護を有効にする方法について説明します。 アプリケーションで実行する必要がある手順の一般的な概要を、次に示します。 詳細については、このセクションで後述します。
- アプリケーションで、ビデオ出力に SRM を提供しなければならない場合があります。 SRM を受信するメカニズムは、OPM インターフェイスの対象範囲ではありません。 たとえば、SRM はブロードキャスト ストリームの一部として配信される場合があります。
- アプリケーションによって HDCP の出力保護が有効になります。
- アプリケーションでビデオ コンテンツが再生されます。 アプリケーションでは定期的にドライバーにポーリングを行い、HDCP がオンになっていることを確認します。
- 再生が完了すると、アプリケーションで HDCP がオフになります。
SRM を設定する
SRM を設定するには、次の手順を実行します。
- SRM バージョン番号を使用して OPM_SET_HDCP_SRM_PARAMETERS 構造体を初期化します。
- SRM を変数に保存します。
- OPM_SET_HDCP_SRM コマンドをビデオ出力に送信します。 「OPM コマンドを送信する」で説明されている手順を使用します。
- OPM_CONFIGURE_PARAMETERS 構造体の abParameters メンバーには、OPM_SET_HDCP_SRM_PARAMETERS 構造体が含まれています。
- IOPMVideoOutput::Configure メソッドの pbAdditionalParameters パラメーターは、SRM を含む変数を指します。
- OPM_GET_CURRENT_HDCP_SRM_VERSION 状態要求をビデオ出力に送信します。 「OPM 状態要求を送信する」で説明されている手順を使用します。 この状態要求には入力データがないため、OPM_GET_INFO_PARAMETERS 構造体の abParameters メンバーの内容は定義されません。
- IOPMVideoOutput::GetInformation メソッドが返されると、OPM_REQUESTED_INFORMATION 構造体の abRequestedInformation 配列に OPM_STANDARD_INFORMATION 構造体が含まれます。 この構造体の ulInformation メンバーには、現在の SRM のバージョン番号が含まれます。 この値は、手順 2 の値と同じである必要があります。
HDCP を有効にする
HDCP を有効にするには、次の手順を実行します。
- 次の値を使用して OPM_SET_PROTECTION_LEVEL_PARAMETERS 構造体を初期化します。
- ulProtectionType = OPM_PROTECTION_TYPE_HDCP
- ulProtectionLevel = OPM_HDCP_ON
- Reserved = 0
- Reserved2 = 0
- OPM_SET_PROTECTION_LEVEL コマンドを送信します。 abParameters 配列内の入力データは OPM_SET_PROTECTION_LEVEL_PARAMETERS 構造体です。
- OPM_GET_VIRTUAL_PROTECTION_LEVEL 状態要求を送信して、HDCP が有効かどうかを確認します。 OPM_GET_INFO_PARAMETERS 構造体の abParameters メンバーの最初の 4 バイトには、値 OPM_PROTECTION_TYPE_HDCP が含まれています。
GetInformation メソッドが返されると、OPM_REQUESTED_INFORMATION 構造体の abRequestedInformation 配列に OPM_STANDARD_INFORMATION 構造体が含まれます。 この構造体の ulInformation メンバーには、OPM_HDCP_PROTECTION_LEVEL 列挙の値が含まれます。 値が OPM_HDCP_ON と等しい場合は、HDCP が有効になっていることを意味します。 それ以外の場合、HDCP が有効になるまで、またはエラーが発生するまで、手順 1 から 2 を繰り返します。 (毎回、シーケンス番号を増分し、新しい乱数を生成することを忘れないでください。)
通常、HDCP を有効にするには 100 から 200 ミリ秒かかりますが、それより長くかかる場合もあります。 検証が済むまでは、HDCP が有効になっていると想定しないでください。
保護されたコンテンツの再生がアプリケーションで終了したら、HDCP をオフにします。 手順は HDCP を有効にする場合と同じですが、手順 1 では ulProtectionLevel を OPM_HDCP_OFF に設定します。
Note
コネクタの種類が OPM_CONNECTOR_TYPE_DISPLAYPORT_EMBEDDED の場合は、HDCP を有効にしないでください。 (「OPM コネクタの種類のフラグ」を参照してください。)
関連トピック