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


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

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

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

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

Ниже описано, как данные подписаны отправителем, а затем проверяются получателем. В диспетчере устройств Windows Media поставщик служб использует класс CSecureChannelServer для создания macs, а приложение использует класс 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.
    }
}

использование защищенных каналов