NdkMediaDrm.cpp revision 63141c4356b4f885d3926247df508df3515e41a7
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    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
257EXPORT
258media_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
275EXPORT
276media_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
326EXPORT
327media_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
358EXPORT
359media_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
377EXPORT
378media_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
398EXPORT
399media_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
432EXPORT
433media_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
454EXPORT
455media_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
471EXPORT
472media_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
501EXPORT
502media_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
518EXPORT
519media_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
540EXPORT
541media_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
563EXPORT
564media_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
574EXPORT
575media_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
586static 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
627EXPORT
628media_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
638EXPORT
639media_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
649EXPORT
650media_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
688EXPORT
689media_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