다음을 통해 공유


메시지 인증

메시지 인증은 애플리케이션과 서비스 공급자가 애플리케이션 간에 전달된 데이터가 변조되지 않았는지 확인할 수 있는 프로세스입니다. Windows Media 장치 관리자 사용하면 애플리케이션 및 서비스 공급자가 MAC(메시지 인증 코드)을 사용하여 메시지 인증을 수행할 수 있습니다. MAC 인증의 작동 방식은 다음과 같습니다.

일반적으로 서비스 공급자인 데이터 보낸 사람은 모든 데이터에 대해 단일 서명인 MAC을 생성하는 단방향 암호화 함수를 통해 하나 이상의 데이터를 전달합니다. 그런 다음 보낸 사람은 MAC과 함께 서명된 모든 데이터를 수신자(일반적으로 애플리케이션)로 보냅니다. 수신기는 동일한 암호화 함수를 통해 데이터를 전달하여 MAC을 생성하고 전송된 MAC과 비교합니다. MAC이 일치하는 경우 데이터가 수정되지 않았습니다.

MAC 인증을 수행하려면 애플리케이션 또는 서비스 공급자에 암호화 키와 일치하는 인증서가 필요합니다. 이러한 정보를 얻을 수 있는 위치에 대한 자세한 내용은 개발 도구를 참조하세요.

다음 단계에서는 보낸 사람에서 데이터를 서명하고 나중에 수신자가 확인하는 방법을 설명합니다. Windows Media 장치 관리자 서비스 공급자는 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.
    }
}

보안 인증 채널 사용