Freigeben über


Initiieren einer COPP-Sitzung

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]

Um eine COPP-Sitzung (Certified Output Protection Protocol) zu initiieren, müssen Sie eine Signatur vorbereiten, bei der es sich um ein Array handelt, das die Verkettung der folgenden Zahlen enthält:

  • Die vom Treiber zurückgegebene 128-Bit-Zufallszahl. (Dieser Wert wird unter Abrufen der Zertifikatkette des Treibers als guidRandom angezeigt.)
  • Ein symmetrischer 128-Bit-AES-Schlüssel.
  • Eine 32-Bit-Startsequenznummer für status Anforderungen.
  • Eine 32-Bit-Startsequenznummer für COPP-Befehle.

Generieren Sie einen symmetrischen AES-Schlüssel wie folgt:

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

Die CryptGenKey-Funktion erstellt den symmetrischen Schlüssel, aber der Schlüssel befindet sich weiterhin im CSP. Um den Schlüssel in ein Bytearray zu exportieren, verwenden Sie die Funktion CryptExportKey . Dies ist der Grund für die Verwendung des CRYPT_EXPORTABLE-Flags beim Aufrufen von CryptGenKey. Der folgende Code exportiert den Schlüssel und kopiert ihn in die

pData

Array.

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

Die in zurückgegebenen Daten

pData

hat das folgende Layout:

BLOBHEADER header
DWORD      cbSize
BYTE       key[]

In den CryptoAPI-Headern ist jedoch keine Struktur definiert, die diesem Layout entspricht. Sie können entweder eine oder eine Zeigerarithmetik definieren. So überprüfen Sie beispielsweise die Größe des Schlüssels:

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

So rufen Sie den Zeiger auf den Schlüssel selbst ab:

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

Generieren Sie als Nächstes eine 32-Bit-Zufallszahl, die als Startsequenz für COPP-status-Anforderungen verwendet werden soll. Die empfohlene Möglichkeit zum Erstellen einer Zufallszahl besteht darin, die CryptGenRandom-Funktion aufzurufen. Verwenden Sie die rand-Funktion nicht in der C-Laufzeitbibliothek, da sie nicht wirklich zufällig ist. Generieren Sie eine zweite 32-Bit-Zufallszahl, die als Startsequenz für COPP-Befehle verwendet werden soll.

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

Jetzt können Sie die COPP-Signatur vorbereiten. Dies ist ein 256-Byte-Array, das als AMCOPPSignature-Struktur definiert ist. Initialisieren Sie den Inhalt des Arrays auf Null. Kopieren Sie dann die vier Zahlen in das Array – die Zufallszahl des Treibers, die AES-Taste, die status Sequenznummer und die Befehlssequenznummer in dieser Reihenfolge. Tauschen Sie schließlich die Bytereihenfolge des gesamten Arrays aus.

Gemäß der Dokumentation für CryptEncrypt:

"Die Länge der Klartextdaten, die mit einem Aufruf von **CryptEncrypt** mit einem RSA-Schlüssel verschlüsselt werden können, ist die Länge des Schlüsselmoduls minus elf Bytes. Die elf Bytes sind das für PKCS \#1-Auffüllung ausgewählte Minimum."

In diesem Fall beträgt das Modul 256 Bytes, sodass die maximale Nachrichtenlänge 245 Bytes (256 – 11) beträgt. Die AMCOPPSignature-Struktur ist 256 Bytes, aber die aussagekräftigen Daten in der Signatur sind nur 40 Bytes. Der folgende Code verschlüsselt die Signatur und stellt das Ergebnis in bereit.

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

Übergeben Sie nun das verschlüsselte Array an IAMCertifiedOutputProtection::SessionSequenceStart:

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

Wenn diese Methode erfolgreich ist, können Sie COPP-Befehle und status Anforderungen an den Treiber senden.

Verwenden des Certified Output Protection Protocol (COPP)