콘텐츠 보호 GPU-Based

이 항목에서는 그래픽 드라이버가 제공할 수 있는 비디오 콘텐츠 보호 기능에 대해 설명합니다.

소개

다음 다이어그램은 보호된 비디오 콘텐츠가 렌더링될 파이프라인을 통해 이동하는 방법에 대한 간소화된 보기를 보여 줍니다.

보호된 비디오 콘텐츠를 보여 주는 다이어그램

참고

PMP( 보호된 미디어 경로 )는 이 다이어그램에 표시되지 않습니다. 여기에 표시된 데이터 흐름은 PMP 프로세스 내에서 또는 애플리케이션 프로세스 내에서 발생할 수 있습니다.

디코더는 외부 원본에서 암호화되고 압축된 비디오 데이터를 받습니다. 또한 디코더는 이 데이터의 암호를 해독하는 암호화 키도 수신한다고 가정합니다. 이 항목에서는 비디오 원본과 디코더 간의 키 교환에 대해 설명하지 않지만 PMP는 가능한 메커니즘 하나를 정의합니다. GPU는 이 단계에 포함되지 않습니다.

하드웨어 가속 디코딩의 경우 소프트웨어 디코더는 압축된 비디오 콘텐츠를 GPU에 전달합니다. 이 콘텐츠를 보호하기 위해 디코더는 데이터를 하드웨어 가속기로 전달하기 전에 일반적으로 AES-CTR을 사용하여 데이터를 다시 암호화합니다. 키 교환 메커니즘은 디코더와 그래픽 드라이버 간에 정의됩니다.

디코딩된 비디오 프레임은 일반적으로 투명하게 비디오 메모리에 저장됩니다. 이 시점에서 프레임이 처리된 다음 표시됩니다. 프레젠테이션에는 두 가지 기본 옵션이 있습니다.

  • 프레임은 하드웨어 오버레이를 사용하여 표시할 수 있습니다. 자세한 내용은 하드웨어 오버레이 지원을 참조하세요.
  • 공유 표면을 사용하여 DWM(데스크톱 창 관리)에서 프레임을 표시할 수 있습니다.

마지막 단계는 모니터에 프레임을 표시하는 것입니다. 이 프레임은 그래픽 카드 디스플레이 디바이스 간의 링크 보호가 필요할 수 있습니다. 링크 보호의 예로 High-Bandwidth HDCP(Digital Content Protection)가 있습니다. 연결 보호는 OPM( 출력 보호 관리자 )을 사용하여 구성됩니다. 이 항목에서는 OPM에 대해 설명하지 않습니다. 자세한 내용은 출력 보호 관리자 사용을 참조하세요.

디코딩 프로세스 개요

하드웨어 가속 디코딩 중에 소프트웨어 디코더는 압축된 비디오 데이터를 그래픽 카드 전달해야 합니다. 프리미엄 콘텐츠의 경우 일반적으로 GPU로 전송되기 전에 대칭 키 암호화를 사용하여 이 데이터를 암호화해야 합니다.

디코딩을 위해 비디오를 암호화하기 위해 소프트웨어 디코더는 다음 인터페이스를 사용합니다.

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. 인증된 채널 명령 보내기 섹션에 설명된 대로 IDirect3DAuthenticatedChannel9::Configure를 호출하여 D3DAUTHENTICATEDCONFIGURE_INITIALIZE 명령을 보냅니다. 이 명령에는 인증된 채널로 전송되는 명령 및 쿼리에 대한 시작 시퀀스 번호가 포함됩니다.
  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 구조에서 함수 멤버를 DXVA2_DECODE_GET_DRIVER_HANDLE 설정합니다. pPrivateOutputDataHANDLE 값을 저장할 수 있을 만큼 큰 버퍼의 주소로 설정합니다. (이전 예제에서 이 버퍼는 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씩 증분합니다. 시퀀스 번호는 재생 공격을 방지합니다. 참고: 두 개의 개별 시퀀스 번호가 사용되며, 하나는 명령에, 다른 하나는 쿼리용으로 사용됩니다.
  1. 입력 구조체의 omac 멤버 다음에 나타나는 데이터 블록에 대한 OMAC 태그를 계산합니다. 그런 다음 이 태그 값을 omac 멤버에 복사합니다.
  2. IDirect3DAuthenticatedChannel9::Configure를 호출합니다.
  3. 드라이버는 명령의 출력을 D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT 구조체에 배치합니다.
  4. 출력 구조체의 omac 멤버 다음에 나타나는 데이터 블록에 대한 OMAC 태그를 계산합니다. 이를 omac 멤버의 값과 비교합니다. 일치하지 않으면 실패합니다.
  5. 출력 구조의 ConfigureType, hChannelSequenceNumber 멤버의 값을 해당 멤버의 값과 비교합니다. 일치하지 않으면 실패합니다.
  6. 다음 명령에 대한 시퀀스 번호를 증분합니다.

인증된 채널 쿼리 보내기

인증된 채널에 대한 정보를 검색하기 위한 쿼리 집합이 정의됩니다. 쿼리 목록은 콘텐츠 보호 쿼리를 참조하세요.

인증된 채널에 명령을 보내려면 다음 단계를 수행합니다.

  1. 입력 데이터 구조를 입력합니다. 이 데이터 구조는 항상 D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 구조이며 추가 필드가 뒤따를 수 있습니다. 다음 표와 같이 D3DAUTHENTICATEDCHANNEL_QUERY_INPUT 구조를 채웁니다.
멤버 설명
QueryType 쿼리를 식별하는 GUID입니다. 쿼리 목록은 콘텐츠 보호 쿼리를 참조하세요.
hChannel 인증된 채널에 대한 핸들입니다.
SequenceNumber 시퀀스 번호입니다. 첫 번째 시퀀스 번호는 D3DAUTHENTICATEDCONFIGURE_INITIALIZE 명령을 전송하여 지정됩니다. 다른 쿼리를 보낼 때마다 이 숫자를 1씩 증분합니다. 시퀀스 번호는 재생 공격을 방어합니다. 참고: 두 개의 별도 시퀀스 번호가 사용 됩니다., 명령에 대 한 하나 및 쿼리에 대 한 하나.
  1. IDirect3DAuthenticatedChannel9::Query를 호출합니다.
  2. 드라이버는 쿼리의 출력을 D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT 구조에 배치합니다. 이 구조 다음에는 쿼리 형식에 따라 추가 필드가 잇습니다.
  3. 출력 구조의 omac 멤버 다음에 나타나는 데이터 블록에 대한 OMAC 태그를 계산합니다. 이를 omac 멤버의 값과 비교합니다. 일치하지 않으면 실패합니다.
  4. 출력 구조의 ConfigureType, hChannelSequenceNumber 멤버의 값을 해당 멤버의 값과 비교합니다. 일치하지 않으면 실패합니다.
  5. 다음 쿼리에 대한 시퀀스 번호를 증분합니다.

Direct3D 9 비디오 API