Megosztás:


PlayReady beépülő modul androidos specifikációhoz

1. Bevezetés

Ez a specifikáció útmutatást nyújt az eredeti berendezés gyártóknak a PlayReady 4.0-alapú digitális jogok kezelésére szolgáló (DRM) beépülő modulok androidos implementálásához. További információért lásd: https://developer.android.com/reference/android/media/MediaDrm.html.

Ez a specifikáció tájékoztatást nyújt arról, hogy a beépülő modul API-k hogyan képeznek le PlayReady-hívásokra.

1.1. Változási előzmények

verzió Változás
2016. május Kezdeti verzió

2. Interfészek

A PlayReadyDrmPlugin biztosítja a DRM beépülő modul implementációját. A PlayReadyDrmPlugin feladata a DRM Manager API-k burkolása és a paraméterek megfelelő fordítása a felület által megadott formátumban, amelyen a PlayReady képes működni.

PlayReadyDRMPlugin interfész

A PlayReadyCryptoPlugin biztosítja a Crypto beépülő modul felületének implementálását, amely a minták visszafejtéséért felelős. Az OEM-nek biztosítania kell, hogy a visszafejtett minták soha ne hagyják el a megbízható végrehajtási környezetet (TEE).

PlayReadyCryptoPlugin felület

3. Művelet

Az alábbi lépések egy egyszerű lejátszási forgatókönyvet írnak le:

  1. Az alkalmazás létrehozza a MediaDrm objektumot, amely a PlayReadyDrmPlugin példányosítását eredményezi.

  2. Ezután hívja meg az openSessiont, amely a DRM-kezelő inicializálását eredményezi.

  3. Az alkalmazás ezután meghívja a getKeyRequest parancsot , és initData paraméterként átadja a tartalomból kinyert tartalomfejlécet. Emellett az alkalmazás a licencszerzési feladat egyéni adatait is átadhatja az opcionálisParameters kulcs-érték vektorban. A licenc megszerzésekor az egyedi adatokat ezután Drm_Content_SetProperty hívásként kell propagálni a DRM-kezelő számára.

  4. Ezen a ponton az alkalmazás végrehajthatja a (getKeyRequest / provideKeyResponse) parancsot, amely létrehozza a DRM Manager megfelelő (Drm_LicenseAcq_GenerateChallenge) / Drm_LicenseAcq_ProcessResponse) hívásait.

  5. Az alkalmazás ezután létrehozhat egy MediaCrypto-objektumot , amely létrehozza a PlayReadyCryptoPlugin felület egy példányát (burkoló DRM_DECRYPT_CONTEXT), amikor a Drm_Reader_Bind hívás visszatér.

  6. Ezután minden visszafejtési hívás a PlayReadyCryptoPlugin::d ecrypt metódust használja, amely egy leírót ad vissza a visszafejtett mintákhoz.

Egyszerű lejátszási folyamatábra

Egyszerű lejátszási rétegek

4. PlayReadyDRMPlugin

setPropertyString

Az alkalmazások ezzel a módszerrel adják át a paramétereket a PlayReadynek, amelyek egyébként nem lehetségesek a beépülő modul API-k jelenlegi kialakítása miatt.

  • DeviceStoreName – Az alkalmazásnak a munkamenet megnyitása előtt tulajdonságként kell beállítania az eszköztároló helyét. Ezután a PlayReady megkeresi a DeviceStoreName tulajdonságot, amikor inicializálja a DRM Managert az openSession hívásai során. Az eszköztároló elérési útjának elérhetőnek kell lennie az alkalmazásnak, például az alkalmazás privát adatkönyvtárának. A tulajdonságnak egy <olyan elérési útra/fájlnévre> kell mutatnia, amely a HDS-t tárolja.

  • LicenseChallengeCustomData – Az alkalmazás igény szerint beállíthatja ezt a tulajdonságot a getKeyRequest meghívása előtt, ahol a PlayReady megkeresi a tulajdonságot, és létrehoz egy licencszerzési kihívást, és belefoglalja az egyéni adatokat a kérelembe.

  • SecureStopCustomData – Az alkalmazás igény szerint beállíthatja ezt a tulajdonságot egy hívás előtt a Secure Stop kihívás létrehozásához. A PlayReady megkeresi a tulajdonságot, és összeállítja a Biztonságos leállítás kihívást, és belefoglalja az egyéni adatokat a kérésbe.

  • SelectKID – Azokban az esetekben, amikor az alkalmazás több memórián belüli licencet szerzett be egyetlen kötegben, megadhat egy base64 kódolású KID-t a kötéshez.

status_t PlayReadyDrmPlugin::setPropertyString(
String8 const &name,
String8 const &value)
{
  DRM_RESULT       dr = DRM_SUCCESS;
  Mutex::Autolock lock(&SessionManager::sLock);

  //
  // Store the Property in the name/value KeyedVector
  // for later usage.
  //
  ChkDR( mStringProperties.add(name, value));

  if (name == "SelectKID")
  {
    DRM_SUBSTRING dasstrKID = DRM_EMPTY_DRM_SUBSTRING;
    DRM_CONST_STRING dstrKID = DRM_EMPTY_DRM_STRING;
    DRM_BYTE rgbKID[CCH_BASE64_EQUIV(CCH_BASE64_EQUIV(DRM_ID_SIZE)] = {0};

    const char *pszhKID = value.string();

    // Convert the ASCII KID to UNICODE
    DRM_DSTR_FROM_PB(&dstrKID, rgbKID, sizeof(rgbKID));
    DRM_UTL_PromoteASCIItoUNICODE(pszhKID, &dasstrKID, (DRM_STRING *)&dstrKID);

    ChkDR(Drm_Content_SetProperty(
    &SessionManager::soAppContext, // DRM_APP_CONTEXT pointer
    DRM_CSP_SELECT_KID,
    dstrKID.pwszString,
    dstrKID.cchString * sizeof(DRM_WCHAR)));
  }

ErrorExit:
  return _DR_TO_STATUS(dr);
}

byteArrayTulajdonságBeállítása

Az alkalmazások ezzel a módszerrel adják át a paramétereket a PlayReadynek, amelyek egyébként nem lehetségesek a beépülő modul API-k jelenlegi kialakítása miatt.

  • ContentHeader – Az alkalmazásnak be kell állítania a tartalomfejlécet a beépülő modulon, mielőtt kriptoobjektumot próbál létrehozni. A tartalomfejléc a következő formátumok egyikében szerepelhet:

    • Bájttömb a PlayReady-objektum tartalmával.

    • Bájttömb a V2, V2.4, V4, V4.1, V4.2 fejlécek (unicode XML) tartalmával.

    • Széles karaktertömb, amely a 24 karakteres KeyID azonosítót adja meg.

  • SecureStopPublisherCert – Az alkalmazásnak egyszer be kell állítania a Közzétevő tanúsítványt a biztonságos leállítással kapcsolatos hívások előtt.

status_t PlayReadyDrmPlugin::setPropertyByteArray(
String8         const &name,
Vector<uint8_t> const &value)
{
  DRM_RESULT      dr = DRM_SUCCESS;
  Mutex::Autolock lock(&SessionManager::sLock);

  // Add the name/value pair to a KeyedVector
  mByteArrayProperties.add(name, value);

  // If the provided property is a content header
  // go ahead and set the property.
  if (name == "ContentHeader")
  {
    ChkDR(Drm_Content_SetProperty(
      &SessionManager::soAppContext, // DRM_APP_CONTEXT pointer
      DRM_CSP_AUTODETECT_HEADER,
      value.data(),
      value.size()));
  }

ErrorExit:
  return _DR_TO_STATUS(dr);
}

munkamenet megnyitása

Ennek a hívásnak az AppContext inicializálását kell eredményeznie a DRM Manager Drm_Initialize függvény meghívásával.

A hívás előtt az alkalmazásnak be kell állítania a PropertyStringet a beépülő modulon, hogy megadja a HDS tárolására használt eszköztároló elérési útját.

status_t PlayReadyDrmPlugin::openSession(Vector<luint8_t> &sessionId)
{
  DRM_RESULT          dr = DRM_SUCCESS;
  DRM_CONST_STRING    dstrDeviceStoreName = { 0 };
  String8             deviceStoreName;

  Mutex::Autolock lock(&SessionManager::sLock);

  ChkMem(mpbOpaqueBuffer =
    (DRM_BYTE*)Oem_MemAlloc(MINIMUM_APPCONTEXT_OPAQUE_BUFFER_SIZE));

  //
  // Application must call setPropertyString to set the DeviceStoreName
  // before opening the session.
  // So the call to getPropertyString with DeviceStoreName must return a value.
  //
  ChkDR(getPropertyString(String8("DeviceStoreName"), deviceStoreName));

  // Convert the deviceStoreName to a DRM_CONST_STRING */
  ChkDR(util_String8ToDrmConstString(deviceStoreName, &dstrDeviceStoreName));

  // Initialize AppContext
  ChkDR(Drm_Initialize(
    &SessionManager::soAppContext,
    NULL,             // pOEMContext : OEM can initialize and pass if needed.
    mpbOpaqueBuffer,
    MINIMUM_APPCONTEXT_OPAQUE_BUFFER_SIZE,
    &dstrDeviceStoreName));

ErrorExit:
  return _DR_TO_STATUS(dr);
}

munkamenet lezárása

A DRM-munkamenet lezárásakor meg kell hívnia a Drm_Uninitialize függvényt az AppContext felszabadításához.

status_t PlayReadyDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
{
  Mutex::Autolock lock(&SessionManager::sLock);

  // Clear the App Context
  Drm_Uninitialize(&SessionManager::soAppContext);
  SAFE_FREE(mpbOpaqueBuffer);
  return OK;
}

getKeyRequest

Ez a módszer egy licenckérelem-kihívást fog generálni.

ContentHeader – Az alkalmazás átadhatja a tartalomfejlécet az initData paraméterben, vagy a függvény meghívása előtt az alkalmazásnak be kell állítania a ContentHeader sztringtulajdonságot.

LicenseChallengeCustomData – Az alkalmazás a "LicenseChallengeCustomData" sztringkulccsal átadhatja a feladat egyéni adatait az opcionálisParameters paraméterben. Másik lehetőségként a metódus felveheti a LicenseChallengeCustomData értéket, ha az alkalmazás már beállította tulajdonságként.

A metódus feltölti a defaultUrl értéket, ha az elérhető a tartalomfejlécben, valamint előkészíti a licenckiszolgálónak küldendő kérést.

status_t PlayReadyDrmPlugin::getKeyRequest(
        Vector<uint8_t>                   const &sessionId,
        Vector<uint8_t>                   const &initData, s// ContentHeader
        String8                           const &mimeType,
        KeyType                                 keyType,
        KeyedVector<String8, String8="">  const &optionalParameters, // ChallengeCustomData
        Vector<uint8_t>                         &request,            // Output Challenge
        String8                                 &defaultUrl,         // Output URL
        KeyRequestType                         *keyRequestType)
{
  DRM_RESULT      dr = DRM_SUCCESS;
  DRM_BYTE       *pbContentProperty = NULL;
  DRM_DWORD       cbContentProperty = 0;
  DRM_CHAR       *pchCustomData = NULL;
  DRM_DWORD       cchCustomData = 0;
  DRM_CHAR       *pchSilentURL = NULL;
  DRM_DWORD       cchSilentURL = 0;
  DRM_BYTE       *pbChallenge = NULL;
  DRM_DWORD       cbChallenge = 0;
  DRM_BOOL        fHasUrl = FALSE;
  Vector<uint8_t> contentHeader;
  String8         customData;

  Mutex::Autolock lock(&SessionManager::sLock);

  if (getValue(optionalParameters, String8("LicenseChallengeCustomData"), customData) == OK)
  {
    //
    // The Application can pass the custom data as a part of the optionalParameters.
    // The key string would be "LicenseChallengeCustomData".
    // If it is provided. The plug-in should use it when generating the license challenge.
    //
    pchCustomData = customData.data();
    cchCustomData = customData.size();
  }
  else if (getPropertyString(String8("LicenseChallengeCustomData"), customData) == OK)
  {
    //
    // Alternatively the Application could have provided customData for this operation
    // via a previous call to setPropertyString.
    // Try to retrieve it if available. Otherwise, skip without failing.
    //
    pchCustomData = customData.data();
    cchCustomData = customData.size();
  }

  //
  // The Application could choose to pass the content header as the initData
  // If the initData is passed, use it to call Drm_Content_SetProperty
  //
  if (value.size() != 0)
  {
    ChkDR(Drm_Content_SetProperty(
      &SessionManager::soAppContext, // DRM_APP_CONTEXT pointer
      DRM_CSP_AUTODETECT_HEADER,
      value.data(),
      value.size()));
  }

  //
  // First, try to retrieve the URL.
  //
  dr = Drm_LicenseAcq_GenerateChallenge(
    &SessionManager::soAppContext,
    NULL,
    0,
    NULL,
    pchCustomData,
    cchCustomData,
    pchSilentURL,
    &cchSilentURL,    // Attempt to get the URL size.
    NULL,
    NULL,
    pbChallenge,
    &cbChallenge);
  if (dr == DRM_E_BUFFERTOOSMALL)oi
  {
    fHasUrl = TRUE;

    // ContentHeader has a URL. Allocate buffer for it.
    ChkMem(pchSilentURL = (DRM_CHAR*)Oem_MemAlloc(cchSilentURL));
  }
  else if (dr == DRM_E_NO_URL)
  {
    // No Url in the content header, no need to fail.
    // The Application can get the URL independently.
    dr = DRM_SUCCESS;
  }
  else
  {
    ChkDR(dr);
  }

  //
  // Second, get the challenge size.
  //
  dr = Drm_LicenseAcq_GenerateChallenge(
    poAppContext,
    NULL,
    0,
    NULL,
    pchCustomData,
    cchCustomData,
    pchSilentURL,
    fHasUrl ? &cchSilentURL : NULL,
    NULL,
    NULL,
    pbChallenge,
    &cbChallenge);
  if (dr == DRM_E_BUFFERTOOSMALL)
  {
    // Allocate buffer that is sufficient
    // to store the license acquisition challenge.
    ChkMem(pbChallenge = (DRM_BYTE*)Oem_MemAlloc(cbChallenge));
  }
  else
  {
    ChkDR(dr);
  }

  //
  // Finally, generate challenge.
  //
  ChkDR(Drm_LicenseAcq_GenerateChallenge(
    &SessionManager::soAppContext,
    NULL,
    0,
    NULL,
    pchCustomData,
    cchCustomData,
    pchSilentURL,
    fHasUrl ? &cchSilentURL : NULL,
    NULL,
    NULL,
    pbChallenge,
    &cbChallenge));

  //
  // Write the License Challenge to the request buffer.
  //
  request.appendArray(pbChallenge, cbChallenge);

  if (fHasUrl)
  {
    defaultUrl.appendArray(pchSilentURL, cchSilentURL);
  }

ErrorExit:
  SAFE_OEM_FREE(pbChallenge);
  SAFE_OEM_FREE(pchSilentURL);
  return _DR_TO_STATUS(dr);
}

adja meg a kulcsválaszt

Miután az alkalmazás elküldött egy KeyRequest (LicenseChallenge) a licenckiszolgálónak, tovább kell adnia a KeyResponse (LicenseResponse)-et a beépülő modulnak.

status_t PlayReadyDrmPlugin::provideKeyResponse(
      Vector<uint8_t>        const &sessionId,
      Vector<uint8_t>        const &response,
      Vector<uint8_t>        &keySetId)
{
  DRM_RESULT           dr = DRM_SUCCESS;
  DRM_LICENSE_RESPONSE oLicenseResponse = { 0 };
  DRM_DWORD            idx = 0;
  DRM_BOOL             fExceedMaxLic = FALSE;
  Mutex::Autolock lock(&SessionManager::sLock);

  //
  // Process the response.
  //
  dr = Drm_LicenseAcq_ProcessResponse(
            &SessionManager::soAppContext,
            0,
            NULL,
            NULL,
            response.data(),
            response.size(),
            &oLicenseResponse);
  if(dr ==  DRM_E_LICACQ_TOO_MANY_LICENSES)
  {
    //
    // Received more licenses than DRM_MAX_LICENSE_ACK.
    // Allocate space for that.
    //

    oLicenseResponse.m_cMaxAcks = oLicenseResponse.m_cAcks;
    ChkMem(oLicenseResponse.m_pAcks=
    (DRM_BYTE*)Oem_MemAlloc(sizeof(DRM_LICENSE_ACK)
    * oLicenseResponse.m_cAcks ));
    ChkDR(Drm_LicenseAcq_ProcessResponse(
            &SessionManager::soAppContext,
            0,
            NULL,
            NULL,
            response.data(),
            response.size(),
            &oLicenseResponse);

    fExceedMaxLic = TRUE;
  }
  ChkDR(dr);

  //
  // Ensure that all licenses were processed successfully.
  //

  if(fExceedMaxLic)
  {
    for (idx = 0; idx < oLicenseResponse.m_cAcks; idx++)
    {
      ChkDR(oLicenseResponse.m_pAcks[idx].m_dwResult);
    }
  }
  else
  {
    for (idx = 0; idx < oLicenseResponse.m_cAcks; idx++)
    {
      ChkDR(oLicenseResponse.m_rgoAcks[idx].m_dwResult);
    }
  }

ErrorExit:
  SAFE_FREE(oLicenseResponse.m_pAcks);
  return _DR_TO_STATUS(dr);
}

getSecureStop(s)

Az alkalmazások meghívhatják a getSecureStop metódust, hogy biztonságos leállítási kihívást generáljanak a megadott biztonságos leállítási azonosítóhoz. Alternatívaként az alkalmazás meghívhatja a getSecureStops függvényt, hogy kihívást generáljon az összes meglévő biztonságos megállítási munkamenethez.

A biztonságos leállítási feladat létrehozása előtt az alkalmazásnak meg kell adnia a közzétevői tanúsítványt a setPropertyByteArray meghívásával és a SecureStopPublisherCert átadásával.

Az alkalmazás opcionálisan a SecureStopCustomData-t is biztosíthatja a biztonságos leállítási feladat részeként.

A biztonságos leállítási feladat létrehozása után az alkalmazásnak el kell küldenie a kiszolgálónak, és vissza kell adnia a biztonsági leállítási választ a releaseSecureStops metódusra.

DRM_RESULT PlayReadyDrmPlugin::_getSecureStop(
DRM_ID       *pIdSession,
DRM_BYTE    **ppbChallenge,
DRM_DWORD    *pcbChallenge)
{
  DRM_RESULT       dr = DRM_SUCCESS;
  DRM_CHAR        *pchCustomData = NULL;
  DRM_DWORD        cchCustomData = 0;
  String8          customData;
  Vector<uint8_t>  publisherCert;

  if (getPropertyString("SecureStopCustomData", customData) == OK)
  {
    // SecureStop CustomData is optional
    pchCustomData = customData.data();
    cchCustomData = customData.size();
  }

  // Application must set SecureStopPublisherCert before calling getSecureStop(s)
  ChkDR(getPropertyByteArray("SecureStopPublisherCert", publisherCert));

  ChkDR(Drm_SecureStop_GenerateChallenge(
        &SessionManager::soAppContext,
        pIdSession,
        publisherCert.size(),
        publisherCert.data(),
        cchCustomData,
        pchCustomData,
        pcbChallenge,
        ppbChallenge));
ErrorExit:
  return dr;
}

status_t PlayReadyDrmPlugin::getSecureStop(
        Vector<uint8_t>          const &ssid,           // In
        Vector<uint8_t>                &secureStop)     // Out
{
  DRM_RESULT dr = DRM_SUCCESS;
  DRM_ID     idSecureStop = { 0 };
  DRM_BYTE  *pbChallenge = NULL;
  DRM_DWORD  cbChallenge = 0;
  Mutex::Autolock lock(&SessionManager::sLock);

  ChkArg(ssid.size() == sizeof(DRM_ID));
  memcpy(&idSecureStop, ssid.data(), sizeof(DRM_ID));

  ChkDR(_getSecureStop(
            &idSecureStop,
            &pbChallenge,
            &cbChallenge));

  secureStop.appendArray(pbChallenge, cbChallenge);
ErrorExit:
  SAFE_FREE(pbChallenge);
  return _DR_TO_STATUS(dr);
}

status_t PlayReadyDrmPlugin::getSecureStops(
            List<Vector<uint8_t> > &secureStops)
{
  DRM_RESULT dr = DRM_SUCCESS;
  DRM_BYTE  *pbChallenge = NULL;
  DRM_DWORD  cbChallenge = 0;
  Vector<uint8_t> secureStopChallenge;
  Mutex::Autolock lock(&SessionManager::sLock);

  ChkDR(_getSecureStop(
    NULL,
    &pbChallenge,
    &cbChallenge));

  secureStopChallenge.appendArray(pbChallenge, cbChallenge);
  secureStops.push_back(secureStopChallenge);
ErrorExit:
  SAFE_FREE(pbChallenge);
  return _DR_TO_STATUS(dr);
}

releaseSecureStops

Miután az alkalmazás megkapta a biztonságos leállítási választ a kiszolgálótól, az üzenetet le kell adni a beépülő modulnak, hogy eltávolítsa a biztonságos leállítási információkat a tárolóból.

status_t PlayReadyDrmPlugin::releaseSecureStops(
    Vector<uint8_t>      const &ssRelease)
{
  DRM_RESULT dr = DRM_SUCCESS;
  DRM_CHAR    *pchCustomData = NULL;
  DRM_DWORD    cchCustomData = 0;
  Vector<uint8_t> publisherCert;
  Mutex::Autolock lock(&SessionManager::sLock);

  // Application must set SecureStopPublisherCert before calling
  // releaseSecureStops
  ChkDR(getPropertyByteArray("SecureStopPublisherCert", publisherCert));

  ChkDR(Drm_SecureStop_ProcessResponse(
    &SessionManager::soAppContext,
    NULL,
    publisherCert.size(),
    publisherCert.data(),
    ssRelease.size(),
    ssRelease.data(),
    &cchCustomData,
    &pchCustomData));
ErrorExit:
  SAFE_FREE(pchCustomData);
  return _DR_TO_STATUS(dr);
}

Nem támogatott API-k (nincs művelet)

Az API-k alábbi listája nem rendelkezik megfelelő művelettel a PlayReadyben, és nem szükséges a támogatott forgatókönyvek sikeres végrehajtásához.

lekérdezniKulcsállapotot

status_t PlayReadyDrmPlugin::queryKeyStatus(
        Vector<uint8_t>                  const &sessionId,
        KeyedVector<String8, String8="">       &infoMap) const
{ return _DR_TO_STATUS(DRM_E_NOTIMPL); }

getProvisionRequest

A PlayReady csak Android-eszközökön támogatja a helyi kiépítést.

status_t PlayReadyDrmPlugin::getProvisionRequest(
        String8 const         &certType,
        String8 const         &certAuthority,
        Vector<uint8_t>       &request,
        String8               &defaultUrl) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

provideProvisionResponse

A PlayReady csak Android-eszközökön támogatja a helyi kiépítést.

status_t PlayReadyDrmPlugin::provideProvisionResponse(
        Vector<uint8_t>          const &response,
        Vector<uint8_t>                &certificate,
        Vector<uint8_t>                &wrappedKey) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

unprovisionDevice

A PlayReady csak Android-eszközökön támogatja a helyi kiépítést.

status_t PlayReadyDrmPlugin::unprovisionDevice() { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

titkosítási algoritmus beállítása

A PlayReady nem titkosítja/fejti vissza a tetszőleges adatokat.

status_t PlayReadyDrmPlugin::setCipherAlgorithm(
        Vector<uint8_t>       const &sessionId,
        String8               const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

MacAlgoritmusBeállítás

A PlayReady nem ír alá/ellenőriz tetszőleges adatokat.

status_t PlayReadyDrmPlugin::setMacAlgorithm(
        Vector<uint8_t>       const &sessionId,
        String8               const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

titkosít

A PlayReady nem titkosítja/fejti vissza a tetszőleges adatokat.

status_t PlayReadyDrmPlugin::encrypt(
        Vector<uint8_t> const &sessionId,
        Vector<uint8_t> const &keyId,
        Vector<uint8_t> const &input,
        Vector<uint8_t> const &iv,
        Vector<uint8_t>       &output) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

visszafejt

A PlayReady nem titkosítja/fejti vissza a tetszőleges adatokat.

status_t PlayReadyDrmPlugin::decrypt(
        Vector<uint8_t> const &sessionId,
        Vector<uint8_t> const &keyId,
        Vector<uint8_t> const &input,
        Vector<uint8_t> const &iv,
        Vector<uint8_t>       &output) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

jel

A PlayReady nem ír alá/ellenőriz tetszőleges adatokat.

status_t PlayReadyDrmPlugin::sign(
        Vector<uint8_t> const &sessionId,
        Vector<uint8_t> const &keyId,
        Vector<uint8_t> const &message,
        Vector<uint8_t>       &signature) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

ellenőriz

A PlayReady nem ír alá/ellenőriz tetszőleges adatokat.

status_t PlayReadyDrmPlugin::verify(
        Vector<uint8_t> const &sessionId,
        Vector<uint8_t> const &keyId,
        Vector<uint8_t> const &message,
        Vector<uint8_t> const &signature,
        bool                  &match) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

signRSA

A PlayReady nem ír alá/ellenőriz tetszőleges adatokat.

status_t PlayReadyDrmPlugin::signRSA(
        Vector<uint8_t> const &sessionId,
        String8         const &algorithm,
        Vector<uint8_t> const &message,
        Vector<uint8_t> const &wrappedKey,
        Vector<uint8_t>       &signature) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }

5. PlayReadyCryptoPlugin

PlayReadyCryptoPlugin

PlayReadyCryptoPlugin-objektum létrehozásához szükséges konstruktor.

PlayReadyCryptoPlugin::PlayReadyCryptoPlugin(
      const uint8_t sessionId[16],
      const void *  data,
      size_t        size);
{
  DRM_RESULT         dr = DRM_SUCCESS;
  Mutex::Autolock lock(&SessionManager::sLock);

  ChkDR(Drm_Reader_Bind(
         &SessionManager::soAppContext,
         NULL,
         0,
         NULL,
         NULL,
         &moDecryptContext));

ErrorExit:
  // Cache the Bind Result and check for it on the first call to decrypt.
  mdrBindResult = dr;
}

biztonságos dekóderkomponens szükséges

A PlayReady titkosított tartalmainak feldolgozásához biztonságos dekóder-összetevőre van szükség.

bool PlayReadyCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
{
  // Must always return true for PlayReady Content.
  return true;
}

visszafejt

A MediaCodec által elindított visszafejtés.

Mivel a visszafejtési módszer nem ad egyértelmű mintákat, hanem egy OEM-specifikus leírót, az OEM-nek biztosítania kell, hogy a MediaCodec megfelelően tudjon működni ezen a leírón.

ssize_t PlayReadyCryptoPlugin::decrypt(
      bool                 secure,
      const uint8_t        key[16],
      const uint8_t        iv[16],
      Mode                 mode,
      const void          *srcPtr,
      const SubSample     *subSamples,
      size_t               numSubSamples,
      void                *dstPtr,
      AString             *errorDetailMsg)
{
  DRM_RESULT        dr = DRM_SUCCESS;
  DRM_DWORD         idx = 0;
  DRM_DWORD         idxSubSample = 0;
  DRM_DWORD         cbEncryptedContent = 0;
  DRM_UINT64        ui64InitializationVector;
  DRM_DWORD        *pdwEncryptedRegionMappings = NULL;
  DRM_DWORD         cbOpaqueClearContentHandle = 0;
  Mutex::Autolock lock(mLock);

  // Only AES_CTR is supported
  ChkBOOL(mode == kMode_AES_CTR, DRM_E_UNSUPPORTED_ALGORITHM);
  ChkArg(secure == TRUE);

  // Ensure that bind returned successfully in the constructor.
  ChkDR( mdrBindResult );

  // Allocate a list for the region mapping.
  ChkMem(pdwEncryptedRegionMappings
        = Oem_MemAlloc(sizeof(DRM_DWORD)* numSubSamples * 2));

  // Fill the region mappings list with the information
  // from the subSamples.
  for (idxSubSample = 0; idxSubSample < numSubSamples; idxSubSample++)
  {
    pdwEncryptedRegionMappings[idx++]
          = subSamples[idxSubSample].mNumBytesOfClearData;
    pdwEncryptedRegionMappings[idx++]
          = subSamples[idxSubSample].mNumBytesOfEncryptedData;

    // Calculate the total number of bytes
    cbEncryptedContent +=
          (subSamples[idxSubSample].mNumBytesOfClearData
          + subSamples[idxSubSample].mNumBytesOfEncryptedData);
  }

  // Convert the IV from a uint8 array to a DRM_UINT64
  // Endianess should be taken into consideration.
  ChkStatus(initializeIV(iv, &ui64InitializationVector));

  // Decrypt
  ChkDR(Drm_Reader_DecryptOpaque(
      &moDecryptContext,
      numSubSamples * 2,
      pdwEncryptedRegionMappings,
      ui64InitializationVector,
      cbEncryptedContent,
      srcPtr,
      &cbOpaqueClearContentHandle,
      &dstPtr);

ErrorExit:
  // Free the Region mappings list.
  SAFE_FREE(pdwEncryptedRegionMappings);

  if (DRM_FAILED(dr))
  {
    // If an error occurs, fill the errorMessage
    // then return the DRM_RESULT
    SetErrorDetails(errorDetailMsg, dr);
    return _DR_TO_STATUS(dr);
  }
  // In case of success, return the size of the handle pointing
  // to the clear content.
  return cbOpaqueClearContentHandle;
}

~PlayReadyCryptoPlugin

A titkosítási beépülő modul destruktorának be kell zárnia a visszafejtési környezetet.

~PlayReadyCryptoPlugin::PlayReadyCryptoPlugin()
{
  Mutex::Autolock lock(mLock);
  Drm_Reader_Close(&moDecryptContext);
}

6. PlayReadyDrmFactory és PlayReadyCryptoFactory

A PlayReadyDrmFactory és a PlayReadyCryptoFactory interfészek implementálása szükséges mind a PlayReadyDrmPlugin , mind a PlayReadyCryptoPlugin példányainak létrehozásához.

Mindkét gyári osztálynak jeleznie kell a hívóknak, hogy támogatják a PlayReady által védett tartalmakat használó objektumok létrehozását az isCryptoSchemeSupported API megfelelő implementálásával.


const uint8_t playready_uuid[16] =
    {0x79, 0xf0, 0x04, 0x9a, 0x40, 0x98, 0x86, 0x42, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95};

bool isCryptoSchemeSupported(const uint8_t uuid[16])
{
  return (!memcmp(uuid, playready_uuid, sizeof(playready_uuid)));
}

7. SessionManager

A DRM_APP_CONTEXT tárolásához és a PlayReadyDrmPlugin és a PlayReadyCryptoPlugin közötti megosztás engedélyezéséhez egy egyszeri munkamenet-kezelőt kell implementálnia.

Más tervek is elfogadhatók, amelyek ugyanazt a célt érik el.

SessionManager
statikus DRM_APP_CONTEXT soAppContext
statikus Mutex sLock