• 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 "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     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
316             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
317     if (status != OK) {
318         return translateStatus(status);
319     } else {
320         *keyRequest = mObj->mKeyRequest.array();
321         *keyRequestSize = mObj->mKeyRequest.size();
322     }
323     return AMEDIA_OK;
324 }
325 
326 EXPORT
AMediaDrm_provideKeyResponse(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * response,size_t responseSize,AMediaDrmKeySetId * keySetId)327 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
328         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
329 
330     if (!mObj || mObj->mDrm == NULL) {
331         return AMEDIA_ERROR_INVALID_OBJECT;
332     }
333     if (!scope || !response || !responseSize || !keySetId) {
334         return AMEDIA_ERROR_INVALID_PARAMETER;
335     }
336 
337     List<idvec_t>::iterator iter;
338     if (!findId(mObj, *scope, iter)) {
339         return AMEDIA_DRM_SESSION_NOT_OPENED;
340     }
341     Vector<uint8_t> mdResponse;
342     mdResponse.appendArray(response, responseSize);
343 
344     Vector<uint8_t> mdKeySetId;
345     status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
346     if (status == OK) {
347         mObj->mIds.push_front(mdKeySetId);
348         List<idvec_t>::iterator iter = mObj->mIds.begin();
349         keySetId->ptr = iter->array();
350         keySetId->length = iter->size();
351     } else {
352         keySetId->ptr = NULL;
353         keySetId->length = 0;
354     }
355     return AMEDIA_OK;
356 }
357 
358 EXPORT
AMediaDrm_restoreKeys(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const AMediaDrmKeySetId * keySetId)359 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
360         const AMediaDrmKeySetId *keySetId) {
361 
362     if (!mObj || mObj->mDrm == NULL) {
363         return AMEDIA_ERROR_INVALID_OBJECT;
364     }
365     if (!sessionId || !keySetId) {
366         return AMEDIA_ERROR_INVALID_PARAMETER;
367     }
368     List<idvec_t>::iterator iter;
369     if (!findId(mObj, *sessionId, iter)) {
370         return AMEDIA_DRM_SESSION_NOT_OPENED;
371     }
372     Vector<uint8_t> keySet;
373     keySet.appendArray(keySetId->ptr, keySetId->length);
374     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
375 }
376 
377 EXPORT
AMediaDrm_removeKeys(AMediaDrm * mObj,const AMediaDrmSessionId * keySetId)378 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
379     if (!mObj || mObj->mDrm == NULL) {
380         return AMEDIA_ERROR_INVALID_OBJECT;
381     }
382     if (!keySetId) {
383         return AMEDIA_ERROR_INVALID_PARAMETER;
384     }
385     List<idvec_t>::iterator iter;
386     status_t status;
387     if (!findId(mObj, *keySetId, iter)) {
388         Vector<uint8_t> keySet;
389         keySet.appendArray(keySetId->ptr, keySetId->length);
390         status = mObj->mDrm->removeKeys(keySet);
391     } else {
392         status = mObj->mDrm->removeKeys(*iter);
393         mObj->mIds.erase(iter);
394     }
395     return translateStatus(status);
396 }
397 
398 EXPORT
AMediaDrm_queryKeyStatus(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,AMediaDrmKeyValue * keyValuePairs,size_t * numPairs)399 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
400         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
401 
402     if (!mObj || mObj->mDrm == NULL) {
403         return AMEDIA_ERROR_INVALID_OBJECT;
404     }
405     if (!sessionId || !numPairs) {
406         return AMEDIA_ERROR_INVALID_PARAMETER;
407     }
408     List<idvec_t>::iterator iter;
409     if (!findId(mObj, *sessionId, iter)) {
410         return AMEDIA_DRM_SESSION_NOT_OPENED;
411     }
412 
413     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
414     if (status != OK) {
415         *numPairs = 0;
416         return translateStatus(status);
417     }
418 
419     if (mObj->mQueryResults.size() > *numPairs) {
420         *numPairs = mObj->mQueryResults.size();
421         return AMEDIA_DRM_SHORT_BUFFER;
422     }
423 
424     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
425         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
426         keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
427     }
428     *numPairs = mObj->mQueryResults.size();
429     return AMEDIA_OK;
430 }
431 
432 EXPORT
AMediaDrm_getProvisionRequest(AMediaDrm * mObj,const uint8_t ** provisionRequest,size_t * provisionRequestSize,const char ** serverUrl)433 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
434         size_t *provisionRequestSize, const char **serverUrl) {
435     if (!mObj || mObj->mDrm == NULL) {
436         return AMEDIA_ERROR_INVALID_OBJECT;
437     }
438     if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
439         return AMEDIA_ERROR_INVALID_PARAMETER;
440     }
441 
442     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
443             mObj->mProvisionRequest, mObj->mProvisionUrl);
444     if (status != OK) {
445         return translateStatus(status);
446     } else {
447         *provisionRequest = mObj->mProvisionRequest.array();
448         *provisionRequestSize = mObj->mProvisionRequest.size();
449         *serverUrl = mObj->mProvisionUrl.string();
450     }
451     return AMEDIA_OK;
452 }
453 
454 EXPORT
AMediaDrm_provideProvisionResponse(AMediaDrm * mObj,const uint8_t * response,size_t responseSize)455 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
456         const uint8_t *response, size_t responseSize) {
457     if (!mObj || mObj->mDrm == NULL) {
458         return AMEDIA_ERROR_INVALID_OBJECT;
459     }
460     if (!response || !responseSize) {
461         return AMEDIA_ERROR_INVALID_PARAMETER;
462     }
463 
464     Vector<uint8_t> mdResponse;
465     mdResponse.appendArray(response, responseSize);
466 
467     Vector<uint8_t> unused;
468     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
469 }
470 
471 EXPORT
AMediaDrm_getSecureStops(AMediaDrm * mObj,AMediaDrmSecureStop * secureStops,size_t * numSecureStops)472 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
473         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
474 
475     if (!mObj || mObj->mDrm == NULL) {
476         return AMEDIA_ERROR_INVALID_OBJECT;
477     }
478     if (!numSecureStops) {
479         return AMEDIA_ERROR_INVALID_PARAMETER;
480     }
481     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
482     if (status != OK) {
483         *numSecureStops = 0;
484         return translateStatus(status);
485     }
486     if (*numSecureStops < mObj->mSecureStops.size()) {
487         return AMEDIA_DRM_SHORT_BUFFER;
488     }
489     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
490     size_t i = 0;
491     while (iter != mObj->mSecureStops.end()) {
492         secureStops[i].ptr = iter->array();
493         secureStops[i].length = iter->size();
494         ++iter;
495         ++i;
496     }
497     *numSecureStops = mObj->mSecureStops.size();
498     return AMEDIA_OK;
499 }
500 
501 EXPORT
AMediaDrm_releaseSecureStops(AMediaDrm * mObj,const AMediaDrmSecureStop * ssRelease)502 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
503         const AMediaDrmSecureStop *ssRelease) {
504 
505     if (!mObj || mObj->mDrm == NULL) {
506         return AMEDIA_ERROR_INVALID_OBJECT;
507     }
508     if (!ssRelease) {
509         return AMEDIA_ERROR_INVALID_PARAMETER;
510     }
511 
512     Vector<uint8_t> release;
513     release.appendArray(ssRelease->ptr, ssRelease->length);
514     return translateStatus(mObj->mDrm->releaseSecureStops(release));
515 }
516 
517 
518 EXPORT
AMediaDrm_getPropertyString(AMediaDrm * mObj,const char * propertyName,const char ** propertyValue)519 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
520         const char **propertyValue) {
521 
522     if (!mObj || mObj->mDrm == NULL) {
523         return AMEDIA_ERROR_INVALID_OBJECT;
524     }
525     if (!propertyName || !propertyValue) {
526         return AMEDIA_ERROR_INVALID_PARAMETER;
527     }
528 
529     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
530             mObj->mPropertyString);
531 
532     if (status == OK) {
533         *propertyValue = mObj->mPropertyString.string();
534     } else {
535         *propertyValue = NULL;
536     }
537     return translateStatus(status);
538 }
539 
540 EXPORT
AMediaDrm_getPropertyByteArray(AMediaDrm * mObj,const char * propertyName,AMediaDrmByteArray * propertyValue)541 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
542         const char *propertyName, AMediaDrmByteArray *propertyValue) {
543     if (!mObj || mObj->mDrm == NULL) {
544         return AMEDIA_ERROR_INVALID_OBJECT;
545     }
546     if (!propertyName || !propertyValue) {
547         return AMEDIA_ERROR_INVALID_PARAMETER;
548     }
549 
550     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
551             mObj->mPropertyByteArray);
552 
553     if (status == OK) {
554         propertyValue->ptr = mObj->mPropertyByteArray.array();
555         propertyValue->length = mObj->mPropertyByteArray.size();
556     } else {
557         propertyValue->ptr = NULL;
558         propertyValue->length = 0;
559     }
560     return translateStatus(status);
561 }
562 
563 EXPORT
AMediaDrm_setPropertyString(AMediaDrm * mObj,const char * propertyName,const char * value)564 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
565         const char *propertyName, const char *value) {
566     if (!mObj || mObj->mDrm == NULL) {
567         return AMEDIA_ERROR_INVALID_OBJECT;
568     }
569 
570     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
571                     String8(value)));
572 }
573 
574 EXPORT
AMediaDrm_setPropertyByteArray(AMediaDrm * mObj,const char * propertyName,const uint8_t * value,size_t valueSize)575 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
576         const char *propertyName, const uint8_t *value, size_t valueSize) {
577 
578     Vector<uint8_t> byteArray;
579     byteArray.appendArray(value, valueSize);
580 
581     return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
582                     byteArray));
583 }
584 
585 
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)586 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
587         const AMediaDrmSessionId &sessionId,
588         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
589         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
590 
591     if (!mObj || mObj->mDrm == NULL) {
592         return AMEDIA_ERROR_INVALID_OBJECT;
593     }
594     List<idvec_t>::iterator iter;
595     if (!findId(mObj, sessionId, iter)) {
596         return AMEDIA_DRM_SESSION_NOT_OPENED;
597     }
598 
599     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
600     if (status != OK) {
601         return translateStatus(status);
602     }
603 
604     Vector<uint8_t> keyIdVec;
605     const size_t kKeyIdSize = 16;
606     keyIdVec.appendArray(keyId, kKeyIdSize);
607 
608     Vector<uint8_t> inputVec;
609     inputVec.appendArray(input, dataSize);
610 
611     Vector<uint8_t> ivVec;
612     const size_t kIvSize = 16;
613     ivVec.appendArray(iv, kIvSize);
614 
615     Vector<uint8_t> outputVec;
616     if (encrypt) {
617         status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
618     } else {
619         status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
620     }
621     if (status == OK) {
622         memcpy(output, outputVec.array(), outputVec.size());
623     }
624     return translateStatus(status);
625 }
626 
627 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)628 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
629         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
630         const uint8_t *input, uint8_t *output, size_t dataSize) {
631     if (!sessionId) {
632         return AMEDIA_ERROR_INVALID_PARAMETER;
633     }
634     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
635             input, output, dataSize, true);
636 }
637 
638 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)639 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
640         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
641         const uint8_t *input, uint8_t *output, size_t dataSize) {
642     if (!sessionId) {
643         return AMEDIA_ERROR_INVALID_PARAMETER;
644     }
645     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
646             input, output, dataSize, false);
647 }
648 
649 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)650 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
651         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
652         uint8_t *signature, size_t *signatureSize) {
653 
654     if (!mObj || mObj->mDrm == NULL) {
655         return AMEDIA_ERROR_INVALID_OBJECT;
656     }
657     if (!sessionId) {
658         return AMEDIA_ERROR_INVALID_PARAMETER;
659     }
660     List<idvec_t>::iterator iter;
661     if (!findId(mObj, *sessionId, iter)) {
662         return AMEDIA_DRM_SESSION_NOT_OPENED;
663     }
664 
665     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
666     if (status != OK) {
667         return translateStatus(status);
668     }
669 
670     Vector<uint8_t> keyIdVec;
671     const size_t kKeyIdSize = 16;
672     keyIdVec.appendArray(keyId, kKeyIdSize);
673 
674     Vector<uint8_t> messageVec;
675     messageVec.appendArray(message, messageSize);
676 
677     Vector<uint8_t> signatureVec;
678     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
679     if (signatureVec.size() > *signatureSize) {
680         return AMEDIA_DRM_SHORT_BUFFER;
681     }
682     if (status == OK) {
683         memcpy(signature, signatureVec.array(), signatureVec.size());
684     }
685     return translateStatus(status);
686 }
687 
688 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)689 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
690         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
691         const uint8_t *signature, size_t signatureSize) {
692 
693     if (!mObj || mObj->mDrm == NULL) {
694         return AMEDIA_ERROR_INVALID_OBJECT;
695     }
696     if (!sessionId) {
697         return AMEDIA_ERROR_INVALID_PARAMETER;
698     }
699     List<idvec_t>::iterator iter;
700     if (!findId(mObj, *sessionId, iter)) {
701         return AMEDIA_DRM_SESSION_NOT_OPENED;
702     }
703 
704     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
705     if (status != OK) {
706         return translateStatus(status);
707     }
708 
709     Vector<uint8_t> keyIdVec;
710     const size_t kKeyIdSize = 16;
711     keyIdVec.appendArray(keyId, kKeyIdSize);
712 
713     Vector<uint8_t> messageVec;
714     messageVec.appendArray(message, messageSize);
715 
716     Vector<uint8_t> signatureVec;
717     signatureVec.appendArray(signature, signatureSize);
718 
719     bool match;
720     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
721     if (status == OK) {
722         return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
723     }
724     return translateStatus(status);
725 }
726 
727 } // extern "C"
728 
729