드라이버 공개 키 가져오기

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드가 DirectShow 대신 Media Foundation에서 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

드라이버의 RSA 공개 키는 인증서 리프 노드의 Modulus 및 지수 태그에 포함되어 있습니다. 두 값 모두 base64로 인코딩되며 디코딩되어야 합니다. Microsoft의 CryptoAPI를 사용하는 경우 암호화 알고리즘을 구현하는 모듈인 CSP(암호화 서비스 공급자)로 키를 가져와야 합니다.

모듈러스 및 지수를 base64 인코딩에서 이진 배열로 변환하려면 다음 코드와 같이 CryptStringToBinary 함수를 사용합니다. 함수를 한 번 호출하여 바이트 배열의 크기를 가져옵니다. 그런 다음 버퍼를 할당하고 함수를 다시 호출합니다.

DWORD cbLen = 0, dwSkip = 0, dwFlags = 0;
::CryptStringToBinary(
   pszModulus,  // String that contains the Base64-encoded modulus.
   cchModulus,  // Length of the string, not including the trailing NULL.
   CRYPT_STRING_BASE64,  // Base64 encoding.
   NULL,     // Do not convert yet. Just calculate the length.
   &cbLen,   // Receives the length of the buffer that is required.
   &dwSkip,  // Receives the number of skipped characters.
   &dwFlags  // Receives flags.
);

// Allocate a new buffer.
BYTE *pbBuffer = new BYTE [cbLen];
::CryptStringToBinary(pszModulus, cchModulus, CRYPT_STRING_BASE64, 
    pbBuffer, &cbLen, &dwSkip, &dwFlags);

// (Repeat these steps for the exponent.)

base64로 인코딩된 배열은 big-endian 순서인 반면 CryptoAPI는 작은 엔디안 순서로 숫자를 예상하므로 CryptStringToBinary에서 반환되는 배열의 바이트 순서를 바꿔야 합니다. 모듈러스는 256바이트이지만 디코딩된 바이트 배열은 256바이트 미만일 수 있습니다. 이 경우 256바이트인 새 배열을 할당하고, 데이터를 새 배열에 복사하고, 배열 앞면에 0을 채워야 합니다. 지수는 DWORD(4 바이트) 값입니다.

모듈러스 및 지수 값이 있으면 다음 코드와 같이 키를 기본 CSP(암호화 서비스 공급자)로 가져올 수 있습니다.

// Assume the following values exist:
BYTE *pModulus;     // Byte array that contains the modulus.
DWORD cbModulus;    // Size of the modulus in bytes.
DWORD dwExponent;   // Exponent.

// Create a new key container to hold the key. 
::CryptAcquireContext(
    &hCSP,         // Receives a handle to the CSP.
    NULL,          // Use the default key container.
    NULL,          // Use the default CSP.
    PROV_RSA_AES,  // Use the AES provider (public-key algorithm).
    CRYPT_SILENT | CRYPT_NEWKEYSET 
);

// Move the key into the key container. 
// The data format is: PUBLICKEYSTRUC + RSAPUBKEY + key
DWORD cbKeyBlob = cbModulus + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)
BYTE *pBlob = new BYTE[cbKeyBlob];

// Fill in the data.
PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pBlob;
pPublicKey->bType = PUBLICKEYBLOB; 
pPublicKey->bVersion = CUR_BLOB_VERSION;  // Always use this value.
pPublicKey->reserved = 0;                 // Must be zero.
pPublicKey->aiKeyAlg = CALG_RSA_KEYX;     // RSA public-key key exchange. 

// The next block of data is the RSAPUBKEY structure.
RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pBlob + sizeof(PUBLICKEYSTRUC));
pRsaPubKey->magic = RSA1;            // Public key.
pRsaPubKey->bitlen = cbModulus * 8;  // Number of bits in the modulus.
pRsaPubKey->pubexp = dwExponent;     // Exponent.

// Copy the modulus into the blob. Put the modulus directly after the
// RSAPUBKEY structure in the blob.
BYTE *pKey = (BYTE*)(pRsaPubkey + sizeof(RSAPUBKEY));
CopyMemory(pKey, pModulus, cbModulus);

// Now import the key.
HCRYPTKEY hRSAKey;  // Receives a handle to the key.
CryptImportKey(hCSP, pBlob, cbKeyBlob, 0, 0, &hRSAKey) 

이제 CryptoAPI를 사용하여 명령을 암호화하고 드라이버의 공개 키를 사용하여 요청을 상태 수 있습니다.

COPP(Certified Output Protection Protocol) 사용