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 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), 316 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); 317 if (status != OK) { 318 return translateStatus(status); 319 } else { 320 *keyRequest = mObj->mKeyRequest.array(); 321 *keyRequestSize = mObj->mKeyRequest.size(); 322 } 323 return AMEDIA_OK; 324 } 325 326 EXPORT 327 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope, 328 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) { 329 330 if (!mObj || mObj->mDrm == NULL) { 331 return AMEDIA_ERROR_INVALID_OBJECT; 332 } 333 if (!scope || !response || !responseSize || !keySetId) { 334 return AMEDIA_ERROR_INVALID_PARAMETER; 335 } 336 337 List<idvec_t>::iterator iter; 338 if (!findId(mObj, *scope, iter)) { 339 return AMEDIA_DRM_SESSION_NOT_OPENED; 340 } 341 Vector<uint8_t> mdResponse; 342 mdResponse.appendArray(response, responseSize); 343 344 Vector<uint8_t> mdKeySetId; 345 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); 346 if (status == OK) { 347 mObj->mIds.push_front(mdKeySetId); 348 List<idvec_t>::iterator iter = mObj->mIds.begin(); 349 keySetId->ptr = iter->array(); 350 keySetId->length = iter->size(); 351 } else { 352 keySetId->ptr = NULL; 353 keySetId->length = 0; 354 } 355 return AMEDIA_OK; 356 } 357 358 EXPORT 359 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 360 const AMediaDrmKeySetId *keySetId) { 361 362 if (!mObj || mObj->mDrm == NULL) { 363 return AMEDIA_ERROR_INVALID_OBJECT; 364 } 365 if (!sessionId || !keySetId) { 366 return AMEDIA_ERROR_INVALID_PARAMETER; 367 } 368 List<idvec_t>::iterator iter; 369 if (!findId(mObj, *sessionId, iter)) { 370 return AMEDIA_DRM_SESSION_NOT_OPENED; 371 } 372 Vector<uint8_t> keySet; 373 keySet.appendArray(keySetId->ptr, keySetId->length); 374 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); 375 } 376 377 EXPORT 378 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) { 379 if (!mObj || mObj->mDrm == NULL) { 380 return AMEDIA_ERROR_INVALID_OBJECT; 381 } 382 if (!keySetId) { 383 return AMEDIA_ERROR_INVALID_PARAMETER; 384 } 385 List<idvec_t>::iterator iter; 386 status_t status; 387 if (!findId(mObj, *keySetId, iter)) { 388 Vector<uint8_t> keySet; 389 keySet.appendArray(keySetId->ptr, keySetId->length); 390 status = mObj->mDrm->removeKeys(keySet); 391 } else { 392 status = mObj->mDrm->removeKeys(*iter); 393 mObj->mIds.erase(iter); 394 } 395 return translateStatus(status); 396 } 397 398 EXPORT 399 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 400 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) { 401 402 if (!mObj || mObj->mDrm == NULL) { 403 return AMEDIA_ERROR_INVALID_OBJECT; 404 } 405 if (!sessionId || !numPairs) { 406 return AMEDIA_ERROR_INVALID_PARAMETER; 407 } 408 List<idvec_t>::iterator iter; 409 if (!findId(mObj, *sessionId, iter)) { 410 return AMEDIA_DRM_SESSION_NOT_OPENED; 411 } 412 413 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); 414 if (status != OK) { 415 *numPairs = 0; 416 return translateStatus(status); 417 } 418 419 if (mObj->mQueryResults.size() > *numPairs) { 420 *numPairs = mObj->mQueryResults.size(); 421 return AMEDIA_DRM_SHORT_BUFFER; 422 } 423 424 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { 425 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); 426 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); 427 } 428 *numPairs = mObj->mQueryResults.size(); 429 return AMEDIA_OK; 430 } 431 432 EXPORT 433 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest, 434 size_t *provisionRequestSize, const char **serverUrl) { 435 if (!mObj || mObj->mDrm == NULL) { 436 return AMEDIA_ERROR_INVALID_OBJECT; 437 } 438 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) { 439 return AMEDIA_ERROR_INVALID_PARAMETER; 440 } 441 442 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), 443 mObj->mProvisionRequest, mObj->mProvisionUrl); 444 if (status != OK) { 445 return translateStatus(status); 446 } else { 447 *provisionRequest = mObj->mProvisionRequest.array(); 448 *provisionRequestSize = mObj->mProvisionRequest.size(); 449 *serverUrl = mObj->mProvisionUrl.string(); 450 } 451 return AMEDIA_OK; 452 } 453 454 EXPORT 455 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, 456 const uint8_t *response, size_t responseSize) { 457 if (!mObj || mObj->mDrm == NULL) { 458 return AMEDIA_ERROR_INVALID_OBJECT; 459 } 460 if (!response || !responseSize) { 461 return AMEDIA_ERROR_INVALID_PARAMETER; 462 } 463 464 Vector<uint8_t> mdResponse; 465 mdResponse.appendArray(response, responseSize); 466 467 Vector<uint8_t> unused; 468 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); 469 } 470 471 EXPORT 472 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, 473 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) { 474 475 if (!mObj || mObj->mDrm == NULL) { 476 return AMEDIA_ERROR_INVALID_OBJECT; 477 } 478 if (!numSecureStops) { 479 return AMEDIA_ERROR_INVALID_PARAMETER; 480 } 481 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); 482 if (status != OK) { 483 *numSecureStops = 0; 484 return translateStatus(status); 485 } 486 if (*numSecureStops < mObj->mSecureStops.size()) { 487 return AMEDIA_DRM_SHORT_BUFFER; 488 } 489 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin(); 490 size_t i = 0; 491 while (iter != mObj->mSecureStops.end()) { 492 secureStops[i].ptr = iter->array(); 493 secureStops[i].length = iter->size(); 494 ++iter; 495 ++i; 496 } 497 *numSecureStops = mObj->mSecureStops.size(); 498 return AMEDIA_OK; 499 } 500 501 EXPORT 502 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, 503 const AMediaDrmSecureStop *ssRelease) { 504 505 if (!mObj || mObj->mDrm == NULL) { 506 return AMEDIA_ERROR_INVALID_OBJECT; 507 } 508 if (!ssRelease) { 509 return AMEDIA_ERROR_INVALID_PARAMETER; 510 } 511 512 Vector<uint8_t> release; 513 release.appendArray(ssRelease->ptr, ssRelease->length); 514 return translateStatus(mObj->mDrm->releaseSecureStops(release)); 515 } 516 517 518 EXPORT 519 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, 520 const char **propertyValue) { 521 522 if (!mObj || mObj->mDrm == NULL) { 523 return AMEDIA_ERROR_INVALID_OBJECT; 524 } 525 if (!propertyName || !propertyValue) { 526 return AMEDIA_ERROR_INVALID_PARAMETER; 527 } 528 529 status_t status = mObj->mDrm->getPropertyString(String8(propertyName), 530 mObj->mPropertyString); 531 532 if (status == OK) { 533 *propertyValue = mObj->mPropertyString.string(); 534 } else { 535 *propertyValue = NULL; 536 } 537 return translateStatus(status); 538 } 539 540 EXPORT 541 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, 542 const char *propertyName, AMediaDrmByteArray *propertyValue) { 543 if (!mObj || mObj->mDrm == NULL) { 544 return AMEDIA_ERROR_INVALID_OBJECT; 545 } 546 if (!propertyName || !propertyValue) { 547 return AMEDIA_ERROR_INVALID_PARAMETER; 548 } 549 550 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), 551 mObj->mPropertyByteArray); 552 553 if (status == OK) { 554 propertyValue->ptr = mObj->mPropertyByteArray.array(); 555 propertyValue->length = mObj->mPropertyByteArray.size(); 556 } else { 557 propertyValue->ptr = NULL; 558 propertyValue->length = 0; 559 } 560 return translateStatus(status); 561 } 562 563 EXPORT 564 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, 565 const char *propertyName, const char *value) { 566 if (!mObj || mObj->mDrm == NULL) { 567 return AMEDIA_ERROR_INVALID_OBJECT; 568 } 569 570 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), 571 String8(value))); 572 } 573 574 EXPORT 575 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, 576 const char *propertyName, const uint8_t *value, size_t valueSize) { 577 578 Vector<uint8_t> byteArray; 579 byteArray.appendArray(value, valueSize); 580 581 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName), 582 byteArray)); 583 } 584 585 586 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj, 587 const AMediaDrmSessionId &sessionId, 588 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 589 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { 590 591 if (!mObj || mObj->mDrm == NULL) { 592 return AMEDIA_ERROR_INVALID_OBJECT; 593 } 594 List<idvec_t>::iterator iter; 595 if (!findId(mObj, sessionId, iter)) { 596 return AMEDIA_DRM_SESSION_NOT_OPENED; 597 } 598 599 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); 600 if (status != OK) { 601 return translateStatus(status); 602 } 603 604 Vector<uint8_t> keyIdVec; 605 const size_t kKeyIdSize = 16; 606 keyIdVec.appendArray(keyId, kKeyIdSize); 607 608 Vector<uint8_t> inputVec; 609 inputVec.appendArray(input, dataSize); 610 611 Vector<uint8_t> ivVec; 612 const size_t kIvSize = 16; 613 ivVec.appendArray(iv, kIvSize); 614 615 Vector<uint8_t> outputVec; 616 if (encrypt) { 617 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 618 } else { 619 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 620 } 621 if (status == OK) { 622 memcpy(output, outputVec.array(), outputVec.size()); 623 } 624 return translateStatus(status); 625 } 626 627 EXPORT 628 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 629 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 630 const uint8_t *input, uint8_t *output, size_t dataSize) { 631 if (!sessionId) { 632 return AMEDIA_ERROR_INVALID_PARAMETER; 633 } 634 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, 635 input, output, dataSize, true); 636 } 637 638 EXPORT 639 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 640 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 641 const uint8_t *input, uint8_t *output, size_t dataSize) { 642 if (!sessionId) { 643 return AMEDIA_ERROR_INVALID_PARAMETER; 644 } 645 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, 646 input, output, dataSize, false); 647 } 648 649 EXPORT 650 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 651 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, 652 uint8_t *signature, size_t *signatureSize) { 653 654 if (!mObj || mObj->mDrm == NULL) { 655 return AMEDIA_ERROR_INVALID_OBJECT; 656 } 657 if (!sessionId) { 658 return AMEDIA_ERROR_INVALID_PARAMETER; 659 } 660 List<idvec_t>::iterator iter; 661 if (!findId(mObj, *sessionId, iter)) { 662 return AMEDIA_DRM_SESSION_NOT_OPENED; 663 } 664 665 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 666 if (status != OK) { 667 return translateStatus(status); 668 } 669 670 Vector<uint8_t> keyIdVec; 671 const size_t kKeyIdSize = 16; 672 keyIdVec.appendArray(keyId, kKeyIdSize); 673 674 Vector<uint8_t> messageVec; 675 messageVec.appendArray(message, messageSize); 676 677 Vector<uint8_t> signatureVec; 678 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); 679 if (signatureVec.size() > *signatureSize) { 680 return AMEDIA_DRM_SHORT_BUFFER; 681 } 682 if (status == OK) { 683 memcpy(signature, signatureVec.array(), signatureVec.size()); 684 } 685 return translateStatus(status); 686 } 687 688 EXPORT 689 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 690 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, 691 const uint8_t *signature, size_t signatureSize) { 692 693 if (!mObj || mObj->mDrm == NULL) { 694 return AMEDIA_ERROR_INVALID_OBJECT; 695 } 696 if (!sessionId) { 697 return AMEDIA_ERROR_INVALID_PARAMETER; 698 } 699 List<idvec_t>::iterator iter; 700 if (!findId(mObj, *sessionId, iter)) { 701 return AMEDIA_DRM_SESSION_NOT_OPENED; 702 } 703 704 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 705 if (status != OK) { 706 return translateStatus(status); 707 } 708 709 Vector<uint8_t> keyIdVec; 710 const size_t kKeyIdSize = 16; 711 keyIdVec.appendArray(keyId, kKeyIdSize); 712 713 Vector<uint8_t> messageVec; 714 messageVec.appendArray(message, messageSize); 715 716 Vector<uint8_t> signatureVec; 717 signatureVec.appendArray(signature, signatureSize); 718 719 bool match; 720 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); 721 if (status == OK) { 722 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED; 723 } 724 return translateStatus(status); 725 } 726 727 } // extern "C" 728 729