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