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.
Tópicos relacionados