Поделиться через


Проверка подлинности сообщений

Проверка подлинности сообщений — это процесс, который позволяет приложениям и поставщикам служб проверять, что данные, передаваемые между ними, не были изменены. Windows Media диспетчер устройств позволяет приложениям и поставщикам служб выполнять проверку подлинности сообщений с помощью кодов проверки подлинности сообщений (MAC). Вот как работает проверка подлинности MAC:

Отправитель данных, как правило, поставщик услуг, передает один или несколько фрагментов данных с помощью односторонняя криптографическая функция, которая создает для всех данных одну сигнатуру MAC. Затем отправитель отправляет все подписанные фрагменты данных вместе с MAC получателю (обычно это приложение). Получатель передает данные через ту же криптографическую функцию для создания MAC-адреса и сравнивает их с отправленным mac-адресом. Если MAC-адрес совпадает, данные не были изменены.

Чтобы выполнить проверку подлинности MAC, приложению или поставщику услуг требуется ключ шифрования и соответствующий сертификат. Сведения о том, где их можно получить, см. в разделе Средства для разработки.

Ниже описано, как данные подписываются отправителем, а затем проверяются получателем. В Windows Media диспетчер устройств поставщик услуг использует класс CSecureChannelServer для создания mac, а приложение использует класс CSecureChannelClient. Оба класса предоставляют идентичные функции с одинаковыми параметрами, поэтому следующие действия применимы к обоим классам.

Отправитель (обычно поставщик услуг):

  1. Получение подписываемого данных.
  2. Создайте новый дескриптор MAC, вызвав MACInit.
  3. Добавьте часть данных для подписи в дескриптор, вызвав MACUpdate. Эта функция принимает ранее созданный дескриптор, а также часть данных, которые должны быть подписаны.
  4. Повторите шаг 3 с каждым дополнительным фрагментом данных, который необходимо подписать. Не имеет значения, в каком порядке данные добавляются в MAC.
  5. Скопируйте MAC-адрес из дескриптора в новый буфер байтов, вызвав MACFinal. Эта функция принимает дескриптор MAC и выделенный буфер и копирует MAC-адрес из дескриптора в указанный буфер.

При выполнении проверки подлинности MAC важно, чтобы и отправитель, и получатель помещают одни и те же данные в MAC-адрес. Для методов приложения, предоставляющих MAC, обычно все параметры включаются в значение MAC (за исключением самого MAC, конечно). Например, рассмотрим метод IWMDMOperation::TransferObjectData :

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

В этом методе MAC-адрес будет включать pData и pdwSize. Если не включить оба параметра, создаваемый MAC-адрес не будет соответствовать mac-адресу, переданном в abMac. Поставщик услуг должен обязательно поместить все необходимые параметры в методе приложения в значение MAC.

В следующем коде C++ показано создание MAC-адреса в реализации поставщика услуг IMDSPStorageGlobals::GetSerialNumber.

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++ показано, как приложение проверка mac-адреса, полученного в вызове IWMDMStorageGlobals::GetSerialNumber, чтобы убедиться, что серийный номер не был изменен при передаче.

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

Использование защищенных каналов с проверкой подлинности