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