Home | History | Annotate | Download | only in ndk
      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