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