Nachrichtenauthentifizierung

Die Nachrichtenauthentifizierung ist ein Prozess, mit dem Anwendungen und Dienstanbieter überprüfen können, ob zwischen ihnen übergebene Daten nicht manipuliert wurden. Windows Media Geräte-Manager ermöglicht Anwendungen und Dienstanbietern die Nachrichtenauthentifizierung mithilfe von Nachrichtenauthentifizierungscodes (Message Authentication Codes, MACs). So funktioniert die MAC-Authentifizierung:

Der Datensender(in der Regel der Dienstanbieter) übergibt ein oder mehrere Datenteile über eine einseitige kryptografische Funktion, die eine einzelne Signatur, den MAC, für alle Daten erzeugt. Der Absender sendet dann alle signierten Daten zusammen mit dem MAC an den Empfänger (in der Regel die Anwendung). Der Empfänger übergibt die Daten über dieselbe kryptografische Funktion, um einen MAC zu generieren, und vergleicht sie mit dem gesendeten MAC. Wenn der MAC übereinstimmt, wurden die Daten nicht geändert.

Zum Ausführen der MAC-Authentifizierung benötigt die Anwendung oder der Dienstanbieter einen Verschlüsselungsschlüssel und ein entsprechendes Zertifikat. Informationen dazu, wo Sie diese abrufen können, finden Sie unter Tools für die Entwicklung.

In den folgenden Schritten wird beschrieben, wie Daten vom Absender signiert und später vom Empfänger überprüft werden. In Windows Media Geräte-Manager verwendet der Dienstanbieter die CSecureChannelServer-Klasse, um MACs zu generieren, und die Anwendung verwendet die CSecureChannelClient-Klasse. Beide Klassen stellen identische Funktionen mit identischen Parametern bereit, sodass die folgenden Schritte für beide Klassen gelten.

Der Absender (in der Regel der Dienstanbieter):

  1. Abrufen der zu signierten Daten.
  2. Erstellen Sie ein neues MAC-Handle, indem Sie MACInit aufrufen.
  3. Fügen Sie dem Handle durch Aufrufen von MACUpdate ein Datenteil hinzu, das signiert werden soll. Diese Funktion akzeptiert das zuvor erstellte Handle sowie ein Datenteil, das signiert werden muss.
  4. Wiederholen Sie Schritt 3 mit jedem zusätzlichen Datenteil, der signiert werden muss. Es spielt keine Rolle, in welcher Reihenfolge Daten dem MAC hinzugefügt werden.
  5. Kopieren Sie den MAC aus dem Handle in einen neuen Bytepuffer, indem Sie MACFinal aufrufen. Diese Funktion akzeptiert das MAC-Handle und einen Puffer, den Sie zuordnen, und kopiert den MAC aus dem Handle in den bereitgestellten Puffer.

Beim Ausführen der MAC-Authentifizierung ist es wichtig, dass sowohl der Absender als auch der Empfänger die gleichen Daten auf dem MAC ablegt. Für die Anwendungsmethoden, die einen MAC bereitstellen, sind in der Regel alle Parameter im MAC-Wert enthalten (natürlich mit Ausnahme des MAC selbst). Betrachten Sie beispielsweise die IWMDMOperation::TransferObjectData-Methode:

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

In dieser Methode würde der MAC pData und pdwSize enthalten. Wenn Sie nicht beide Parameter einschließen, stimmt der von Ihnen erstellte MAC nicht mit dem MAC überein, der an abMac übergeben wurde. Ein Dienstanbieter muss sicherstellen, dass alle erforderlichen Parameter in der Anwendungsmethode in den MAC-Wert aufgenommen werden.

Der folgende C++-Code veranschaulicht das Erstellen eines MAC in der Implementierung von IMDSPStorageGlobals::GetSerialNumbereines Dienstanbieters.

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

Der Empfänger (in der Regel die Anwendung):

Wenn der Empfänger die IWMDMOperation3-Schnittstelle nicht implementiert hat, sollte er die gleichen Schritte wie der Absender ausführen und dann die beiden MAC-Werte vergleichen. Das folgende C++-Codebeispiel zeigt, wie eine Anwendung den MAC überprüfen würde, der in einem Aufruf von IWMDMStorageGlobals::GetSerialNumber empfangen wurde, um sicherzustellen, dass die Seriennummer während der Übertragung nicht manipuliert wurde.

//
// 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.
    }
}

Verwenden von sicheren authentifizierten Kanälen