Partager via


Lancement d’une session COPP

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement au nouveau code d’utiliser MediaPlayer, IMFMediaEngine et La capture audio/vidéo dans Media Foundation au lieu de DirectShow, lorsque cela est possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

Pour lancer une session COPP (Certified Output Protection Protocol), vous devez préparer une signature, qui est un tableau qui contient la concaténation des nombres suivants :

  • Nombre aléatoire 128 bits retourné par le pilote. (Cette valeur est indiquée sous la forme guidRandom dans Obtention de la chaîne de certificats du pilote.)
  • Clé AES symétrique 128 bits.
  • Numéro de séquence de départ 32 bits pour les requêtes status.
  • Numéro de séquence de départ 32 bits pour les commandes COPP.

Générez une clé AES symétrique comme suit :

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 fonction CryptGenKey crée la clé symétrique, mais la clé est toujours conservée dans le csp. Pour exporter la clé dans un tableau d’octets, utilisez la fonction CryptExportKey . C’est la raison pour laquelle vous utilisez l’indicateur CRYPT_EXPORTABLE lors de l’appel de CryptGenKey. Le code suivant exporte la clé et la copie dans le

pData

.

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

Données retournées dans

pData

a la disposition suivante :

BLOBHEADER header
DWORD      cbSize
BYTE       key[]

Toutefois, aucune structure qui correspond à cette disposition n’est définie dans les en-têtes CryptoAPI. Vous pouvez en définir un ou effectuer un pointeur arithmétique. Par exemple, pour vérifier la taille de la clé :

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

Pour obtenir le pointeur vers la clé elle-même :

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

Ensuite, générez un nombre aléatoire 32 bits à utiliser comme séquence de départ pour les requêtes copp status. La méthode recommandée pour créer un nombre aléatoire consiste à appeler la fonction CryptGenRandom . N’utilisez pas la fonction rand dans la bibliothèque d’exécution C, car elle n’est pas vraiment aléatoire. Générez un deuxième nombre aléatoire 32 bits à utiliser comme séquence de départ pour les commandes COPP.

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

Vous pouvez maintenant préparer la signature COPP. Il s’agit d’un tableau de 256 octets, défini comme la structure AMCOPPSignature . Initialisez le contenu du tableau à zéro. Ensuite, copiez les quatre nombres dans le tableau : le nombre aléatoire du pilote, la clé AES, le numéro de séquence status et le numéro de séquence de commande, dans cet ordre. Enfin, échangez l’ordre des octets de l’ensemble du tableau.

Selon la documentation de CryptEncrypt :

« La longueur des données en texte clair qui peuvent être chiffrées avec un appel à **CryptEncrypt** avec une clé RSA est la longueur du module de clé moins onze octets. Les onze octets sont le minimum choisi pour le remplissage PKCS \#1. »

Dans ce cas, le module est de 256 octets, de sorte que la longueur maximale du message est de 245 octets (256 à 11). La structure AMCOPPSignature est de 256 octets, mais les données significatives dans la signature ne sont que de 40 octets. Le code suivant chiffre la signature et fournit le résultat dans

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

Passez maintenant le tableau chiffré à IAMCertifiedOutputProtection::SessionSequenceStart :

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

Si cette méthode réussit, vous êtes prêt à envoyer des commandes COPP et des requêtes status au pilote.

Utilisation du protocole COPP (Certified Output Protection Protocol)