NdkMediaDrm.cpp revision 7c96d53a65085f42ac2b6d416cbc16fd36ed72ff
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 34using namespace android; 35 36typedef Vector<uint8_t> idvec_t; 37 38struct DrmListener: virtual public BnDrmClient 39{ 40private: 41 AMediaDrm *mObj; 42 AMediaDrmEventListener mListener; 43 44public: 45 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {} 46 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj); 47}; 48 49struct 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 63void 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 111extern "C" { 112 113static 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 149static 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 172static 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 188EXPORT 189bool 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 200EXPORT 201AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 202 AMediaDrm *mObj = new AMediaDrm(); 203 mObj->mDrm = CreateDrmFromUUID(uuid); 204 return mObj; 205} 206 207EXPORT 208void 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 217EXPORT 218media_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 228static 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 238EXPORT 239media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) { 240 if (!mObj || mObj->mDrm == NULL) { 241 return AMEDIA_ERROR_INVALID_OBJECT; 242 } 243 Vector<uint8_t> session; 244 status_t status = mObj->mDrm->openSession(session); 245 if (status == OK) { 246 mObj->mIds.push_front(session); 247 List<idvec_t>::iterator iter = mObj->mIds.begin(); 248 sessionId.ptr = iter->array(); 249 sessionId.length = iter->size(); 250 } 251 return AMEDIA_OK; 252} 253 254EXPORT 255media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) { 256 if (!mObj || mObj->mDrm == NULL) { 257 return AMEDIA_ERROR_INVALID_OBJECT; 258 } 259 260 List<idvec_t>::iterator iter; 261 if (!findId(mObj, sessionId, iter)) { 262 return AMEDIA_DRM_SESSION_NOT_OPENED; 263 } 264 mObj->mDrm->closeSession(*iter); 265 mObj->mIds.erase(iter); 266 return AMEDIA_OK; 267} 268 269EXPORT 270media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope, 271 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, 272 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, 273 const uint8_t *&keyRequest, size_t &keyRequestSize) { 274 275 if (!mObj || mObj->mDrm == NULL) { 276 return AMEDIA_ERROR_INVALID_OBJECT; 277 } 278 if (!mimeType) { 279 return AMEDIA_ERROR_INVALID_PARAMETER; 280 } 281 282 List<idvec_t>::iterator iter; 283 if (!findId(mObj, scope, iter)) { 284 return AMEDIA_DRM_SESSION_NOT_OPENED; 285 } 286 287 Vector<uint8_t> mdInit; 288 mdInit.appendArray(init, initSize); 289 DrmPlugin::KeyType mdKeyType; 290 switch (keyType) { 291 case KEY_TYPE_STREAMING: 292 mdKeyType = DrmPlugin::kKeyType_Streaming; 293 break; 294 case KEY_TYPE_OFFLINE: 295 mdKeyType = DrmPlugin::kKeyType_Offline; 296 break; 297 case KEY_TYPE_RELEASE: 298 mdKeyType = DrmPlugin::kKeyType_Release; 299 break; 300 default: 301 return AMEDIA_ERROR_INVALID_PARAMETER; 302 } 303 KeyedVector<String8, String8> mdOptionalParameters; 304 for (size_t i = 0; i < numOptionalParameters; i++) { 305 mdOptionalParameters.add(String8(optionalParameters[i].mKey), 306 String8(optionalParameters[i].mValue)); 307 } 308 String8 defaultUrl; 309 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), 310 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl); 311 if (status != OK) { 312 return translateStatus(status); 313 } else { 314 keyRequest = mObj->mKeyRequest.array(); 315 keyRequestSize = mObj->mKeyRequest.size(); 316 } 317 return AMEDIA_OK; 318} 319 320EXPORT 321media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope, 322 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) { 323 324 if (!mObj || mObj->mDrm == NULL) { 325 return AMEDIA_ERROR_INVALID_OBJECT; 326 } 327 if (!response || !responseSize) { 328 return AMEDIA_ERROR_INVALID_PARAMETER; 329 } 330 331 List<idvec_t>::iterator iter; 332 if (!findId(mObj, scope, iter)) { 333 return AMEDIA_DRM_SESSION_NOT_OPENED; 334 } 335 Vector<uint8_t> mdResponse; 336 mdResponse.appendArray(response, responseSize); 337 338 Vector<uint8_t> mdKeySetId; 339 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); 340 if (status == OK) { 341 mObj->mIds.push_front(mdKeySetId); 342 List<idvec_t>::iterator iter = mObj->mIds.begin(); 343 keySetId.ptr = iter->array(); 344 keySetId.length = iter->size(); 345 } else { 346 keySetId.ptr = NULL; 347 keySetId.length = 0; 348 } 349 return AMEDIA_OK; 350} 351 352EXPORT 353media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 354 const AMediaDrmKeySetId &keySetId) { 355 356 if (!mObj || mObj->mDrm == NULL) { 357 return AMEDIA_ERROR_INVALID_OBJECT; 358 } 359 List<idvec_t>::iterator iter; 360 if (!findId(mObj, sessionId, iter)) { 361 return AMEDIA_DRM_SESSION_NOT_OPENED; 362 } 363 Vector<uint8_t> keySet; 364 keySet.appendArray(keySetId.ptr, keySetId.length); 365 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); 366} 367 368EXPORT 369media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) { 370 if (!mObj || mObj->mDrm == NULL) { 371 return AMEDIA_ERROR_INVALID_OBJECT; 372 } 373 List<idvec_t>::iterator iter; 374 status_t status; 375 if (!findId(mObj, keySetId, iter)) { 376 Vector<uint8_t> keySet; 377 keySet.appendArray(keySetId.ptr, keySetId.length); 378 status = mObj->mDrm->removeKeys(keySet); 379 } else { 380 status = mObj->mDrm->removeKeys(*iter); 381 mObj->mIds.erase(iter); 382 } 383 return translateStatus(status); 384} 385 386EXPORT 387media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 388 AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) { 389 390 if (!mObj || mObj->mDrm == NULL) { 391 return AMEDIA_ERROR_INVALID_OBJECT; 392 } 393 List<idvec_t>::iterator iter; 394 if (!findId(mObj, sessionId, iter)) { 395 return AMEDIA_DRM_SESSION_NOT_OPENED; 396 } 397 398 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); 399 if (status != OK) { 400 numPairs = 0; 401 return translateStatus(status); 402 } 403 404 if (mObj->mQueryResults.size() > numPairs) { 405 numPairs = mObj->mQueryResults.size(); 406 return AMEDIA_DRM_SHORT_BUFFER; 407 } 408 409 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { 410 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); 411 keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string(); 412 } 413 numPairs = mObj->mQueryResults.size(); 414 return AMEDIA_OK; 415} 416 417EXPORT 418media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest, 419 size_t &provisionRequestSize, const char *&serverUrl) { 420 if (!mObj || mObj->mDrm == NULL) { 421 return AMEDIA_ERROR_INVALID_OBJECT; 422 } 423 if (!provisionRequestSize || !serverUrl) { 424 return AMEDIA_ERROR_INVALID_PARAMETER; 425 } 426 427 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), 428 mObj->mProvisionRequest, mObj->mProvisionUrl); 429 if (status != OK) { 430 return translateStatus(status); 431 } else { 432 provisionRequest = mObj->mProvisionRequest.array(); 433 provisionRequestSize = mObj->mProvisionRequest.size(); 434 serverUrl = mObj->mProvisionUrl.string(); 435 } 436 return AMEDIA_OK; 437} 438 439EXPORT 440media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, 441 const uint8_t *response, size_t responseSize) { 442 if (!mObj || mObj->mDrm == NULL) { 443 return AMEDIA_ERROR_INVALID_OBJECT; 444 } 445 if (!response || !responseSize) { 446 return AMEDIA_ERROR_INVALID_PARAMETER; 447 } 448 449 Vector<uint8_t> mdResponse; 450 mdResponse.appendArray(response, responseSize); 451 452 Vector<uint8_t> unused; 453 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); 454} 455 456EXPORT 457media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, 458 AMediaDrmSecureStop *secureStops, size_t &numSecureStops) { 459 460 if (!mObj || mObj->mDrm == NULL) { 461 return AMEDIA_ERROR_INVALID_OBJECT; 462 } 463 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); 464 if (status != OK) { 465 numSecureStops = 0; 466 return translateStatus(status); 467 } 468 if (numSecureStops < mObj->mSecureStops.size()) { 469 return AMEDIA_DRM_SHORT_BUFFER; 470 } 471 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin(); 472 size_t i = 0; 473 while (iter != mObj->mSecureStops.end()) { 474 secureStops[i].ptr = iter->array(); 475 secureStops[i].length = iter->size(); 476 ++iter; 477 ++i; 478 } 479 numSecureStops = mObj->mSecureStops.size(); 480 return AMEDIA_OK; 481} 482 483EXPORT 484media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, 485 const AMediaDrmSecureStop &ssRelease) { 486 487 if (!mObj || mObj->mDrm == NULL) { 488 return AMEDIA_ERROR_INVALID_OBJECT; 489 } 490 491 Vector<uint8_t> release; 492 release.appendArray(ssRelease.ptr, ssRelease.length); 493 return translateStatus(mObj->mDrm->releaseSecureStops(release)); 494} 495 496 497EXPORT 498media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, 499 const char *&propertyValue) { 500 501 if (!mObj || mObj->mDrm == NULL) { 502 return AMEDIA_ERROR_INVALID_OBJECT; 503 } 504 505 status_t status = mObj->mDrm->getPropertyString(String8(propertyName), 506 mObj->mPropertyString); 507 508 if (status == OK) { 509 propertyValue = mObj->mPropertyString.string(); 510 } else { 511 propertyValue = NULL; 512 } 513 return translateStatus(status); 514} 515 516EXPORT 517media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, 518 const char *propertyName, AMediaDrmByteArray &propertyValue) { 519 if (!mObj || mObj->mDrm == NULL) { 520 return AMEDIA_ERROR_INVALID_OBJECT; 521 } 522 523 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), 524 mObj->mPropertyByteArray); 525 526 if (status == OK) { 527 propertyValue.ptr = mObj->mPropertyByteArray.array(); 528 propertyValue.length = mObj->mPropertyByteArray.size(); 529 } else { 530 propertyValue.ptr = NULL; 531 propertyValue.length = 0; 532 } 533 return translateStatus(status); 534} 535 536EXPORT 537media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, 538 const char *propertyName, const char *value) { 539 if (!mObj || mObj->mDrm == NULL) { 540 return AMEDIA_ERROR_INVALID_OBJECT; 541 } 542 543 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), 544 String8(value))); 545} 546 547EXPORT 548media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, 549 const char *propertyName, const uint8_t *value, size_t valueSize) { 550 551 Vector<uint8_t> byteArray; 552 byteArray.appendArray(value, valueSize); 553 554 return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName), 555 byteArray)); 556} 557 558 559static media_status_t encrypt_decrypt_common(AMediaDrm *mObj, 560 const AMediaDrmSessionId &sessionId, 561 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 562 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { 563 564 if (!mObj || mObj->mDrm == NULL) { 565 return AMEDIA_ERROR_INVALID_OBJECT; 566 } 567 List<idvec_t>::iterator iter; 568 if (!findId(mObj, sessionId, iter)) { 569 return AMEDIA_DRM_SESSION_NOT_OPENED; 570 } 571 572 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); 573 if (status != OK) { 574 return translateStatus(status); 575 } 576 577 Vector<uint8_t> keyIdVec; 578 const size_t kKeyIdSize = 16; 579 keyIdVec.appendArray(keyId, kKeyIdSize); 580 581 Vector<uint8_t> inputVec; 582 inputVec.appendArray(input, dataSize); 583 584 Vector<uint8_t> ivVec; 585 const size_t kIvSize = 16; 586 ivVec.appendArray(iv, kIvSize); 587 588 Vector<uint8_t> outputVec; 589 if (encrypt) { 590 status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 591 } else { 592 status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 593 } 594 if (status == OK) { 595 memcpy(output, outputVec.array(), outputVec.size()); 596 } 597 return translateStatus(status); 598} 599 600EXPORT 601media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 602 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 603 const uint8_t *input, uint8_t *output, size_t dataSize) { 604 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 605 input, output, dataSize, true); 606} 607 608EXPORT 609media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 610 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 611 const uint8_t *input, uint8_t *output, size_t dataSize) { 612 return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv, 613 input, output, dataSize, false); 614} 615 616EXPORT 617media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 618 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, 619 uint8_t *signature, size_t *signatureSize) { 620 621 if (!mObj || mObj->mDrm == NULL) { 622 return AMEDIA_ERROR_INVALID_OBJECT; 623 } 624 List<idvec_t>::iterator iter; 625 if (!findId(mObj, sessionId, iter)) { 626 return AMEDIA_DRM_SESSION_NOT_OPENED; 627 } 628 629 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 630 if (status != OK) { 631 return translateStatus(status); 632 } 633 634 Vector<uint8_t> keyIdVec; 635 const size_t kKeyIdSize = 16; 636 keyIdVec.appendArray(keyId, kKeyIdSize); 637 638 Vector<uint8_t> messageVec; 639 messageVec.appendArray(message, messageSize); 640 641 Vector<uint8_t> signatureVec; 642 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); 643 if (signatureVec.size() > *signatureSize) { 644 return AMEDIA_DRM_SHORT_BUFFER; 645 } 646 if (status == OK) { 647 memcpy(signature, signatureVec.array(), signatureVec.size()); 648 } 649 return translateStatus(status); 650} 651 652EXPORT 653media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId, 654 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, 655 const uint8_t *signature, size_t signatureSize) { 656 657 if (!mObj || mObj->mDrm == NULL) { 658 return AMEDIA_ERROR_INVALID_OBJECT; 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 signatureVec.appendArray(signature, signatureSize); 679 680 bool match; 681 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); 682 if (status == OK) { 683 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED; 684 } 685 return translateStatus(status); 686} 687 688} // extern "C" 689 690