Condividi tramite


Avvio di una sessione COPP

[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation anziché DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Per avviare una sessione COPP (Certified Output Protection Protocol), è necessario preparare una firma, ovvero una matrice che contiene la concatenazione dei numeri seguenti:

  • Numero casuale a 128 bit restituito dal driver. Questo valore viene visualizzato come guidRandom in Recupero della catena di certificati del driver.
  • Chiave AES simmetrica a 128 bit.
  • Numero di sequenza iniziale a 32 bit per le richieste di stato.
  • Numero di sequenza iniziale a 32 bit per i comandi COPP.

Generare una chiave AES simmetrica come indicato di seguito:

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.
);

La funzione CryptGenKey crea la chiave simmetrica, ma la chiave è ancora contenuta nel CSP. Per esportare la chiave in una matrice di byte, usare la funzione CryptExportKey . Questo è il motivo per l'uso del flag CRYPT_EXPORTABLE quando si chiama CryptGenKey. Il codice seguente esporta la chiave e la copia in

pData

matrice.

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);  

I dati restituiti in

pData

ha il layout seguente:

BLOBHEADER header
DWORD      cbSize
BYTE       key[]

Tuttavia, nessuna struttura corrispondente a questo layout è definita nelle intestazioni CryptoAPI. È possibile definire uno o eseguire un aritmetico puntatore. Ad esempio, per verificare le dimensioni della chiave:

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

Per ottenere il puntatore alla chiave stessa:

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

Generare quindi un numero casuale a 32 bit da usare come sequenza iniziale per le richieste di stato COPP. Il modo consigliato per creare un numero casuale consiste nel chiamare la funzione CryptGenRandom . Non usare la funzione rand nella libreria di runtime C, perché non è veramente casuale. Generare un secondo numero casuale a 32 bit da usare come sequenza iniziale per i comandi COPP.

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

È ora possibile preparare la firma COPP. Si tratta di una matrice a 256 byte definita come struttura AMCOPPSignature . Inizializzare il contenuto della matrice su zero. Copiare quindi i quattro numeri nella matrice, ovvero il numero casuale del driver, la chiave AES, il numero di sequenza di stato e il numero di sequenza di comando, in tale ordine. Infine, scambiare l'ordine di byte dell'intera matrice.

Secondo la documentazione per CryptEncrypt:

"La lunghezza dei dati di testo non crittografato che può essere crittografata con una chiamata a **CryptEncrypt** con una chiave RSA è la lunghezza del modulo di chiave meno undici byte. Gli undici byte sono il minimo scelto per PKCS \#1 riempimento."

In questo caso, il modulo è 256 byte, quindi la lunghezza massima del messaggio è di 245 byte (256 - 11). La struttura AMCOPPSignature è di 256 byte, ma i dati significativi nella firma sono solo 40 byte. Il codice seguente crittografa la firma e fornisce il risultato

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
);

Passare ora la matrice crittografata a IAMCertifiedOutputProtection::SessionSequenceStart:

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

Se questo metodo ha esito positivo, è possibile inviare comandi COPP e richieste di stato al driver.

Uso del protocollo COPP (Certified Output Protection Protocol)