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 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 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 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 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 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 196 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 197 AMediaDrm *mObj = new AMediaDrm(); 198 mObj->mDrm = CreateDrmFromUUID(uuid); 199 return mObj; 200 } 201 202 EXPORT 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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