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: 46 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 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 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 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 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 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 198 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 199 AMediaDrm *mObj = new AMediaDrm(); 200 mObj->mDrm = CreateDrmFromUUID(uuid); 201 return mObj; 202 } 203 204 EXPORT 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 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 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 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 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 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 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 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 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 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.keyAt(i).string(); 425 } 426 *numPairs = mObj->mQueryResults.size(); 427 return AMEDIA_OK; 428 } 429 430 EXPORT 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 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 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 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 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 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 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 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 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 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 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 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 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