rech

hi ,

I meet a problem to call IAMCertifiedOutputProtection:essionSequenceStart function.

it always failed. I eximine the follow discription in MSDN(location:http://msdn2.microsoft.com/en-us/library/aa468617.aspx).

I want to know when to swap the byte order of AMCOPPSignature struct.before encryt or after encrypt

accorording this document ,it should be "before encrypt " .

if it is , CryptEncrypt can't encrypt the AMCOPPSignature by once.that is because the the meaningful data has been swapped to end beyoned 245.

but the document says it can encrypt the struct by once.

Can somebody tell me how to do or why


thanks


///////////////////////////////////////////////////

///the words below comes from msdn.

Next, generate a 32-bit random number to use as the starting sequence for COPP status requests. The recommended way to create a random number is to call the CryptGenRandom function. Do not use the rand function in the C run-time library, because it is not truly random. Generate a second 32-bit random number to use as the starting sequence for COPP commands.

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

Now you can prepare the COPP signature. This is a 256-byte array, defined as the AMCOPPSignature structure. Initialize the contents of the array to zero. Then copy the four numbers into the array¡ªthe driver's random number, the AES key, the status sequence number, and the command sequence number, in that order. Finally, swap the byte order of the entire array.

According to the documentation for CryptEncrypt:

The length of plaintext data that can be encrypted with a call to CryptEncrypt with an RSA key is the length of the key modulus minus eleven bytes.

In this case, the modulus is 256 bytes, so the maximum message length is 245 bytes (256 ¨C 11). The AMCOPPSignature structure is 256 bytes, but the meaningful data in the signature is only 40 bytes. The following code encrypts the signature and provides the result in 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
);



Re: DirectShow Development Enable COPP on display driver problem . help me ! thanks

Mike Wasson-MSFT

The signature is to be inverted only for the first (256 ¨C padding) number of bytes. Code:

ASSERT(cbToEncrypt > RSA_PADDING);

cbDataOut = cbToEncrypt - RSA_PADDING;

if (!CryptEncrypt(m_hRSAKey, 0, TRUE, 0, 0, &cbDataOut, cbDataIn))

{

dwErr = LogDebugErrorMessage("CryptEncrypt");

hr = HRESULT_FROM_WIN32(dwErr);

break;

}

pbBuf = new BYTE[cbDataOut];

if (0 == pbBuf)

{

hr = E_OUTOFMEMORY;

break;

}

ZeroMemory(pbBuf, cbDataOut);

cbDataOut = cbToEncrypt - RSA_PADDING;

// Crypto API outputs/encrypts in little endian;

for (UINT i = 0; i < cbDataOut; i++)

{

pbBufIdea = pbDataIn[cbDataOut-i-1];

}

if (!CryptEncrypt(m_hRSAKey, 0, TRUE, 0, pbBuf, &cbDataOut, cbDataIn))

{

dwErr = LogDebugErrorMessage("CryptEncrypt");

hr = HRESULT_FROM_WIN32(dwErr);

break;

}

Dragos Avadanei [MSFT]

----------------------------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights. You assume all risk for your use.

(c) 2006 Microsoft Corporation. All rights reserved.








Re: DirectShow Development Enable COPP on display driver problem . help me ! thanks

rech

thanks Dragos for your adivce

I will try this method .






Re: DirectShow Development Enable COPP on display driver problem . help me ! thanks

rech

Ok,

It works ,thanks for your help






Re: DirectShow Development Enable COPP on display driver problem . help me ! thanks

kevin.jztan

Dear Mike,

I follow your suggestion to swap the COPP signature and do the encrytion by CryptEncrypt() API,
it working and return true.

But, i still get the "E_UNEXPECTED" return when i trying to initiate the COPP session by call IAMCertifiedOutputProtection:: SessionSequenceStart() API.

Beside, there is very very limited relative resource of COPP implementation that can i find on internet.
I had checked my code line by line many time, And still can not figture out what wrong with my code.
Can u help me thank you very much.

Here is my code,

Code Snippet

//-----------------------------------------------------------------------------------------------------
//Import the Drivers's Public Key //-----------------------------------------------------------------------------------------------------
dprintf("[COPPTestBedDlg][------Starting for Import the Drivers's Public Key------]");
CString cstrDriverPubKeyModulus = _T("yxCkp/fatiVYTYmsvLlEcf8CzNtEdqKlB1EqUtJnhAXs6bq+wYIRVRWVn8qRUuHZGDUKM+AY7R61kiy3ASBWVY6kV2UAuLvZ7u5ZxFNQCAq6MCaieaDlKcAzE58RAL3NJt5Q0zxAiImX/o1In4Or7JjDGhiBEkfwn7/HUtQ40OWlxfCfc/Zc4dnIQUgR7vBenULZHBP1Y97QGKLJQphKdlMzOmQiEIpan8JT8DVpnMgQRPL/Tg0GzJ5Ym4cJ/3LMY1VnlstKaYDBaK8ecRGpjvcPaHthWbv1QU6YOAtIaXj0q+NJNZoz/C/t0NZrryKP6YZ7XUWZ7cxMe6IYn2Wcbw==");
CString cstrDriverPubKeyExponent = _T("AQAB");
BYTE *pbDriverPubKeyModulus = new BYTE [256];
BYTE *pbDriverPubKeyExponent = new BYTE [4];
DWORD cbModulus, cbExponent;
//Clean buffer
int idx;
for(idx=0;idx<256;idx++)
pbDriverPubKeyModulus[idx] = 0;
for(idx=0;idx<4;idx++)
pbDriverPubKeyExponent[idx] = 0;

//Do Base64-Decoding and swap the byte order
if( !DoBase64DecodingAndSwap(cstrDriverPubKeyModulus, pbDriverPubKeyModulus, 344, &cbModulus,256) )
{
dprintf("[COPPTestBedDlg][base64-decoding for driver's public key - modulus] failed");
return false;
}
if( !DoBase64DecodingAndSwap(cstrDriverPubKeyExponent, pbDriverPubKeyExponent, 4, &cbExponent,4))
{
dprintf("[COPPTestBedDlg][base64-decoding for driver's public key - exponent] failed");
return false;
}
dprintf("[COPPTestBedDlg][base64-decoding for driver's public key] OK");

//Convert Exponent from byte array -> DWORD
DWORD dwExponent;
memset((void *)(&dwExponent), 0, sizeof(DWORD));
memcpy((void *)(&dwExponent), pbDriverPubKeyExponent, sizeof(DWORD));
dprintf("[COPPTestBedDlg]dwExponent = 0x%.8X\n", dwExponent);

// Create a new key container to hold the key.
HCRYPTPROV hCSP = NULL;
bool bRet = ::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
) true : false;
if ( !bRet )
{
if(GetLastError() == NTE_EXISTS)
{
dprintf("[COPPTestBedDlg][App already exist a CSP , try to get existed CSP.]");
bRet = ::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
) true : false;
if(!bRet)
{
dprintf("[COPPTestBedDlg][Create a new key container to hold the key Failed ] Error [0x%.8X]",GetLastError());
return false;
}
}

}
dprintf("[COPPTestBedDlg][Create a key container to hold the key] OK");

// 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.
const DWORD RSA1 = 0x31415352; //Reference from http://msdn2.microsoft.com/en-us/library/aa387685.aspx
//Set to RSA1 (0x31415352) for public keys and to RSA2 (0x32415352) for private keys.
//Note The hexadecimal values are the ASCII encoding of RSA1 and RSA2.
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, pbDriverPubKeyModulus, cbModulus);

// Now import the key.
HCRYPTKEY hRSAKey; // Receives a handle to the key.
if( !CryptImportKey(hCSP, pBlob, cbKeyBlob, 0, 0, &hRSAKey))
{
dprintf("[COPPTestBedDlg][import the key Failed] Error");
if(CryptReleaseContext(hCSP,0))
dprintf("[COPPTestBedDlg]The handle (hCSP)has been released.\n");
return false;
}
dprintf("[COPPTestBedDlg][------End of Import the Drivers's Public Key------] OK");

delete[] pbDriverPubKeyModulus;
delete[] pbDriverPubKeyExponent;
//-----------------------------------------------------------------------------------------------------
//Initiating the COPP Session

//-----------------------------------------------------------------------------------------------------

//Generate a symmetric AES key
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.
bRet = 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.
) true : false;
if ( !bRet )
{
dprintf("[COPPTestBedDlg][Generate a symmetric AES key Failed] Error");
return FALSE;
}

//Exports AES Key
DWORD cbData = 0;
BYTE *pData = NULL;
// Get the size of the blob.
bRet = CryptExportKey(m_hAESKey, 0, PLAINTEXTKEYBLOB, 0, NULL, &cbData) true : false;
// Allocate the array and call again.
pData = new BYTE[cbData];
bRet = CryptExportKey(m_hAESKey, 0, PLAINTEXTKEYBLOB, 0, pData, &cbData) true : false;
//The data returned in pData has the following layout
//BLOBHEADER header
//DWORD cbSize
//BYTE key[]
DWORD pcbKey = *(DWORD*)(pData + sizeof(BLOBHEADER));
//chekcing size of COPP session key
if (pcbKey != 16)
{
// Wrong size! Should be 16 bytes (128 bits).
dprintf("[COPPTestBedDlg][COPP session key size wrong] Error");

}
//generate a 32-bit random number to use as the starting sequence for COPP status requests
UINT uStatusSeq = 0; // Status sequence number.
UINT uCommandSeq = 0; // Command sequence number.
CryptGenRandom(hCSP, sizeof(UINT), (BYTE *)(&uStatusSeq));
CryptGenRandom(hCSP, sizeof(UINT), (BYTE *)(&uCommandSeq));

AMCOPPSignature CoppSignTmp, CoppSig;
//clean buffer
ZeroMemory(&CoppSignTmp, sizeof(CoppSignTmp));
ZeroMemory(&CoppSig, sizeof(CoppSig));
//-----------------------------------------------------------------------------------------------------
// Copy the signature data into CoppSig. //-----------------------------------------------------------------------------------------------------
BYTE * ptCoppSig = &CoppSignTmp.Signature[0]; //get pointer of CoppSignTmp
//Copy Driver's Random Number to CoppSign
CopyMemory(ptCoppSig, &m_randomValue, sizeof(GUID));
ptCoppSig += sizeof(GUID);
//Copy AES Key to CoppSign
BYTE *pAesKey = (BYTE *)( pData + sizeof(BLOBHEADER) + sizeof(DWORD) );
CopyMemory(ptCoppSig, &pAesKey, pcbKey);
ptCoppSig += pcbKey;
//Copy Status Sequence Number to CoppSign
CopyMemory(ptCoppSig, &uStatusSeq, sizeof(UINT));
ptCoppSig += sizeof(UINT);
//Copy Command Sequence Number to CoppSign
CopyMemory(ptCoppSig, &uCommandSeq, sizeof(UINT));
//ptCoppSig += sizeof(UINT);
//delete[] pData;

// Encrypt the signature:
const DWORD RSA_PADDING = 11; // 11-byte padding.
DWORD cbDataOut = sizeof(AMCOPPSignature);
DWORD cbDataIn = cbDataOut - RSA_PADDING;

for(DWORD idx=0; idx<cbDataIn; idx++)
{
CoppSig.Signature[idx] = CoppSignTmp.Signature[cbDataIn-1-idx];
}

bRet = CryptEncrypt(
hRSAKey,
NULL, // No hash object.
TRUE, // Final block to encrypt.
0, // Reserved.
(BYTE *)&CoppSig.Signature[0], // COPP signature.
&cbDataIn,
cbDataOut
) true : false;
if ( !bRet )
{
dprintf("[COPPTestBedDlg][Encryption COPP Session Key Error] Error[0x%.8X]",GetLastError());
if (!CryptDestroyKey(m_hAESKey))
{
dprintf("[COPPTestBedDlg]Error during CryptDestroyKey.\n");
}
if(CryptReleaseContext(hCSP,0))
dprintf("[COPPTestBedDlg]The handle (hCSP)has been released.\n");
return false;
}

//-----------------------------------------------------------------------------------------------------
//Sending COPP Status Requests
//-----------------------------------------------------------------------------------------------------
hr = m_pCOPPDevice->SessionSequenceStart(&CoppSig);
if (SUCCEEDED(hr))
{
// Ready to send COPP commands and status requests.
dprintf("[COPPTestBedDlg][Ready to send COPP commands and status requestsr] ok");
AMCOPPStatusInput input;
AMCOPPStatusOutput output;

// Create a 128-bit random number.
GUID *pGuid = new GUID();
if (pGuid == NULL)
{
// Handle out-of-memory condition.
dprintf("[COPPTestBedDlg][Create a 128-bit random number Failed] Error");
return false;
}
CryptGenRandom(hCSP, sizeof(GUID), (BYTE*)pGuid);

// Copy the random number into the command structure.
memcpy(&input.rApp, pGuid, sizeof(GUID));

// Fill in the other data.
input.guidStatusRequestID = DXVA_COPPQueryProtectionType; // Request type.
input.dwSequence = uStatusSeq; // Status sequence number.
input.cbSizeData = 0 ; // No other data for this query.

// Send the request.
hr = m_pCOPPDevice->ProtectionStatus(&input, &output);

// Increment the sequence number each time.
++uStatusSeq;
return true;
}


Function DoBase64DecodingAndSwap()
Code Snippet

bool DoBase64DecodingAndSwap(CString in_cstrB64E, BYTE *out_pB64D,DWORD in_dwStrLen, DWORD *outcbLen, DWORD in_bufSize)
{
bool bRet = false;
DWORD dwCchString = in_dwStrLen, cbLen = 0, dwSkip = 0, dwFlags = 0;

bRet = CryptStringToBinary(
in_cstrB64E, // String that contains the Base64-encoded modulus.
dwCchString, // 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.
) true : false;

// Allocate a new buffer.
BYTE *pbBuffer = new BYTE [cbLen];

bRet = CryptStringToBinary(
in_cstrB64E,
dwCchString,
CRYPT_STRING_BASE64,
pbBuffer,
&cbLen,
&dwSkip,
&dwFlags
) true : false;
*(outcbLen) = cbLen;
//--------------------------------------------------
//Do swap
//--------------------------------------------------
//Padding the front of the array with 0,
//if the decoded byte array is less than buffer size
//--------------------------------------------------
for(DWORD idx=0; idx < cbLen; idx++)
{
out_pB64D[in_bufSize-1-idx] = pbBuffer[idx];
}
delete[] pbBuffer;
return bRet;
}