Bagikan melalui


Memulai Sesi COPP

[Fitur yang terkait dengan halaman ini, DirectShow, adalah fitur warisan. Ini telah digantikan oleh MediaPlayer, IMFMediaEngine, dan Pengambilan Audio/Video di Media Foundation. Fitur-fitur tersebut telah dioptimalkan untuk Windows 10 dan Windows 11. Microsoft sangat menyarankan agar kode baru menggunakan MediaPlayer, IMFMediaEngine , dan Pengambilan Audio/Video di Media Foundation alih-alih DirectShow, jika memungkinkan. Microsoft menyarankan agar kode yang ada yang menggunakan API warisan ditulis ulang untuk menggunakan API baru jika memungkinkan.]

Untuk memulai sesi Certified Output Protection Protocol (COPP), Anda harus menyiapkan tanda tangan, yang merupakan array yang berisi perangkaian angka-angka berikut:

  • Angka acak 128-bit yang dikembalikan oleh driver. (Nilai ini ditampilkan sebagai guidRandom dalam Mendapatkan Rantai Sertifikat Driver.)
  • Kunci AES simetris 128-bit.
  • Nomor urutan awal 32-bit untuk permintaan status.
  • Nomor urutan awal 32-bit untuk perintah COPP.

Hasilkan kunci AES simetris sebagai berikut:

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

Fungsi CryptGenKey membuat kunci konten, tetapi kuncinya masih ditahan di CSP. Untuk mengekspor kunci ke dalam array byte, gunakan fungsi CryptExportKey . Ini adalah alasan untuk menggunakan bendera CRYPT_EXPORTABLE saat memanggil CryptGenKey. Kode berikut mengekspor kunci dan menyalinnya ke dalam

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

Data yang dikembalikan di

pData

memiliki tata letak berikut:

BLOBHEADER header
DWORD      cbSize
BYTE       key[]

Namun, tidak ada struktur yang cocok dengan tata letak ini yang didefinisikan dalam header CryptoAPI. Anda dapat menentukan satu atau melakukan beberapa aritmatika penunjuk. Misalnya, untuk memverifikasi ukuran kunci:

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

Untuk mendapatkan penunjuk ke kunci itu sendiri:

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

Selanjutnya, buat angka acak 32-bit untuk digunakan sebagai urutan awal untuk permintaan status COPP. Cara yang disarankan untuk membuat nomor acak adalah dengan memanggil fungsi CryptGenRandom . Jangan gunakan fungsi rand di pustaka run-time C, karena tidak benar-benar acak. Hasilkan angka acak 32-bit kedua untuk digunakan sebagai urutan awal untuk perintah COPP.

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

Sekarang Anda dapat menyiapkan tanda tangan COPP. Ini adalah array 256-byte, yang didefinisikan sebagai struktur AMCOPPSignature . Menginisialisasi konten array ke nol. Kemudian salin empat angka ke dalam array—angka acak driver, kunci AES, nomor urutan status, dan nomor urutan perintah, dalam urutan tersebut. Terakhir, tukar urutan byte dari seluruh array.

Menurut dokumentasi untuk CryptEncrypt:

"Panjang data teks biasa yang dapat dienkripsi dengan panggilan ke **CryptEncrypt** dengan kunci RSA adalah panjang modulus kunci dikurangi sebelas byte. Sebelas byte adalah minimum yang dipilih untuk padding PKCS \#1."

Dalam hal ini, modulus adalah 256 byte, sehingga panjang pesan maksimum adalah 245 byte (256 – 11). Struktur AMCOPPSignature adalah 256 byte, tetapi data yang bermakna dalam tanda tangan hanya 40 byte. Kode berikut mengenkripsi tanda tangan dan memberikan hasilnya dalam

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

Sekarang teruskan array terenkripsi ke IAMCertifiedOutputProtection::SessionSequenceStart:

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

Jika metode ini berhasil, Anda siap untuk mengirim perintah COPP dan permintaan status ke driver.

Menggunakan Protokol Perlindungan Output Bersertifikat (COPP)