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