Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
1. Inleiding
Deze specificatie stelt richtlijnen vast voor OEM's voor het implementeren van Op PlayReady 4.0 gebaseerde DRM-invoegtoepassingen (Digital Rights Management) op Android. Zie voor naslaginformatie https://developer.android.com/reference/android/media/MediaDrm.html.
Deze specificatie bevat informatie over hoe de plug-in API's worden toegewezen aan PlayReady-aanroepen.
1.1. Wijzigingsgeschiedenis
Versie | Veranderen |
---|---|
Mei 2016 | Eerste versie |
2. Interfaces
PlayReadyDrmPlugin biedt de implementatie voor de DRM-invoegtoepassingsinterface. PlayReadyDrmPlugin is verantwoordelijk voor het verpakken van de DRM Manager-API's en het uitvoeren van de juiste vertaling voor de parameters zoals opgegeven door de interface in een indeling waarop PlayReady kan werken.
PlayReadyCryptoPlugin biedt de implementatie voor de Crypto plug-in interface, die verantwoordelijk is voor het ontsleutelen van de voorbeelden. De OEM moet ervoor zorgen dat de ontsleutelde voorbeelden nooit de TEE (Trusted Execution Environment) verlaten.
3. Bewerking
In de volgende stappen wordt een eenvoudig afspeelscenario beschreven:
De app maakt het MediaDrm-object , wat resulteert in de instantiëring van PlayReadyDrmPlugin.
Roep vervolgens openSession aan, wat resulteert in de initialisatie van drm-beheer.
De app zal vervolgens getKeyRequest aanroepen en de uit de inhoud geëxtraheerde contentheader als de initData-parameter doorgeven. Daarnaast kan de app ook de uitdaging van het verkrijgen van licenties doorgeven als aangepaste gegevens in de optionele parameters sleutel-waarde vector. Het proces voor het verkrijgen van licenties voor aangepaste gegevens moet vervolgens worden doorgegeven aan de DRM-manager als een Drm_Content_SetProperty-aanroep.
Op dit moment kan de app de aanroepen (getKeyRequest / provideKeyResponse) uitvoeren, waarmee de equivalente aanroepen (Drm_LicenseAcq_GenerateChallenge) / Drm_LicenseAcq_ProcessResponse) in de DRM Manager worden geproduceerd.
De app kan vervolgens een MediaCrypto-object instantiëren waarmee een exemplaar van een PlayReadyCryptoPlugin-interface (wrapping DRM_DECRYPT_CONTEXT) wordt gemaakt wanneer de Drm_Reader_Bind aanroep terugkeert.
Daarna zullen alle ontsleutelingsaanroepen gebruikmaken van de PlayReadyCryptoPlugin::d ecrypt-methode , die een ingang retourneert naar de ontsleutelde voorbeelden.
4. PlayReadyDRMPlugin
setPropertyString
Apps gebruiken deze methode om parameters door te geven aan PlayReady die anders niet mogelijk zijn vanwege het huidige ontwerp van de invoegtoepassing-API's.
DeviceStoreName — de app moet de locatie van de apparatenwinkel instellen als eigenschap voordat een sessie wordt geopend. Vervolgens zoekt PlayReady de eigenschap DeviceStoreName op bij het initialiseren van DRM Manager tijdens aanroepen omSession te openen. Het pad naar de apparaatopslag moet toegankelijk zijn voor de app, zoals de privégegevensmap van de app. De eigenschap moet verwijzen naar een <pad/bestandsnaam> die de HDS moet bevatten.
LicenseChallengeCustomData : de app kan deze eigenschap desgewenst instellen voordat aanroepen naar getKeyRequest worden aanroepen, waarbij PlayReady de eigenschap opzoekt en een vraag voor het verkrijgen van licenties opstelt en de aangepaste gegevens in de aanvraag opneemt.
SecureStopCustomData : de app kan deze eigenschap desgewenst instellen vóór een aanroep om de Secure Stop-uitdaging te genereren. PlayReady zoekt de eigenschap op en stelt de Secure Stop-uitdaging samen en neemt de aangepaste gegevens op in de aanvraag.
SelectKID : in situaties waarin de app meerdere in-memory licenties in één batch heeft verkregen, kan er een base64 gecodeerd KID voor binding worden opgegeven.
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 gebruiken deze methode om parameters door te geven aan PlayReady die anders niet mogelijk zijn vanwege het huidige ontwerp van de invoegtoepassings-API's.
ContentHeader: De app moet de header instellen op de plug-in voordat het probeert een Crypto-object te maken. De inhoudskoptekst kan een van de volgende indelingen hebben:
Bytematrix met de inhoud van het PlayReady-object.
Bytematrix met de inhoud van de headers V2, V2.4, V4.1, V4.2 (Unicode XML).
Brede tekenmatrix die de KeyID van 24 tekens aangeeft.
SecureStopPublisherCert: de app moet het uitgeverscertificaat eenmaal instellen voordat er enige beveiligde stop-gerelateerde oproepen worden gedaan.
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);
}
sessie openen
Deze aanroep moet resulteren in het initialiseren van de AppContext door de Drm_Initialize-functie van DRM Manager aan te roepen.
Vóór deze aanroep moet de app PropertyString instellen op de invoegtoepassing om het pad naar de apparaatopslag op te geven dat wordt gebruikt om de HDS op te slaan.
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);
}
sluitSessie
Als u een DRM-sessie sluit, moet Drm_Uninitialize worden aangeroepen om de AppContext vrij te geven.
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
Met deze methode wordt een licentieaanvraagvraag gegenereerd.
ContentHeader: de app kan de inhoudskop doorgeven in de parameter initData of, voordat deze functie wordt aangeroepen, moet de app de eigenschap ContentHeader-tekenreeks instellen.
LicenseChallengeCustomData: de app kan de aangepaste vraag doorgeven in de parameter optionalParameters met de tekenreekssleutel LicenseChallengeCustomData. De methode kan ook de LicenseChallengeCustomData ophalen als de app deze al heeft ingesteld als een eigenschap.
De methode vult de defaultUrl in, indien beschikbaar in de inhoudskoptekst en de aanvraag die naar de licentieserver moet worden verzonden.
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);
}
geefBelangrijkeReactie
Zodra een KeyRequest (LicenseChallenge)
door de app naar de licentieserver is verzonden, moet de app de KeyResponse (LicenseResponse)
doorgeven aan de invoegtoepassing.
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 kunnen de getSecureStop-methode aanroepen om een secure stop-uitdaging te genereren voor de opgegeven secure stop-id. De app kan ook getSecureStops aanroepen om een uitdaging te genereren voor alle bestaande beveiligde stopsessies.
Voordat de secure stop-uitdaging wordt gegenereerd, moet de app het uitgeverscertificaat opgeven door setPropertyByteArray aan te roepen en SecureStopPublisherCert door te geven.
De app kan ook optioneel SecureStopCustomData leveren om als onderdeel van de secure stop-uitdaging te worden opgenomen.
Nadat de secure stop-uitdaging is gemaakt, moet de app deze naar de server verzenden en de reactie van de secure stop terugsturen naar de releaseSecureStops-methode .
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
Zodra de app het antwoord van de server over de beveiligde stop ontvangt, moet het bericht worden doorgegeven aan de plug-in om de beveiligde stopinformatie uit de opslag te verwijderen.
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);
}
Niet-ondersteunde API's (geen bewerking)
De volgende lijst met API's heeft geen bijbehorende bewerking in PlayReady en is niet vereist voor een geslaagde uitvoering van de ondersteunde scenario's.
vraag sleutelstatus op
status_t PlayReadyDrmPlugin::queryKeyStatus(
Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8=""> &infoMap) const
{ return _DR_TO_STATUS(DRM_E_NOTIMPL); }
krijgVoorzieningsVerzoek
PlayReady biedt alleen ondersteuning voor lokale inrichting op Android-apparaten.
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 biedt alleen ondersteuning voor lokale inrichting op Android-apparaten.
status_t PlayReadyDrmPlugin::provideProvisionResponse(
Vector<uint8_t> const &response,
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
inrichting ongedaan makenDevice
PlayReady biedt alleen ondersteuning voor lokale inrichting op Android-apparaten.
status_t PlayReadyDrmPlugin::unprovisionDevice() { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
setCipherAlgorithm
PlayReady versleutelt/ontsleutelt willekeurige gegevens niet.
status_t PlayReadyDrmPlugin::setCipherAlgorithm(
Vector<uint8_t> const &sessionId,
String8 const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
setMacAlgorithm
PlayReady ondertekent/verifieert geen willekeurige gegevens.
status_t PlayReadyDrmPlugin::setMacAlgorithm(
Vector<uint8_t> const &sessionId,
String8 const &algorithm) { return _DR_TO_STATUS(DRM_E_NOTIMPL); }
versleutelen
PlayReady versleutelt/ontsleutelt willekeurige gegevens niet.
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); }
ontsleutelen
PlayReady versleutelt/ontsleutelt willekeurige gegevens niet.
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); }
teken
PlayReady ondertekent/verifieert geen willekeurige gegevens.
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); }
verifiëren
PlayReady ondertekent/verifieert geen willekeurige gegevens.
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); }
RSA-ondertekenen
PlayReady ondertekent/verifieert geen willekeurige gegevens.
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
Constructor voor het maken van een PlayReadyCryptoPlugin-object .
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;
}
vereist beveiligde decodercomponent
Een beveiligd decoderonderdeel is vereist voor het verwerken van versleutelde PlayReady-inhoud.
bool PlayReadyCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
{
// Must always return true for PlayReady Content.
return true;
}
ontsleutelen
De decryptie die door MediaCodec wordt aangeroepen.
Omdat de ontsleutelingsmethode geen duidelijke voorbeelden geeft, maar eerder een OEM-specifieke ingang, moet de OEM ervoor zorgen dat MediaCodec correct op die ingang kan werken.
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
De crypto-plug-in destructor moet de ontsleutelingscontext sluiten.
~PlayReadyCryptoPlugin::PlayReadyCryptoPlugin()
{
Mutex::Autolock lock(mLock);
Drm_Reader_Close(&moDecryptContext);
}
6. PlayReadyDrmFactory en PlayReadyCryptoFactory
Implementatie van de PlayReadyDrmFactory - en PlayReadyCryptoFactory-interfaces is vereist voor het maken van exemplaren van zowel PlayReadyDrmPlugin als PlayReadyCryptoPlugin .
Beide factoryklassen moeten tegen de aanroepen aangeven dat ze ondersteuning bieden voor het maken van objecten die PlayReady-beveiligde inhoud kunnen gebruiken door de isCryptoSchemeSupported-API correct te implementeren.
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
Er moet een singleton session manager worden geïmplementeerd om de DRM_APP_CONTEXT vast te houden en deze te kunnen delen tussen de PlayReadyDrmPlugin en PlayReadyCryptoPlugin.
Andere ontwerpen die hetzelfde doel bereiken, zijn ook acceptabel.
SessionManager |
---|
statische DRM_APP_CONTEXT soAppContext |
statische Mutex sLock |