GPU-Based 內容保護
本主題描述圖形驅動程式可以提供的視訊內容保護功能。
簡介
下圖顯示受保護影片內容如何透過管線轉譯的簡化檢視。
注意
此圖未描述 受保護的媒體路徑 (PMP) 。 此處顯示的資料流程可能會發生在 PMP 進程或應用程式進程內。
解碼器會接收來自外部來源的加密、壓縮視訊資料。 它也假設解碼器也會收到密碼編譯金鑰來解密此資料。 本主題不會描述影片來源與解碼器之間的金鑰交換,但 PMP 會定義一個可能的機制。 此階段未涉及 GPU。
針對硬體加速解碼,軟體解碼器會將壓縮的視訊內容傳遞至 GPU。 為了保護此內容,解碼器通常會使用 AES-CTR 重新加密資料,再將它傳遞至硬體加速器。 在解碼器和圖形驅動程式之間定義金鑰交換器制。
解碼的視訊畫面會儲存在視訊記憶體中,通常是在清楚的。 此時會處理框架,然後呈現。 簡報有兩個主要選項。
- 畫面格可以使用硬體重迭來呈現。 如需詳細資訊,請參閱 硬體重迭支援。
- 您可以使用共用介面,透過桌面視窗管理 (DWM) 來呈現框架。
最後一個步驟是在監視器上顯示框架,這可能需要圖形卡與顯示裝置之間的連結保護。 連結保護的範例是 High-Bandwidth Digital Content Protection (HDCP) 。 連結保護是使用 Output Protection Manager (OPM) 來設定。 本主題不會描述 OPM;如需詳細資訊,請參閱 使用 Output Protection Manager。
解碼程式概觀
在硬體加速解碼期間,軟體解碼器必須將壓縮的視訊資料傳遞至圖形卡。 針對進階內容,此資料通常必須先使用對稱金鑰加密進行加密,才能傳送至 GPU。
若要加密影片進行解碼,軟體解碼器會使用下列介面:
- IDirectXVideoDecoder。 代表 DXVA 解碼器裝置,也稱為加速器。
- IDirect3DCryptoSession9。 表示提供加密金鑰的密碼編譯會話。
- IDirect3DAuthenticatedChannel9。 表示已驗證的通道,可讓軟體解碼器將密碼編譯會話與 DXVA 解碼器產生關聯。
所有這些介面都是從 Direct3D 裝置取得,如下所示:
介面 | 建立 |
---|---|
IDirectXVideoDecoder | 呼叫 IDirectXVideoDecoderService::CreateVideoDecoder。 DXVA 解碼器裝置是由 DXVA 設定檔 GUID 所識別。 |
IDirect3DCryptoSession9 | 呼叫 IDirect3DDevice9Video::CreateCryptoSession。 |
IDirect3DAuthenticatedChannel9 | 呼叫 IDirect3DDevice9Video::CreateAuthenticatedChannel。 |
注意
若要取得 IDirect3DDevice9Video 介面的指標,請在 D3D9Ex 裝置上呼叫 QueryInterface 。
已驗證的通道會在軟體解碼器和驅動程式之間提供受信任的通道。 通道的運作方式如下:
- 驅動程式提供 X.509 憑證鏈結,其根憑證是由 Microsoft 簽署。
- 憑證包含驅動程式的 RSA 公開金鑰。
- 軟體解碼器會使用公開金鑰來傳送驅動程式 128 位 AES 工作階段金鑰。
- 軟體解碼器會將查詢和命令傳送至已驗證的通道。
- 工作階段金鑰是用來計算查詢和命令 (MAC) 訊息驗證碼。 驅動程式會使用 MAC 來驗證查詢/命令資料的完整性,而軟體解碼器會使用它們來驗證驅動程式回應資料的完整性。
加密解碼器的壓縮視訊緩衝區
以下是加密和解碼程式的高階概觀:
軟體解碼器會從視訊來源接收加密資料的資料流程。 解碼器會解密此資料流程。
軟體解碼器會與密碼編譯會話交涉工作階段金鑰。
軟體解碼器會使用已驗證的通道,將密碼編譯會話與 DXVA 解碼器裝置產生關聯。
軟體解碼器會將壓縮的資料放在 DXVA 緩衝區中,它會從 DXVA 解碼器裝置 (加速器) 。 針對受保護的內容,軟體編碼器會使用加密的工作階段金鑰,加密放入 DXVA 緩衝區的資料。
注意
某些驅動程式會使用內容金鑰,而不是工作階段金鑰進行加密。 內容索引鍵可能會從一個畫面變更為下一個畫面。
解碼器會將加密的壓縮緩衝區提交至加速器。 針對 AES-CTR,解碼器也會傳遞初始化向量。 如果使用內容金鑰,解碼器會傳遞內容金鑰,並使用工作階段金鑰加密。
Direct3D 具有 128 位 AES-CTR 的標準支援,但專為擴充至其他加密類型而設計。
接下來五節會提供更詳細的步驟。
1.查詢驅動程式的內容保護功能
嘗試套用加密之前,請先取得驅動程式的內容保護功能。
- 取得 Direct3D 9 裝置的指標。
- 呼叫IDirect3DDevice9Video介面的QueryInterface。
- 呼叫 IDirect3DDevice9Video::GetContentProtectionCaps。 此方法會在 D3DCONTENTPROTECTIONCAPS 結構中填入驅動程式的內容保護功能。
特別是,尋找下列功能:
- 如果 Caps 成員包含 D3DCPCAPS_SOFTWARE 或 D3DCPCAPS_HARDWARE 旗標,驅動程式就可以執行加密。
- KeyExchangeType成員會指定如何執行工作階段金鑰的金鑰交換。
- 如果 Caps 成員包含 D3DCPCAPS_CONTENTKEY 旗標,驅動程式會使用不同的內容金鑰進行加密。 當您產生工作階段金鑰時,這很重要。
Caps成員會指出其他功能。
2.設定已驗證的通道
下一個步驟是設定已驗證的通道。
呼叫 IDirect3DDevice9Video::CreateAuthenticatedChannel 來建立已驗證的通道。 針對 ChannelType 參數,指定符合驅動程式功能的通道類型。
- D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE通道類型會對應至D3DCPCAPS_SOFTWARE。
- D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE通道類型會對應至D3DCPCAPS_HARDWARE。
CreateAuthenticatedChannel方法會傳回IDirect3DAuthenticatedChannel9介面的指標,以及通道的控制碼。 稍後會使用控制碼,將密碼編譯會話與已驗證的通道產生關聯。
呼叫 IDirect3DAuthenticatedChannel9::GetCertificateSize 以取得驅動程式 X.509 憑證的大小。 配置所需大小的緩衝區。
呼叫 IDirect3DAuthenticatedChannel9::GetCertificate 以取得憑證。 方法會將憑證複製到上一個步驟中配置的緩衝區。
確認驅動程式的憑證已由 Microsoft 簽署,且尚未撤銷。
從憑證取得公開金鑰。
產生隨機 RSA 工作階段金鑰。 此工作階段金鑰用來簽署傳送至已驗證通道的資料。 使用驅動程式的公開金鑰來加密工作階段金鑰。
呼叫 IDirect3DAuthenticatedChannel9::NegotiateKeyExchange 將加密的工作階段金鑰傳送至驅動程式。
初始化安全通道,如下所示:
- 如檔中所述,填入 D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE 結構。
- 呼叫IDirect3DAuthenticatedChannel9::Configure以傳送已驗證通道命令一節中所述的方式傳送D3DAUTHENTICATEDCONFIGURE_INITIALIZE命令。 此命令包含傳送至已驗證通道之命令和查詢的起始序號。
將 D3DAUTHENTICATEDQUERY_CHANNELTYPE 查詢傳送至已驗證通道,以確認通道類型,如 傳送已驗證通道查詢一節中所述。 檢查通道類型是否符合您在 CreateAuthenticatedChannel 方法中指定的內容。
3.設定密碼編譯會話
接下來,設定密碼編譯會話並建立工作階段金鑰。
- 呼叫 IDirect3DDevice9Video::CreateCryptoSession 以建立密碼編譯會話。 這個方法會傳回 IDirect3DCryptoSession9 介面的指標,以及密碼編譯會話的控制碼。
- 呼叫 IDirect3DCryptoSession9::GetCertificateSize 以取得驅動程式 X.509 憑證的大小。 配置所需大小的緩衝區。
- 呼叫 IDirect3DCryptoSession9::GetCertificate 以取得憑證。 方法會將憑證複製到上一個步驟中配置的緩衝區。
- 確認驅動程式的憑證已由 Microsoft 簽署,且尚未撤銷。
- 從憑證取得公開金鑰。
- 產生隨機 RSA 工作階段金鑰。 這是與已驗證通道工作階段金鑰不同的工作階段金鑰。 使用驅動程式的公開金鑰來加密工作階段金鑰。
- 呼叫 IDirect3DCryptoSession9::NegotiateKeyExchange 將加密的工作階段金鑰傳送至驅動程式。
- 如果內容保護功能包含 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 variable.)
然後呼叫 IDirectXVideoDecoder::Execute ,並傳入 DXVA2_DecodeExecuteParams 結構的位址。 DXVA 解碼器的控制碼會在 pPrivateOutputData中傳回。
5.建立 DXVA 解碼器與密碼編譯會話的關聯
接下來,將 DXVA 解碼器裝置與 Direct3D 裝置和密碼編譯會話產生關聯,如下所示:
- 取得 DXVA 解碼器裝置的控制碼,如上一節所述。
- 將 D3DAUTHENTICATEDQUERY_DEVICEHANDLE 查詢傳送至已驗證通道,以取得 Direct3D 裝置的控制碼。
- 使用下列資訊填入 D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION 結構:
- 將 DXVA2DecodeHandle 成員設定為 DXVA 解碼器裝置的控制碼。
- 將 CryptoSessionHandle 成員設定為密碼編譯會話的控制碼。 IDirect3DDevice9Video::CreateCryptoSession方法會傳回此控制碼。
- 將 DeviceHandle 成員設定為 Direct3D 裝置控制碼。
- 呼叫 IDirect3DAuthenticatedChannel9::Configure ,將 D3DAUTHENTICATEDCONFIGURE_CRYPTOSESSION 命令傳送至已驗證的通道。
下圖說明控制碼的交換:
軟體解碼器現在可以使用密碼編譯工作階段金鑰來加密壓縮的視訊緩衝區。 每個壓縮緩衝區都會有自己的初始化向量 (IV) DXVA2_DecodeBufferDesc結構之 pvPVPState成員中指定的。
傳送已驗證的通道命令
系統會定義一組命令來設定已驗證的通道,以及設定各種內容保護。 如需命令清單,請參閱 Content Protection 命令。
若要將命令傳送至已驗證的通道,請執行下列步驟。
- 填入輸入資料結構。 此資料結構一律是 D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT 結構,後面接著其他欄位。 填入 D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT 結構,如下表所示。
member | 描述 |
---|---|
omac | 目前請略過此欄位。 |
ConfigureType | 識別命令的 GUID。 如需命令清單,請參閱 Content Protection 命令。 |
hChannel | 已驗證通道的控制碼。 |
SequenceNumber | 序號。 第一個序號是藉由傳送 D3DAUTHENTICATEDCONFIGURE_INITIALIZE 命令來指定。 每次傳送另一個命令時,請將此數位遞增 1。 序號可防止重新執行攻擊。
注意: 使用兩個不同的序號,一個用於命令,另一個用於查詢。 |
- 計算在輸入結構 omac 成員之後所顯示之資料區塊的 OMAC 標記。 然後將此標籤值複製到 omac 成員。
- 呼叫 IDirect3DAuthenticatedChannel9::Configure。
- 驅動程式會將命令的輸出放在 D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT 結構中。
- 計算輸出結構 omac 成員之後所顯示之資料區塊的 OMAC 標記。 將此與 omac 成員的值進行比較。 如果不符合,則失敗。
- 將輸出結構中 ConfigureType、 hChannel和 SequenceNumber 成員的值,與這些成員的值進行比較。 如果不符合,則失敗。
- 遞增下一個命令的序號。
傳送已驗證的通道查詢
系統會定義一組查詢,以擷取已驗證通道的相關資訊。 如需查詢清單,請參閱 內容保護查詢。
若要將命令傳送至已驗證的通道,請執行下列步驟。
- 填入輸入資料結構。 此資料結構一律是 D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 結構,可能後面接著其他欄位。 填入 D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 結構,如下表所示。
member | 描述 |
---|---|
QueryType | 識別查詢的 GUID。 如需查詢清單,請參閱 內容保護查詢。 |
hChannel | 已驗證通道的控制碼。 |
SequenceNumber | 序號。 第一個序號是藉由傳送 D3DAUTHENTICATEDCONFIGURE_INITIALIZE 命令來指定。 每次傳送另一個查詢時,請將此數位遞增 1。 序號可防止重新執行攻擊。
注意: 使用兩個不同的序號,一個用於命令,另一個用於查詢。 |
- 呼叫 IDirect3DAuthenticatedChannel9::Query。
- 驅動程式會將查詢的輸出放在 D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT 結構中。 此結構後面接著其他欄位,視查詢類型而定。
- 計算輸出結構 omac 成員之後所顯示之資料區塊的 OMAC 標記。 將此與 omac 成員的值進行比較。 如果不符合,則失敗。
- 將輸出結構中 ConfigureType、 hChannel和 SequenceNumber 成員的值,與這些成員的值進行比較。 如果不符合,則失敗。
- 遞增下一個查詢的序號。