Iniciando uma sessão COPP

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Para iniciar uma sessão copp (Protocolo de Proteção de Saída Certificada), você deve preparar uma assinatura, que é uma matriz que contém a concatenação dos seguintes números:

  • O número aleatório de 128 bits retornado pelo driver. (Esse valor é mostrado como guidRandom em Obtendo a cadeia de certificados do driver.)
  • Uma chave AES simétrica de 128 bits.
  • Um número de sequência inicial de 32 bits para solicitações de status.
  • Um número de sequência inicial de 32 bits para comandos COPP.

Gere uma chave AES simétrica da seguinte maneira:

DWORD dwFlag = 0x80;         // Bit length: 128-bit AES.
dwFlag <<= 16;               // Move this value to the upper 16 bits.
dwFlag |= CRYPT_EXPORTABLE;  // We want to export the key.
CryptGenKey(
    hCSP,           // Handle to the CSP.
    CALG_AES_128,   // Use 128-bit AES block encryption algorithm.
    dwFlag,
    &m_hAESKey      // Receives a handle to the AES key.
);

A função CryptGenKey cria a chave simétrica, mas a chave ainda é mantida no CSP. Para exportar a chave para uma matriz de bytes, use a função CryptExportKey . Esse é o motivo para usar o sinalizador CRYPT_EXPORTABLE ao chamar CryptGenKey. O código a seguir exporta a chave e a copia para o

pData

matriz.

DWORD cbData = 0; 
BYTE *pData = NULL;
// Get the size of the blob.
CryptExportKey(hAESKey, 0, PLAINTEXTKEYBLOB, 0, NULL, &cbData);  

// Allocate the array and call again.
pData = new BYTE[cbData];
CryptExportKey(hAESKey, 0, PLAINTEXTKEYBLOB, 0, pData, &cbData);  

Os dados retornados em

pData

tem o seguinte layout:

BLOBHEADER header
DWORD      cbSize
BYTE       key[]

No entanto, nenhuma estrutura que corresponda a esse layout é definida nos cabeçalhos cryptoAPI. Você pode definir um ou fazer alguma aritmética de ponteiro. Por exemplo, para verificar o tamanho da chave:

DWORD *pcbKey = (DWORD*)(pData + sizeof(BLOBHEADER));
if (*pcbKey != 16)
{
    // Wrong size! Should be 16 bytes (128 bits).
}

Para obter o ponteiro para a própria chave:

BYTE *pKey = pData + sizeof(BLOBHEADER) + sizeof(DWORD);

Em seguida, gere um número aleatório de 32 bits a ser usado como a sequência inicial para solicitações de status COPP. A maneira recomendada de criar um número aleatório é chamar a função CryptGenRandom . Não use a função rand na biblioteca de tempo de execução C, pois ela não é verdadeiramente aleatória. Gere um segundo número aleatório de 32 bits a ser usado como a sequência inicial para comandos COPP.

UINT uStatusSeq;     // Status sequence number.
UINT uCommandSeq;    // Command sequence number.
CryptGenRandom(hCSP, sizeof(UINT), &uStatusSeq);
CryptGenRandom(hCSP, sizeof(UINT), &uCommandSeq);

Agora você pode preparar a assinatura copp. Essa é uma matriz de 256 bytes, definida como a estrutura AMCOPPSignature . Inicialize o conteúdo da matriz como zero. Em seguida, copie os quatro números para a matriz : o número aleatório do driver, a chave AES, o status número de sequência e o número da sequência de comandos, nessa ordem. Por fim, troque a ordem de bytes de toda a matriz.

De acordo com a documentação do CryptEncrypt:

"O comprimento dos dados de texto sem formatação que podem ser criptografados com uma chamada para **CryptEncrypt** com uma chave RSA é o comprimento do módulo de chave menos onze bytes. Os onze bytes são o mínimo escolhido para preenchimento PKCS \#1."

Nesse caso, o módulo é de 256 bytes, portanto, o comprimento máximo da mensagem é de 245 bytes (256 – 11). A estrutura AMCOPPSignature é de 256 bytes, mas os dados significativos na assinatura são apenas 40 bytes. O código a seguir criptografa a assinatura e fornece o resultado em

CoppSig

.

AMCOPPSignature CoppSig;
ZeroMemory(&CoppSig, sizeof(CoppSig));
// Copy the signature data into CoppSig. (Not shown.)

// Encrypt the signature:
const DWORD RSA_PADDING = 11;    // 11-byte padding.
DWORD cbDataOut = sizeof(AMCOPPSignature);
DWORD cbDataIn = cbDataOut - RSA_PADDING;
CryptEncrypt(
    hRSAKey, 
    NULL,     // No hash object.
    TRUE,     // Final block to encrypt.
    0,        // Reserved.
    &CoppSig, // COPP signature.
    &cbDataOut, 
    cbDataIn
);

Agora passe a matriz criptografada para IAMCertifiedOutputProtection::SessionSequenceStart:

hr = pCOPP->SessionSequenceStart(&CoppSig);
if (SUCCEEDED(hr))
{
    // Ready to send COPP commands and status requests.
}

Se esse método for bem-sucedido, você estará pronto para enviar comandos COPP e solicitações de status para o driver.

Usando o COPP (Certified Output Protection Protocol)