• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "NdkMediaDrm"
19 
20 #include <media/NdkMediaDrm.h>
21 
22 #include <cutils/properties.h>
23 #include <utils/Log.h>
24 #include <utils/StrongPointer.h>
25 #include <gui/Surface.h>
26 
27 #include <media/IDrm.h>
28 #include <media/IDrmClient.h>
29 #include <media/stagefright/MediaErrors.h>
30 #include <binder/IServiceManager.h>
31 #include <media/IMediaDrmService.h>
32 #include <media/NdkMediaCrypto.h>
33 
34 
35 using namespace android;
36 
37 typedef Vector<uint8_t> idvec_t;
38 
39 struct DrmListener: virtual public BnDrmClient
40 {
41 private:
42     AMediaDrm *mObj;
43     AMediaDrmEventListener mListener;
44 
45 public:
DrmListenerDrmListener46     DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
47     void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
48 };
49 
50 struct AMediaDrm {
51     sp<IDrm> mDrm;
52     sp<IDrmClient> mDrmClient;
53     List<idvec_t> mIds;
54     KeyedVector<String8, String8> mQueryResults;
55     Vector<uint8_t> mKeyRequest;
56     Vector<uint8_t> mProvisionRequest;
57     String8 mProvisionUrl;
58     String8 mPropertyString;
59     Vector<uint8_t> mPropertyByteArray;
60     List<Vector<uint8_t> > mSecureStops;
61     sp<DrmListener> mListener;
62 };
63 
notify(DrmPlugin::EventType eventType,int extra,const Parcel * obj)64 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
65     if (!mListener) {
66         return;
67     }
68 
69     AMediaDrmSessionId sessionId = {NULL, 0};
70     int32_t sessionIdSize = obj->readInt32();
71     if (sessionIdSize) {
72         uint8_t *sessionIdData = new uint8_t[sessionIdSize];
73         sessionId.ptr = sessionIdData;
74         sessionId.length = sessionIdSize;
75         obj->read(sessionIdData, sessionId.length);
76     }
77 
78     int32_t dataSize = obj->readInt32();
79     uint8_t *data = NULL;
80     if (dataSize) {
81         data = new uint8_t[dataSize];
82         obj->read(data, dataSize);
83     }
84 
85     // translate DrmPlugin event types into their NDK equivalents
86     AMediaDrmEventType ndkEventType;
87     switch(eventType) {
88         case DrmPlugin::kDrmPluginEventProvisionRequired:
89             ndkEventType = EVENT_PROVISION_REQUIRED;
90             break;
91         case DrmPlugin::kDrmPluginEventKeyNeeded:
92             ndkEventType = EVENT_KEY_REQUIRED;
93             break;
94         case DrmPlugin::kDrmPluginEventKeyExpired:
95             ndkEventType = EVENT_KEY_EXPIRED;
96             break;
97         case DrmPlugin::kDrmPluginEventVendorDefined:
98             ndkEventType = EVENT_VENDOR_DEFINED;
99             break;
100         default:
101             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
102             goto cleanup;
103     }
104 
105     (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
106 
107  cleanup:
108     delete [] sessionId.ptr;
109     delete [] data;
110 }
111 
112 
113 extern "C" {
114 
translateStatus(status_t status)115 static media_status_t translateStatus(status_t status) {
116     media_status_t result = AMEDIA_ERROR_UNKNOWN;
117     switch (status) {
118         case OK:
119             result = AMEDIA_OK;
120             break;
121         case android::ERROR_DRM_NOT_PROVISIONED:
122             result = AMEDIA_DRM_NOT_PROVISIONED;
123             break;
124         case android::ERROR_DRM_RESOURCE_BUSY:
125             result = AMEDIA_DRM_RESOURCE_BUSY;
126             break;
127         case android::ERROR_DRM_DEVICE_REVOKED:
128             result = AMEDIA_DRM_DEVICE_REVOKED;
129             break;
130         case android::ERROR_DRM_CANNOT_HANDLE:
131             result = AMEDIA_ERROR_INVALID_PARAMETER;
132             break;
133         case android::ERROR_DRM_TAMPER_DETECTED:
134             result = AMEDIA_DRM_TAMPER_DETECTED;
135             break;
136         case android::ERROR_DRM_SESSION_NOT_OPENED:
137             result = AMEDIA_DRM_SESSION_NOT_OPENED;
138             break;
139         case android::ERROR_DRM_NO_LICENSE:
140             result = AMEDIA_DRM_NEED_KEY;
141             break;
142         case android::ERROR_DRM_LICENSE_EXPIRED:
143             result = AMEDIA_DRM_LICENSE_EXPIRED;
144             break;
145         default:
146             break;
147     }
148     return result;
149 }
150 
CreateDrm()151 static sp<IDrm> CreateDrm() {
152     sp<IServiceManager> sm = defaultServiceManager();
153     sp<IBinder> binder = sm->getService(String16("media.drm"));
154 
155     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
156     if (service == NULL) {
157         return NULL;
158     }
159 
160     sp<IDrm> drm = service->makeDrm();
161     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
162         return NULL;
163     }
164     return drm;
165 }
166 
167 
CreateDrmFromUUID(const AMediaUUID uuid)168 static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
169     sp<IDrm> drm = CreateDrm();
170 
171     if (drm == NULL) {
172         return NULL;
173     }
174 
175     String8 nullPackageName;
176     status_t err = drm->createPlugin(uuid, nullPackageName);
177 
178     if (err != OK) {
179         return NULL;
180     }
181 
182     return drm;
183 }
184 
185 EXPORT
AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid,const char * mimeType)186 bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
187     sp<IDrm> drm = CreateDrm();
188 
189     if (drm == NULL) {
190         return false;
191     }
192 
193     String8 mimeStr = mimeType ? String8(mimeType) : String8("");
194     return drm->isCryptoSchemeSupported(uuid, mimeStr);
195 }
196 
197 EXPORT
AMediaDrm_createByUUID(const AMediaUUID uuid)198 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
199     AMediaDrm *mObj = new AMediaDrm();
200     mObj->mDrm = CreateDrmFromUUID(uuid);
201     return mObj;
202 }
203 
204 EXPORT
AMediaDrm_release(AMediaDrm * mObj)205 void AMediaDrm_release(AMediaDrm *mObj) {
206     if (mObj->mDrm != NULL) {
207         mObj->mDrm->setListener(NULL);
208         mObj->mDrm->destroyPlugin();
209         mObj->mDrm.clear();
210     }
211     delete mObj;
212 }
213 
214 EXPORT
AMediaDrm_setOnEventListener(AMediaDrm * mObj,AMediaDrmEventListener listener)215 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
216     if (!mObj || mObj->mDrm == NULL) {
217         return AMEDIA_ERROR_INVALID_OBJECT;
218     }
219     mObj->mListener = new DrmListener(mObj, listener);
220     mObj->mDrm->setListener(mObj->mListener);
221     return AMEDIA_OK;
222 }
223 
224 
findId(AMediaDrm * mObj,const AMediaDrmByteArray & id,List<idvec_t>::iterator & iter)225 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
226     for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
227         if (iter->array() == id.ptr && iter->size() == id.length) {
228             return true;
229         }
230     }
231     return false;
232 }
233 
234 EXPORT
AMediaDrm_openSession(AMediaDrm * mObj,AMediaDrmSessionId * sessionId)235 media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
236     if (!mObj || mObj->mDrm == NULL) {
237         return AMEDIA_ERROR_INVALID_OBJECT;
238     }
239     if (!sessionId) {
240         return AMEDIA_ERROR_INVALID_PARAMETER;
241     }
242     Vector<uint8_t> session;
243     status_t status = mObj->mDrm->openSession(session);
244     if (status == OK) {
245         mObj->mIds.push_front(session);
246         List<idvec_t>::iterator iter = mObj->mIds.begin();
247         sessionId->ptr = iter->array();
248         sessionId->length = iter->size();
249     }
250     return AMEDIA_OK;
251 }
252 
253 EXPORT
AMediaDrm_closeSession(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId)254 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
255     if (!mObj || mObj->mDrm == NULL) {
256         return AMEDIA_ERROR_INVALID_OBJECT;
257     }
258     if (!sessionId) {
259         return AMEDIA_ERROR_INVALID_PARAMETER;
260     }
261 
262     List<idvec_t>::iterator iter;
263     if (!findId(mObj, *sessionId, iter)) {
264         return AMEDIA_DRM_SESSION_NOT_OPENED;
265     }
266     mObj->mDrm->closeSession(*iter);
267     mObj->mIds.erase(iter);
268     return AMEDIA_OK;
269 }
270 
271 EXPORT
AMediaDrm_getKeyRequest(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * init,size_t initSize,const char * mimeType,AMediaDrmKeyType keyType,const AMediaDrmKeyValue * optionalParameters,size_t numOptionalParameters,const uint8_t ** keyRequest,size_t * keyRequestSize)272 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
273         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
274         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
275         const uint8_t **keyRequest, size_t *keyRequestSize) {
276 
277     if (!mObj || mObj->mDrm == NULL) {
278         return AMEDIA_ERROR_INVALID_OBJECT;
279     }
280     if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
281         return AMEDIA_ERROR_INVALID_PARAMETER;
282     }
283 
284     List<idvec_t>::iterator iter;
285     if (!findId(mObj, *scope, iter)) {
286         return AMEDIA_DRM_SESSION_NOT_OPENED;
287     }
288 
289     Vector<uint8_t> mdInit;
290     mdInit.appendArray(init, initSize);
291     DrmPlugin::KeyType mdKeyType;
292     switch (keyType) {
293         case KEY_TYPE_STREAMING:
294             mdKeyType = DrmPlugin::kKeyType_Streaming;
295             break;
296         case KEY_TYPE_OFFLINE:
297             mdKeyType = DrmPlugin::kKeyType_Offline;
298             break;
299         case KEY_TYPE_RELEASE:
300             mdKeyType = DrmPlugin::kKeyType_Release;
301             break;
302         default:
303             return AMEDIA_ERROR_INVALID_PARAMETER;
304     }
305     KeyedVector<String8, String8> mdOptionalParameters;
306     for (size_t i = 0; i < numOptionalParameters; i++) {
307         mdOptionalParameters.add(String8(optionalParameters[i].mKey),
308                 String8(optionalParameters[i].mValue));
309     }
310     String8 defaultUrl;
311     DrmPlugin::KeyRequestType keyRequestType;
312     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
313             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
314             &keyRequestType);
315     if (status != OK) {
316         return translateStatus(status);
317     } else {
318         *keyRequest = mObj->mKeyRequest.array();
319         *keyRequestSize = mObj->mKeyRequest.size();
320     }
321     return AMEDIA_OK;
322 }
323 
324 EXPORT
AMediaDrm_provideKeyResponse(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * response,size_t responseSize,AMediaDrmKeySetId * keySetId)325 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
326         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
327 
328     if (!mObj || mObj->mDrm == NULL) {
329         return AMEDIA_ERROR_INVALID_OBJECT;
330     }
331     if (!scope || !response || !responseSize || !keySetId) {
332         return AMEDIA_ERROR_INVALID_PARAMETER;
333     }
334 
335     List<idvec_t>::iterator iter;
336     if (!findId(mObj, *scope, iter)) {
337         return AMEDIA_DRM_SESSION_NOT_OPENED;
338     }
339     Vector<uint8_t> mdResponse;
340     mdResponse.appendArray(response, responseSize);
341 
342     Vector<uint8_t> mdKeySetId;
343     status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
344     if (status == OK) {
345         mObj->mIds.push_front(mdKeySetId);
346         List<idvec_t>::iterator iter = mObj->mIds.begin();
347         keySetId->ptr = iter->array();
348         keySetId->length = iter->size();
349     } else {
350         keySetId->ptr = NULL;
351         keySetId->length = 0;
352     }
353     return AMEDIA_OK;
354 }
355 
356 EXPORT
AMediaDrm_restoreKeys(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const AMediaDrmKeySetId * keySetId)357 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
358         const AMediaDrmKeySetId *keySetId) {
359 
360     if (!mObj || mObj->mDrm == NULL) {
361         return AMEDIA_ERROR_INVALID_OBJECT;
362     }
363     if (!sessionId || !keySetId) {
364         return AMEDIA_ERROR_INVALID_PARAMETER;
365     }
366     List<idvec_t>::iterator iter;
367     if (!findId(mObj, *sessionId, iter)) {
368         return AMEDIA_DRM_SESSION_NOT_OPENED;
369     }
370     Vector<uint8_t> keySet;
371     keySet.appendArray(keySetId->ptr, keySetId->length);
372     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
373 }
374 
375 EXPORT
AMediaDrm_removeKeys(AMediaDrm * mObj,const AMediaDrmSessionId * keySetId)376 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
377     if (!mObj || mObj->mDrm == NULL) {
378         return AMEDIA_ERROR_INVALID_OBJECT;
379     }
380     if (!keySetId) {
381         return AMEDIA_ERROR_INVALID_PARAMETER;
382     }
383     List<idvec_t>::iterator iter;
384     status_t status;
385     if (!findId(mObj, *keySetId, iter)) {
386         Vector<uint8_t> keySet;
387         keySet.appendArray(keySetId->ptr, keySetId->length);
388         status = mObj->mDrm->removeKeys(keySet);
389     } else {
390         status = mObj->mDrm->removeKeys(*iter);
391         mObj->mIds.erase(iter);
392     }
393     return translateStatus(status);
394 }
395 
396 EXPORT
AMediaDrm_queryKeyStatus(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,AMediaDrmKeyValue * keyValuePairs,size_t * numPairs)397 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
398         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
399 
400     if (!mObj || mObj->mDrm == NULL) {
401         return AMEDIA_ERROR_INVALID_OBJECT;
402     }
403     if (!sessionId || !numPairs) {
404         return AMEDIA_ERROR_INVALID_PARAMETER;
405     }
406     List<idvec_t>::iterator iter;
407     if (!findId(mObj, *sessionId, iter)) {
408         return AMEDIA_DRM_SESSION_NOT_OPENED;
409     }
410 
411     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
412     if (status != OK) {
413         *numPairs = 0;
414         return translateStatus(status);
415     }
416 
417     if (mObj->mQueryResults.size() > *numPairs) {
418         *numPairs = mObj->mQueryResults.size();
419         return AMEDIA_DRM_SHORT_BUFFER;
420     }
421 
422     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
423         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
424         keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
425     }
426     *numPairs = mObj->mQueryResults.size();
427     return AMEDIA_OK;
428 }
429 
430 EXPORT
AMediaDrm_getProvisionRequest(AMediaDrm * mObj,const uint8_t ** provisionRequest,size_t * provisionRequestSize,const char ** serverUrl)431 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
432         size_t *provisionRequestSize, const char **serverUrl) {
433     if (!mObj || mObj->mDrm == NULL) {
434         return AMEDIA_ERROR_INVALID_OBJECT;
435     }
436     if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
437         return AMEDIA_ERROR_INVALID_PARAMETER;
438     }
439 
440     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
441             mObj->mProvisionRequest, mObj->mProvisionUrl);
442     if (status != OK) {
443         return translateStatus(status);
444     } else {
445         *provisionRequest = mObj->mProvisionRequest.array();
446         *provisionRequestSize = mObj->mProvisionRequest.size();
447         *serverUrl = mObj->mProvisionUrl.string();
448     }
449     return AMEDIA_OK;
450 }
451 
452 EXPORT
AMediaDrm_provideProvisionResponse(AMediaDrm * mObj,const uint8_t * response,size_t responseSize)453 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
454         const uint8_t *response, size_t responseSize) {
455     if (!mObj || mObj->mDrm == NULL) {
456         return AMEDIA_ERROR_INVALID_OBJECT;
457     }
458     if (!response || !responseSize) {
459         return AMEDIA_ERROR_INVALID_PARAMETER;
460     }
461 
462     Vector<uint8_t> mdResponse;
463     mdResponse.appendArray(response, responseSize);
464 
465     Vector<uint8_t> unused;
466     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
467 }
468 
469 EXPORT
AMediaDrm_getSecureStops(AMediaDrm * mObj,AMediaDrmSecureStop * secureStops,size_t * numSecureStops)470 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
471         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
472 
473     if (!mObj || mObj->mDrm == NULL) {
474         return AMEDIA_ERROR_INVALID_OBJECT;
475     }
476     if (!numSecureStops) {
477         return AMEDIA_ERROR_INVALID_PARAMETER;
478     }
479     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
480     if (status != OK) {
481         *numSecureStops = 0;
482         return translateStatus(status);
483     }
484     if (*numSecureStops < mObj->mSecureStops.size()) {
485         return AMEDIA_DRM_SHORT_BUFFER;
486     }
487     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
488     size_t i = 0;
489     while (iter != mObj->mSecureStops.end()) {
490         secureStops[i].ptr = iter->array();
491         secureStops[i].length = iter->size();
492         ++iter;
493         ++i;
494     }
495     *numSecureStops = mObj->mSecureStops.size();
496     return AMEDIA_OK;
497 }
498 
499 EXPORT
AMediaDrm_releaseSecureStops(AMediaDrm * mObj,const AMediaDrmSecureStop * ssRelease)500 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
501         const AMediaDrmSecureStop *ssRelease) {
502 
503     if (!mObj || mObj->mDrm == NULL) {
504         return AMEDIA_ERROR_INVALID_OBJECT;
505     }
506     if (!ssRelease) {
507         return AMEDIA_ERROR_INVALID_PARAMETER;
508     }
509 
510     Vector<uint8_t> release;
511     release.appendArray(ssRelease->ptr, ssRelease->length);
512     return translateStatus(mObj->mDrm->releaseSecureStops(release));
513 }
514 
515 
516 EXPORT
AMediaDrm_getPropertyString(AMediaDrm * mObj,const char * propertyName,const char ** propertyValue)517 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
518         const char **propertyValue) {
519 
520     if (!mObj || mObj->mDrm == NULL) {
521         return AMEDIA_ERROR_INVALID_OBJECT;
522     }
523     if (!propertyName || !propertyValue) {
524         return AMEDIA_ERROR_INVALID_PARAMETER;
525     }
526 
527     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
528             mObj->mPropertyString);
529 
530     if (status == OK) {
531         *propertyValue = mObj->mPropertyString.string();
532     } else {
533         *propertyValue = NULL;
534     }
535     return translateStatus(status);
536 }
537 
538 EXPORT
AMediaDrm_getPropertyByteArray(AMediaDrm * mObj,const char * propertyName,AMediaDrmByteArray * propertyValue)539 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
540         const char *propertyName, AMediaDrmByteArray *propertyValue) {
541     if (!mObj || mObj->mDrm == NULL) {
542         return AMEDIA_ERROR_INVALID_OBJECT;
543     }
544     if (!propertyName || !propertyValue) {
545         return AMEDIA_ERROR_INVALID_PARAMETER;
546     }
547 
548     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
549             mObj->mPropertyByteArray);
550 
551     if (status == OK) {
552         propertyValue->ptr = mObj->mPropertyByteArray.array();
553         propertyValue->length = mObj->mPropertyByteArray.size();
554     } else {
555         propertyValue->ptr = NULL;
556         propertyValue->length = 0;
557     }
558     return translateStatus(status);
559 }
560 
561 EXPORT
AMediaDrm_setPropertyString(AMediaDrm * mObj,const char * propertyName,const char * value)562 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
563         const char *propertyName, const char *value) {
564     if (!mObj || mObj->mDrm == NULL) {
565         return AMEDIA_ERROR_INVALID_OBJECT;
566     }
567 
568     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
569                     String8(value)));
570 }
571 
572 EXPORT
AMediaDrm_setPropertyByteArray(AMediaDrm * mObj,const char * propertyName,const uint8_t * value,size_t valueSize)573 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
574         const char *propertyName, const uint8_t *value, size_t valueSize) {
575 
576     Vector<uint8_t> byteArray;
577     byteArray.appendArray(value, valueSize);
578 
579     return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
580                     byteArray));
581 }
582 
583 
encrypt_decrypt_common(AMediaDrm * mObj,const AMediaDrmSessionId & sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize,bool encrypt)584 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
585         const AMediaDrmSessionId &sessionId,
586         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
587         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
588 
589     if (!mObj || mObj->mDrm == NULL) {
590         return AMEDIA_ERROR_INVALID_OBJECT;
591     }
592     List<idvec_t>::iterator iter;
593     if (!findId(mObj, sessionId, iter)) {
594         return AMEDIA_DRM_SESSION_NOT_OPENED;
595     }
596 
597     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
598     if (status != OK) {
599         return translateStatus(status);
600     }
601 
602     Vector<uint8_t> keyIdVec;
603     const size_t kKeyIdSize = 16;
604     keyIdVec.appendArray(keyId, kKeyIdSize);
605 
606     Vector<uint8_t> inputVec;
607     inputVec.appendArray(input, dataSize);
608 
609     Vector<uint8_t> ivVec;
610     const size_t kIvSize = 16;
611     ivVec.appendArray(iv, kIvSize);
612 
613     Vector<uint8_t> outputVec;
614     if (encrypt) {
615         status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
616     } else {
617         status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
618     }
619     if (status == OK) {
620         memcpy(output, outputVec.array(), outputVec.size());
621     }
622     return translateStatus(status);
623 }
624 
625 EXPORT
AMediaDrm_encrypt(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize)626 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
627         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
628         const uint8_t *input, uint8_t *output, size_t dataSize) {
629     if (!sessionId) {
630         return AMEDIA_ERROR_INVALID_PARAMETER;
631     }
632     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
633             input, output, dataSize, true);
634 }
635 
636 EXPORT
AMediaDrm_decrypt(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * cipherAlgorithm,uint8_t * keyId,uint8_t * iv,const uint8_t * input,uint8_t * output,size_t dataSize)637 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
638         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
639         const uint8_t *input, uint8_t *output, size_t dataSize) {
640     if (!sessionId) {
641         return AMEDIA_ERROR_INVALID_PARAMETER;
642     }
643     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
644             input, output, dataSize, false);
645 }
646 
647 EXPORT
AMediaDrm_sign(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * macAlgorithm,uint8_t * keyId,uint8_t * message,size_t messageSize,uint8_t * signature,size_t * signatureSize)648 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
649         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
650         uint8_t *signature, size_t *signatureSize) {
651 
652     if (!mObj || mObj->mDrm == NULL) {
653         return AMEDIA_ERROR_INVALID_OBJECT;
654     }
655     if (!sessionId) {
656         return AMEDIA_ERROR_INVALID_PARAMETER;
657     }
658     List<idvec_t>::iterator iter;
659     if (!findId(mObj, *sessionId, iter)) {
660         return AMEDIA_DRM_SESSION_NOT_OPENED;
661     }
662 
663     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
664     if (status != OK) {
665         return translateStatus(status);
666     }
667 
668     Vector<uint8_t> keyIdVec;
669     const size_t kKeyIdSize = 16;
670     keyIdVec.appendArray(keyId, kKeyIdSize);
671 
672     Vector<uint8_t> messageVec;
673     messageVec.appendArray(message, messageSize);
674 
675     Vector<uint8_t> signatureVec;
676     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
677     if (signatureVec.size() > *signatureSize) {
678         return AMEDIA_DRM_SHORT_BUFFER;
679     }
680     if (status == OK) {
681         memcpy(signature, signatureVec.array(), signatureVec.size());
682     }
683     return translateStatus(status);
684 }
685 
686 EXPORT
AMediaDrm_verify(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const char * macAlgorithm,uint8_t * keyId,const uint8_t * message,size_t messageSize,const uint8_t * signature,size_t signatureSize)687 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
688         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
689         const uint8_t *signature, size_t signatureSize) {
690 
691     if (!mObj || mObj->mDrm == NULL) {
692         return AMEDIA_ERROR_INVALID_OBJECT;
693     }
694     if (!sessionId) {
695         return AMEDIA_ERROR_INVALID_PARAMETER;
696     }
697     List<idvec_t>::iterator iter;
698     if (!findId(mObj, *sessionId, iter)) {
699         return AMEDIA_DRM_SESSION_NOT_OPENED;
700     }
701 
702     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
703     if (status != OK) {
704         return translateStatus(status);
705     }
706 
707     Vector<uint8_t> keyIdVec;
708     const size_t kKeyIdSize = 16;
709     keyIdVec.appendArray(keyId, kKeyIdSize);
710 
711     Vector<uint8_t> messageVec;
712     messageVec.appendArray(message, messageSize);
713 
714     Vector<uint8_t> signatureVec;
715     signatureVec.appendArray(signature, signatureSize);
716 
717     bool match;
718     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
719     if (status == OK) {
720         return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
721     }
722     return translateStatus(status);
723 }
724 
725 } // extern "C"
726