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