メッセージ認証

メッセージ認証は、アプリケーションとサービス プロバイダー間で渡されたデータが改ざんされていないことを確認できるようにするプロセスです。 Windows Media デバイス マネージャーを使用すると、アプリケーションとサービス プロバイダーは、メッセージ認証コード (MAC) を使用してメッセージ認証を実行できます。 MAC 認証のしくみを次に示します。

データ送信者 (通常はサービス プロバイダー) は、すべてのデータに対して 1 つの署名 (MAC) を生成する一方向暗号化関数を介して 1 つ以上のデータを渡します。 その後、送信者は、署名されたすべてのデータを 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 インターフェイスを実装していない場合は、送信側と同じ手順を実行してから、2 つの 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.
    }
}

セキュリティで保護された認証済みチャネルの使用