Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
1. Einführung
Diese Spezifikation enthält Anleitungen für OEMs zum Implementieren von PlayReady 4.0-basierten DRM-Plug-Ins (Digital Rights Management) unter Android. Referenz finden Sie unter https://developer.android.com/reference/android/media/MediaDrm.html.
Diese Spezifikation enthält Informationen zur Zuordnung der Plug-In-APIs zu PlayReady-Aufrufen.
1.1. Änderungsverlauf
| Version | Veränderung |
|---|---|
| Mai 2016 | Ursprüngliche Version |
2. Schnittstellen
PlayReadyDrmPlugin stellt die Implementierung für die DRM-Plug-In-Schnittstelle bereit. PlayReadyDrmPlugin ist für das Umschließen der DRM-Manager-APIs verantwortlich und führt die richtige Übersetzung für die Parameter aus, die von der Schnittstelle in ein Format angegeben werden, auf dem PlayReady ausgeführt werden kann.

PlayReadyCryptoPlugin stellt die Implementierung für die Crypto-Plug-In-Schnittstelle bereit, die für die Entschlüsselung der Beispiele verantwortlich ist. Der OEM muss sicherstellen, dass die entschlüsselten Beispiele niemals die vertrauenswürdige Ausführungsumgebung (TEE) verlassen.

3. Vorgang
Die folgenden Schritte beschreiben ein einfaches Wiedergabeszenario:
Die App erstellt das MediaDrm-Objekt , das zur Instanziierung von PlayReadyDrmPlugin führt.
Rufen Sie dann openSession auf, was zur Initialisierung des DRM-Managers führt.
Die App ruft dann getKeyRequest auf und übergibt den aus dem Inhalt extrahierten Content-Header als initData-Parameter. Darüber hinaus kann die App auch die angepassten Daten der Challenge für den Lizenzerwerb im optionalParameters Schlüssel-Wert-Vektor übergeben. Die angepassten Daten der Challenge für den Lizenzerwerb sollten dann als Drm_Content_SetProperty-Aufruf an den DRM Manager weitergegeben werden.
An diesem Punkt kann die App die (getKeyRequest / provideKeyResponse) ausführen, die die entsprechenden Aufrufe (Drm_LicenseAcq_GenerateChallenge) / Drm_LicenseAcq_ProcessResponse) für den DRM-Manager erzeugt.
Die App kann dann ein MediaCrypto-Objekt instanziieren, das eine Instanz einer PlayReadyCryptoPlugin-Schnittstelle (Wrapping DRM_DECRYPT_CONTEXT) erstellt, wenn der Drm_Reader_Bind Aufruf zurückgegeben wird.
Danach verwenden alle Entschlüsselungsaufrufe die PlayReadyCryptoPlugin::d ecrypt-Methode , die ein Handle an die entschlüsselten Beispiele zurückgibt.


4. PlayReadyDRMPlugin
setPropertyString
Apps verwenden diese Methode, um Parameter an PlayReady zu übergeben, die aufgrund des aktuellen Designs der Plug-In-APIs nicht andernfalls möglich sind.
DeviceStoreName – Die App muss den Speicherort des Gerätespeichers vor dem Öffnen einer Sitzung als Eigenschaft festlegen. Anschließend sucht PlayReady beim Initialisieren des DRM-Managers während der Aufrufe von openSession die DeviceStoreName-Eigenschaft. Der Pfad zum Gerätespeicher muss für die App wie das private Datenverzeichnis der App zugänglich sein. Die Eigenschaft sollte auf einen <Pfad/Dateinamen> zeigen, der den HDS enthalten soll.
LicenseChallengeCustomData – Die App kann diese Eigenschaft optional vor Aufrufen von getKeyRequest festlegen, wobei PlayReady die Eigenschaft nachschlagen und eine Lizenzerwerbsaufforderung erstellt und die benutzerdefinierten Daten in die Anforderung einschließt.
SecureStopCustomData – Die App kann diese Eigenschaft optional vor einem Aufruf festlegen, um die Secure Stop-Abfrage zu generieren. PlayReady sucht die Eigenschaft und erstellt die Secure Stop-Abfrage und schließt die benutzerdefinierten Daten in die Anforderung ein.
SelectKID – In Situationen, in denen die App mehrere In-Memory-Lizenzen in einem einzigen Batch erworben hat, kann sie eine base64-codierte KID für die Bindung angeben.
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);
}
setPropertyByteArray
Apps verwenden diese Methode, um Parameter an PlayReady zu übergeben, die aufgrund des aktuellen Designs der Plug-In-APIs nicht andernfalls möglich sind.
ContentHeader – Die App sollte den Inhaltsheader für das Plug-In festlegen, bevor Sie versuchen, ein Crypto-Objekt zu erstellen. Der Inhaltsheader kann in einem der folgenden Formate vorliegen:
Bytearray mit dem Inhalt des PlayReady-Objekts.
Bytearray mit dem Inhalt der Header V2, V2.4, V4, V4.1, V4.2 (Unicode-XML).
Breites Zeichenarray, das die 24-stellige KeyID angibt.
SecureStopPublisherCert-Die App sollte das Publisher Zertifikat einmal vor allen Aufrufen im Zusammenhang mit Secure Stop festlegen.
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);
}
openSession
Dieser Aufruf sollte dazu führen, dass der AppContext initialisiert wird, indem die Drm_Initialize-Funktion des DRM-Managers aufgerufen wird.
Vor diesem Aufruf muss die App PropertyString für das Plug-In festlegen, um den Pfad zum Gerätespeicher bereitzustellen, der zum Speichern des HDS verwendet wird.
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);
}
closeSession
Das Abschließen einer DRM-Sitzung sollte Drm_Uninitialize aufrufen, um den AppContext freizugeben.
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
Diese Methode generiert eine Lizenzanforderungsanforderung.
ContentHeader—Die App kann entweder den ContentHeader im initData-Parameter übergeben oder, bevor sie diese Funktion aufruft, die ContentHeader-Eigenschaft als Zeichenfolge festlegen.
LicenseChallengeCustomData-Die App kann die angepassten Challenge-Daten im Parameter optionalParameters mit der Zeichenfolge „LicenseChallengeCustomData“ übergeben. Alternativ kann die Methode die LicenseChallengeCustomData abrufen, wenn die App sie bereits als Eigenschaft festgelegt hat.
Die Methode füllt die defaultUrl auf, wenn sie im Inhaltsheader verfügbar ist, sowie die Anforderung, die an den Lizenzserver gesendet werden soll.
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);
}
provideKeyResponse
Sobald ein KeyRequest (LicenseChallenge) von der App an den Lizenzserver gesendet wurde, sollte die App das KeyResponse (LicenseResponse) an das Plug-in übergeben.
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)
Apps können die getSecureStop-Methode aufrufen, um eine Abfrage für sicheres Beenden für die angegebene ID für sicheres Beenden zu generieren. Alternativ kann die App getSecureStops aufrufen, um eine Challenge für den Secure Stop zu generieren, der für alle bestehenden Sitzungen gilt.
Bevor die App die Challenge für den Secure Stop generiert, muss sie das Zertifikat des Publishers bereitstellen, indem sie setPropertyByteArray aufruft und SecureStopPublisherCert übergibt.
Optional kann die App auch SecureStopCustomData bereitstellen, die in die Secure-Stop-Herausforderung integriert werden kann.
Nachdem die Abfrage zum sicheren Beenden erstellt wurde, sollte sie von der App an den Server gesendet und die Antwort auf sicheres Beenden an die ReleaseSecureStops-Methode zurückgegeben werden.
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
Sobald die App die Antwort auf sicheres Beenden vom Server empfängt, sollte die Nachricht an das Plug-In übergeben werden, um die Informationen zum sicheren Beenden aus dem Speicher zu entfernen.
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);
}
Nicht unterstützte APIs (kein Vorgang)
Die folgende Liste der APIs verfügt nicht über einen entsprechenden Vorgang in PlayReady und ist für die erfolgreiche Ausführung der unterstützten Szenarien nicht erforderlich.
queryKeyStatus
status_t PlayReadyDrmPlugin::queryKeyStatus(
Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8=""> &infoMap) const
{ return _DR_TO_STATUS(DRM_E_NOTIMPL); }
getProvisionRequest
PlayReady unterstützt die lokale Bereitstellung nur auf Android-Geräten.
status_t PlayReadyDrmPlugin::getProvisionRequest(
String8 const &certType,
String8 const &certAuthority,
Vector<uint8_t> &request,
String8 &defaultUrl) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
provideProvisionResponse
PlayReady unterstützt die lokale Bereitstellung nur auf Android-Geräten.
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
PlayReady unterstützt die lokale Bereitstellung nur auf Android-Geräten.
status_t PlayReadyDrmPlugin::unprovisionDevice() { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
setCipherAlgorithm
PlayReady verschlüsselt/entschlüsselt keine beliebigen Daten.
status_t PlayReadyDrmPlugin::setCipherAlgorithm(
Vector<uint8_t> const &sessionId,
String8 const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
setzeMacAlgorithmus
PlayReady signiert/überprüft keine beliebigen Daten.
status_t PlayReadyDrmPlugin::setMacAlgorithm(
Vector<uint8_t> const &sessionId,
String8 const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
verschlüsseln
PlayReady verschlüsselt/entschlüsselt keine beliebigen Daten.
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); }
entschlüsseln
PlayReady verschlüsselt/entschlüsselt keine beliebigen Daten.
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); }
sign
PlayReady signiert/überprüft keine beliebigen Daten.
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); }
überprüfen
PlayReady signiert/überprüft keine beliebigen Daten.
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
PlayReady signiert/überprüft keine beliebigen Daten.
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
Konstruktor zum Erstellen eines PlayReadyCryptoPlugin-Objekts .
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;
}
requiresSecureDecoderComponent
Zum Verarbeiten verschlüsselter PlayReady-Inhalte ist eine sichere Decoderkomponente erforderlich.
bool PlayReadyCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
{
// Must always return true for PlayReady Content.
return true;
}
entschlüsseln
Die von MediaCodec aufgerufene Entschlüsselung.
Da die Entschlüsselungsmethode keine eindeutigen Beispiele ausgibt, sondern ein OEM-spezifisches Handle, muss der OEM sicherstellen, dass MediaCodec in der Lage ist, mit diesem Handle korrekt zu arbeiten.
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
Der Krypto-Plug-In-Destruktor muss den Entschlüsselungskontext schließen.
~PlayReadyCryptoPlugin::PlayReadyCryptoPlugin()
{
Mutex::Autolock lock(mLock);
Drm_Reader_Close(&moDecryptContext);
}
6. PlayReadyDrmFactory und PlayReadyCryptoFactory
Die Implementierung der Schnittstellen PlayReadyDrmFactory und PlayReadyCryptoFactory ist erforderlich, um Instanzen von PlayReadyDrmPlugin bzw. PlayReadyCryptoPlugin zu erstellen.
Beide Factoryklassen müssen den Aufrufern anzeigen, dass sie das Erstellen von Objekten unterstützen, die PlayReady-geschützte Inhalte konsumieren können, indem sie die isCryptoSchemeSupported-API ordnungsgemäß implementieren.
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
Es muss ein Singleton Session Manager implementiert werden, um den DRM_APP_CONTEXT zu halten und die Möglichkeit zu bieten, ihn zwischen dem PlayReadyDrmPlugin und PlayReadyCryptoPlugin zu teilen.
Andere Designs, die denselben Zweck erreichen, sind ebenfalls akzeptabel.
| SessionManager |
|---|
| static DRM_APP_CONTEXT soAppContext |
| static Mutex sLock |