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: 45 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 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 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 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 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 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 201 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 202 AMediaDrm *mObj = new AMediaDrm(); 203 mObj->mDrm = CreateDrmFromUUID(uuid); 204 return mObj; 205 } 206 207 EXPORT 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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