共用方式為


訊息驗證

訊息驗證是一個程式,可讓應用程式和服務提供者驗證它們之間傳遞的數據尚未遭到竄改。 Windows 媒體設備管理器可讓應用程式和服務提供者使用訊息驗證碼(MAC)來執行訊息驗證。 以下是 MAC 驗證的運作方式:

數據傳送者通常是服務提供者,會透過單向密碼編譯函式傳遞一或多個數據片段,以產生所有數據的單一簽章 MAC。 然後傳送者會將所有已簽署的數據片段連同 MAC 一起傳送給接收者(通常是應用程式)。 接收者會透過相同的密碼編譯函式傳遞數據,以產生MAC,並將其與已傳送的MAC進行比較。 如果 MAC 相符,則數據尚未修改。

若要執行 MAC 驗證,應用程式或服務提供者需要加密金鑰和相符的憑證。 如需取得這些位置的資訊,請參閱 Tools for Development

下列步驟說明傳送者如何簽署數據,稍後由接收者檢查。 在 Windows 媒體設備管理器中,服務提供者會使用 CSecureChannelServer 類別來產生 MAC,而應用程式會使用 CSecureChannelClient 類別。 這兩個類別都使用相同的參數提供相同的函式,因此下列步驟適用於這兩個類別。

寄件者 (通常是服務提供者):

  1. 取得要簽署的數據。
  2. 呼叫 MACInit來建立新的 MAC 句柄。
  3. 呼叫 MACUpdate,以新增要簽署至句柄的數據片段。 此函式會接受先前建立的句柄,以及必須簽署的數據片段。
  4. 重複步驟 3,其中包含必須簽署的每個額外數據片段。 將數據新增至 MAC 的順序並不重要。
  5. 呼叫 MACFinal,將 MAC 從句柄複製到新的位元組緩衝區。 此函式會接受 MAC 句柄和您設定的緩衝區,並將 MAC 從句柄複製到提供的緩衝區。

執行 MAC 驗證時,傳送者和接收者必須同時將相同的數據放入 MAC 中。 對於提供 MAC 的應用程式方法,通常所有參數都會包含在 MAC 值中(當然,MAC 本身除外)。 例如,請考慮 IWMDMOperation::TransferObjectData 方法:

HRESULT TransferObjectData(BYTE* pData, DWORD* pdwSize, BYTE[WMDM_MAC_LENGTH] abMac);

在這裡方法中,MAC 會包含 pDatapdwSize。 如果您不包含這兩個參數,您建立的 MAC 將不會符合傳遞至 abMac的 MAC。 服務提供者必須確定將應用程式方法中所有必要的參數放入 MAC 值。

下列C++程序代碼示範如何在服務提供者實作 IMDSPStorageGlobals::GetSerialNumber 中建立 MAC。

HRESULT CMyDevice::GetSerialNumber(
    PWMDMID pSerialNumber, 
    BYTE abMac[WMDM_MAC_LENGTH])
{
    HRESULT hr;

    // g_pSecureChannelServer is a global CSecureChannelServer object
    // created earlier.

    // Standard check that the CSecureChannelServer was authenticated previously.
    if ( !(g_pSecureChannelServer->fIsAuthenticated()) )
    {
        return WMDM_E_NOTCERTIFIED;
    }

    // Call a helper function to get the device serial number.
    hr = UtilGetSerialNumber(m_wcsName, pSerialNumber, TRUE);
    if(hr == HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED))
    {
        hr = WMDM_E_NOTSUPPORTED;
    }

    if(hr == S_OK)
    {
        // Create the MAC handle.
        HMAC hMAC;
        hr = g_pSecureChannelServer->MACInit(&hMAC);
        if(FAILED(hr))
            return hr;

        // Add the serial number to the MAC.
        g_pSecureChannelServer->MACUpdate(hMAC, (BYTE*)(pSerialNumber), sizeof(WMDMID));
        if(FAILED(hr))
            return hr;

        // Get the created MAC value from the handle.
        g_pSecureChannelServer->MACFinal(hMAC, abMac);
        if(FAILED(hr))
            return hr;
    }

    return hr;
}

接收者 (通常是應用程式):

如果接收者尚未實作 IWMDMOperation3 介面,它應該執行與傳送者相同的步驟,然後比較兩個 MAC 值。 下列C++程式代碼範例示範應用程式如何檢查在呼叫 IWMDMStorageGlobals::GetSerialNumber 中收到的 MAC,以確保序號不會在傳輸中遭到竄改。

//
// Get and verify the serial number.
//
WMDMID serialNumber;
BYTE receivedMAC[WMDM_MAC_LENGTH];
hr = pIWMDMDevice->GetSerialNumber(&serialNumber, receivedMAC);

// Check the MAC to guarantee the serial number has not been tampered with.
if (hr == S_OK)
{
    // Initialize a MAC handle, 
    // add all parameters to the MAC,
    // and retrieve the calculated MAC value.
    // m_pSAC is a global CSecureChannelClient object created earlier.
    HMAC hMAC;
    BYTE calculatedMAC[WMDM_MAC_LENGTH];
    hr = m_pSAC->MACInit(&hMAC);
    if(FAILED(hr))
        return hr;

    hr = m_pSAC->MACUpdate(hMAC, (BYTE*)(&serialNumber), sizeof(serialNumber));
    if(FAILED(hr))
        return hr;

    hr = m_pSAC->MACFinal(hMAC, (BYTE*)calculatedMAC);
    if(FAILED(hr))
        return hr;

    // If the two MAC values match, the MAC is authentic. 
    if (memcmp(calculatedMAC, receivedMAC, sizeof(calculatedMAC)) == 0)
    {
        // The MAC is authentic; print the serial number.
        CHAR* serialNumberBuffer = 
            new CHAR[serialNumber.SerialNumberLength + 1];
        ZeroMemory(serialNumberBuffer, 
            (serialNumber.SerialNumberLength + 1) * sizeof(CHAR));
        memcpy(serialNumberBuffer, serialNumber.pID, 
            serialNumber.SerialNumberLength * sizeof(CHAR));
        // TODO: Display the serial number.
        delete serialNumberBuffer;
    }
    else
    {
        // TODO: Display a message indicating that the serial number MAC 
        // does not match.
    }
}

使用安全驗證通道