启动 COPP 会话
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
若要 (COPP) 会话启动认证输出保护协议,必须准备 一个签名,该签名是包含以下数字串联的数组:
- 驱动程序返回的 128 位随机数。 (此值在获取驱动程序的证书链中显示为 guidRandom。)
- 128 位对称 AES 密钥。
- 状态请求的 32 位起始序列号。
- COPP 命令的 32 位起始序列号。
生成对称 AES 密钥,如下所示:
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.
);
CryptGenKey 函数创建对称密钥,但密钥仍保存在 CSP 中。 若要将密钥导出到字节数组中,请使用 CryptExportKey 函数。 这是调用 CryptGenKey 时使用 CRYPT_EXPORTABLE 标志的原因。 以下代码导出密钥并将其复制到
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);
中返回的数据
pData
具有以下布局:
BLOBHEADER header
DWORD cbSize
BYTE key[]
但是,CryptoAPI 标头中未定义与此布局匹配的结构。 可以定义一个或执行一些指针算术。 例如,若要验证密钥的大小,请执行以下操作:
DWORD *pcbKey = (DWORD*)(pData + sizeof(BLOBHEADER));
if (*pcbKey != 16)
{
// Wrong size! Should be 16 bytes (128 bits).
}
若要获取指向键本身的指针,请执行以下操作:
BYTE *pKey = pData + sizeof(BLOBHEADER) + sizeof(DWORD);
接下来,生成一个 32 位随机数,用作 COPP 状态请求的起始序列。 创建随机数的建议方法是调用 CryptGenRandom 函数。 请勿在 C 运行时库中使用 rand 函数,因为它不是真正随机的。 生成第二个 32 位随机数,用作 COPP 命令的起始序列。
UINT uStatusSeq; // Status sequence number.
UINT uCommandSeq; // Command sequence number.
CryptGenRandom(hCSP, sizeof(UINT), &uStatusSeq);
CryptGenRandom(hCSP, sizeof(UINT), &uCommandSeq);
现在可以准备 COPP 签名。 这是一个 256 字节数组,定义为 AMCOPPSignature 结构。 将数组的内容初始化为零。 然后,将四个数字复制到数组中-驱动程序的随机数、AES 键、状态序列号和命令序列号(按该顺序排列)。 最后,交换整个数组的字节顺序。
根据 CryptEncrypt 的文档:
- “通过调用具有 RSA 密钥的 CryptEncrypt** 可以加密的纯文本数据的长度是密钥取模减去 11 个字节的长度。 11 个字节是 PKCS \#1 填充选择的最小值。”
在这种情况下,取模为 256 字节,因此最大消息长度为 245 字节 (256 – 11) 。 AMCOPPSignature 结构为 256 字节,但签名中有意义的数据仅为 40 字节。 以下代码加密签名,并在 中提供结果
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
);
现在,将加密的数组传递给 IAMCertifiedOutputProtection::SessionSequenceStart:
hr = pCOPP->SessionSequenceStart(&CoppSig);
if (SUCCEEDED(hr))
{
// Ready to send COPP commands and status requests.
}
如果此方法成功,则可以向驱动程序发送 COPP 命令和状态请求。
相关主题