NdkMediaDrm.cpp revision 3305b99ec3804c740aecd2ab6d1edd5c6137b7c6
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 mediadrm_status_t translateStatus(status_t status) {
114    mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR;
115    switch (status) {
116        case OK:
117            result = MEDIADRM_OK;
118            break;
119        case android::ERROR_DRM_NOT_PROVISIONED:
120            result = MEDIADRM_NOT_PROVISIONED_ERROR;
121            break;
122        case android::ERROR_DRM_RESOURCE_BUSY:
123            result = MEDIADRM_RESOURCE_BUSY_ERROR;
124            break;
125        case android::ERROR_DRM_DEVICE_REVOKED:
126            result = MEDIADRM_DEVICE_REVOKED_ERROR;
127            break;
128        case android::ERROR_DRM_CANNOT_HANDLE:
129            result = MEDIADRM_INVALID_PARAMETER_ERROR;
130            break;
131        case android::ERROR_DRM_TAMPER_DETECTED:
132            result = MEDIADRM_TAMPER_DETECTED_ERROR;
133            break;
134        case android::ERROR_DRM_SESSION_NOT_OPENED:
135            result = MEDIADRM_SESSION_NOT_OPENED_ERROR;
136            break;
137        case android::ERROR_DRM_NO_LICENSE:
138            result = MEDIADRM_NEED_KEY_ERROR;
139            break;
140        case android::ERROR_DRM_LICENSE_EXPIRED:
141            result = MEDIADRM_LICENSE_EXPIRED_ERROR;
142            break;
143        default:
144            result = MEDIADRM_UNKNOWN_ERROR;
145            break;
146    }
147    return result;
148}
149
150static sp<IDrm> CreateDrm() {
151    sp<IServiceManager> sm = defaultServiceManager();
152
153    sp<IBinder> binder =
154        sm->getService(String16("media.player"));
155
156    sp<IMediaPlayerService> service =
157        interface_cast<IMediaPlayerService>(binder);
158
159    if (service == NULL) {
160        return NULL;
161    }
162
163    sp<IDrm> drm = service->makeDrm();
164
165    if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
166        return NULL;
167    }
168
169    return drm;
170}
171
172
173static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
174    sp<IDrm> drm = CreateDrm();
175
176    if (drm == NULL) {
177        return NULL;
178    }
179
180    status_t err = drm->createPlugin(uuid);
181
182    if (err != OK) {
183        return NULL;
184    }
185
186    return drm;
187}
188
189EXPORT
190bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
191    sp<IDrm> drm = CreateDrm();
192
193    if (drm == NULL) {
194        return false;
195    }
196
197    String8 mimeStr = mimeType ? String8(mimeType) : String8("");
198    return drm->isCryptoSchemeSupported(uuid, mimeStr);
199}
200
201EXPORT
202AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
203    AMediaDrm *mObj = new AMediaDrm();
204    mObj->mDrm = CreateDrmFromUUID(uuid);
205    return mObj;
206}
207
208EXPORT
209void AMediaDrm_release(AMediaDrm *mObj) {
210    if (mObj->mDrm != NULL) {
211        mObj->mDrm->setListener(NULL);
212        mObj->mDrm->destroyPlugin();
213        mObj->mDrm.clear();
214    }
215    delete mObj;
216}
217
218EXPORT
219mediadrm_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
220    if (!mObj || mObj->mDrm == NULL) {
221        return MEDIADRM_INVALID_OBJECT_ERROR;
222    }
223    mObj->mListener = new DrmListener(mObj, listener);
224    mObj->mDrm->setListener(mObj->mListener);
225    return MEDIADRM_OK;
226}
227
228
229static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
230    iter = mObj->mIds.begin();
231    while (iter != mObj->mIds.end()) {
232        if (iter->array() == id.ptr && iter->size() == id.length) {
233            return true;
234        }
235    }
236    return false;
237}
238
239EXPORT
240mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
241    if (!mObj || mObj->mDrm == NULL) {
242        return MEDIADRM_INVALID_OBJECT_ERROR;
243    }
244    Vector<uint8_t> session;
245    status_t status = mObj->mDrm->openSession(session);
246    if (status == OK) {
247        mObj->mIds.push_front(session);
248        List<idvec_t>::iterator iter = mObj->mIds.begin();
249        sessionId.ptr = iter->array();
250        sessionId.length = iter->size();
251    }
252    return MEDIADRM_OK;
253}
254
255EXPORT
256mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
257    if (!mObj || mObj->mDrm == NULL) {
258        return MEDIADRM_INVALID_OBJECT_ERROR;
259    }
260
261    List<idvec_t>::iterator iter;
262    if (!findId(mObj, sessionId, iter)) {
263        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
264    }
265    mObj->mDrm->closeSession(*iter);
266    mObj->mIds.erase(iter);
267    return MEDIADRM_OK;
268}
269
270EXPORT
271mediadrm_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 MEDIADRM_INVALID_OBJECT_ERROR;
278    }
279    if (!mimeType) {
280        return MEDIADRM_INVALID_PARAMETER_ERROR;
281    }
282
283    List<idvec_t>::iterator iter;
284    if (!findId(mObj, scope, iter)) {
285        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
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 MEDIADRM_INVALID_PARAMETER_ERROR;
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    status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
311            mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
312    if (status != OK) {
313        return translateStatus(status);
314    } else {
315        keyRequest = mObj->mKeyRequest.array();
316        keyRequestSize = mObj->mKeyRequest.size();
317    }
318    return MEDIADRM_OK;
319}
320
321EXPORT
322mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
323        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
324
325    if (!mObj || mObj->mDrm == NULL) {
326        return MEDIADRM_INVALID_OBJECT_ERROR;
327    }
328    if (!response || !responseSize) {
329        return MEDIADRM_INVALID_PARAMETER_ERROR;
330    }
331
332    List<idvec_t>::iterator iter;
333    if (!findId(mObj, scope, iter)) {
334        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
335    }
336    Vector<uint8_t> mdResponse;
337    mdResponse.appendArray(response, responseSize);
338
339    Vector<uint8_t> mdKeySetId;
340    status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
341    if (status == OK) {
342        mObj->mIds.push_front(mdKeySetId);
343        List<idvec_t>::iterator iter = mObj->mIds.begin();
344        keySetId.ptr = iter->array();
345        keySetId.length = iter->size();
346    } else {
347        keySetId.ptr = NULL;
348        keySetId.length = 0;
349    }
350    return MEDIADRM_OK;
351}
352
353EXPORT
354mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
355        const AMediaDrmKeySetId &keySetId) {
356
357    if (!mObj || mObj->mDrm == NULL) {
358        return MEDIADRM_INVALID_OBJECT_ERROR;
359    }
360    List<idvec_t>::iterator iter;
361    if (!findId(mObj, sessionId, iter)) {
362        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
363    }
364    Vector<uint8_t> keySet;
365    keySet.appendArray(keySetId.ptr, keySetId.length);
366    return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
367}
368
369EXPORT
370mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
371    if (!mObj || mObj->mDrm == NULL) {
372        return MEDIADRM_INVALID_OBJECT_ERROR;
373    }
374    List<idvec_t>::iterator iter;
375    status_t status;
376    if (!findId(mObj, keySetId, iter)) {
377        Vector<uint8_t> keySet;
378        keySet.appendArray(keySetId.ptr, keySetId.length);
379        status = mObj->mDrm->removeKeys(keySet);
380    } else {
381        status = mObj->mDrm->removeKeys(*iter);
382        mObj->mIds.erase(iter);
383    }
384    return translateStatus(status);
385}
386
387EXPORT
388mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
389        AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
390
391    if (!mObj || mObj->mDrm == NULL) {
392        return MEDIADRM_INVALID_OBJECT_ERROR;
393    }
394    List<idvec_t>::iterator iter;
395    if (!findId(mObj, sessionId, iter)) {
396        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
397    }
398
399    status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
400    if (status != OK) {
401        numPairs = 0;
402        return translateStatus(status);
403    }
404
405    if (mObj->mQueryResults.size() > numPairs) {
406        numPairs = mObj->mQueryResults.size();
407        return MEDIADRM_SHORT_BUFFER;
408    }
409
410    for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
411        keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
412        keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
413    }
414    numPairs = mObj->mQueryResults.size();
415    return MEDIADRM_OK;
416}
417
418EXPORT
419mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
420        size_t &provisionRequestSize, const char *&serverUrl) {
421    if (!mObj || mObj->mDrm == NULL) {
422        return MEDIADRM_INVALID_OBJECT_ERROR;
423    }
424    if (!provisionRequestSize || !serverUrl) {
425        return MEDIADRM_INVALID_PARAMETER_ERROR;
426    }
427
428    status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
429            mObj->mProvisionRequest, mObj->mProvisionUrl);
430    if (status != OK) {
431        return translateStatus(status);
432    } else {
433        provisionRequest = mObj->mProvisionRequest.array();
434        provisionRequestSize = mObj->mProvisionRequest.size();
435        serverUrl = mObj->mProvisionUrl.string();
436    }
437    return MEDIADRM_OK;
438}
439
440EXPORT
441mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
442        const uint8_t *response, size_t responseSize) {
443    if (!mObj || mObj->mDrm == NULL) {
444        return MEDIADRM_INVALID_OBJECT_ERROR;
445    }
446    if (!response || !responseSize) {
447        return MEDIADRM_INVALID_PARAMETER_ERROR;
448    }
449
450    Vector<uint8_t> mdResponse;
451    mdResponse.appendArray(response, responseSize);
452
453    Vector<uint8_t> unused;
454    return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
455}
456
457EXPORT
458mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
459        AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
460
461    if (!mObj || mObj->mDrm == NULL) {
462        return MEDIADRM_INVALID_OBJECT_ERROR;
463    }
464    status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
465    if (status != OK) {
466        numSecureStops = 0;
467        return translateStatus(status);
468    }
469    if (numSecureStops < mObj->mSecureStops.size()) {
470        return MEDIADRM_SHORT_BUFFER;
471    }
472    List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
473    size_t i = 0;
474    while (iter != mObj->mSecureStops.end()) {
475        secureStops[i].ptr = iter->array();
476        secureStops[i].length = iter->size();
477        ++iter;
478        ++i;
479    }
480    numSecureStops = mObj->mSecureStops.size();
481    return MEDIADRM_OK;
482}
483
484EXPORT
485mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
486        const AMediaDrmSecureStop &ssRelease) {
487
488    if (!mObj || mObj->mDrm == NULL) {
489        return MEDIADRM_INVALID_OBJECT_ERROR;
490    }
491
492    Vector<uint8_t> release;
493    release.appendArray(ssRelease.ptr, ssRelease.length);
494    return translateStatus(mObj->mDrm->releaseSecureStops(release));
495}
496
497
498EXPORT
499mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
500        const char *&propertyValue) {
501
502    if (!mObj || mObj->mDrm == NULL) {
503        return MEDIADRM_INVALID_OBJECT_ERROR;
504    }
505
506    status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
507            mObj->mPropertyString);
508
509    if (status == OK) {
510        propertyValue = mObj->mPropertyString.string();
511    } else {
512        propertyValue = NULL;
513    }
514    return translateStatus(status);
515}
516
517EXPORT
518mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
519        const char *propertyName, AMediaDrmByteArray &propertyValue) {
520    if (!mObj || mObj->mDrm == NULL) {
521        return MEDIADRM_INVALID_OBJECT_ERROR;
522    }
523
524    status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
525            mObj->mPropertyByteArray);
526
527    if (status == OK) {
528        propertyValue.ptr = mObj->mPropertyByteArray.array();
529        propertyValue.length = mObj->mPropertyByteArray.size();
530    } else {
531        propertyValue.ptr = NULL;
532        propertyValue.length = 0;
533    }
534    return translateStatus(status);
535}
536
537EXPORT
538mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
539        const char *propertyName, const char *value) {
540    if (!mObj || mObj->mDrm == NULL) {
541        return MEDIADRM_INVALID_OBJECT_ERROR;
542    }
543
544    return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
545                    String8(value)));
546}
547
548EXPORT
549mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
550        const char *propertyName, const uint8_t *value, size_t valueSize) {
551
552    Vector<uint8_t> byteArray;
553    byteArray.appendArray(value, valueSize);
554
555    return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
556                    byteArray));
557}
558
559
560static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj,
561        const AMediaDrmSessionId &sessionId,
562        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
563        const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
564
565    if (!mObj || mObj->mDrm == NULL) {
566        return MEDIADRM_INVALID_OBJECT_ERROR;
567    }
568    List<idvec_t>::iterator iter;
569    if (!findId(mObj, sessionId, iter)) {
570        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
571    }
572
573    status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
574    if (status != OK) {
575        return translateStatus(status);
576    }
577
578    Vector<uint8_t> keyIdVec;
579    const size_t kKeyIdSize = 16;
580    keyIdVec.appendArray(keyId, kKeyIdSize);
581
582    Vector<uint8_t> inputVec;
583    inputVec.appendArray(input, dataSize);
584
585    Vector<uint8_t> ivVec;
586    const size_t kIvSize = 16;
587    ivVec.appendArray(iv, kIvSize);
588
589    Vector<uint8_t> outputVec;
590    if (encrypt) {
591        status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
592    } else {
593        status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
594    }
595    if (status == OK) {
596        memcpy(output, outputVec.array(), outputVec.size());
597    }
598    return translateStatus(status);
599}
600
601EXPORT
602mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
603        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
604        const uint8_t *input, uint8_t *output, size_t dataSize) {
605    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
606            input, output, dataSize, true);
607}
608
609EXPORT
610mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
611        const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
612        const uint8_t *input, uint8_t *output, size_t dataSize) {
613    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
614            input, output, dataSize, false);
615}
616
617EXPORT
618mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
619        const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
620        uint8_t *signature, size_t *signatureSize) {
621
622    if (!mObj || mObj->mDrm == NULL) {
623        return MEDIADRM_INVALID_OBJECT_ERROR;
624    }
625    List<idvec_t>::iterator iter;
626    if (!findId(mObj, sessionId, iter)) {
627        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
628    }
629
630    status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
631    if (status != OK) {
632        return translateStatus(status);
633    }
634
635    Vector<uint8_t> keyIdVec;
636    const size_t kKeyIdSize = 16;
637    keyIdVec.appendArray(keyId, kKeyIdSize);
638
639    Vector<uint8_t> messageVec;
640    messageVec.appendArray(message, messageSize);
641
642    Vector<uint8_t> signatureVec;
643    status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
644    if (signatureVec.size() > *signatureSize) {
645        return MEDIADRM_SHORT_BUFFER;
646    }
647    if (status == OK) {
648        memcpy(signature, signatureVec.array(), signatureVec.size());
649    }
650    return translateStatus(status);
651}
652
653EXPORT
654mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
655        const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
656        const uint8_t *signature, size_t signatureSize) {
657
658    if (!mObj || mObj->mDrm == NULL) {
659        return MEDIADRM_INVALID_OBJECT_ERROR;
660    }
661    List<idvec_t>::iterator iter;
662    if (!findId(mObj, sessionId, iter)) {
663        return MEDIADRM_SESSION_NOT_OPENED_ERROR;
664    }
665
666    status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
667    if (status != OK) {
668        return translateStatus(status);
669    }
670
671    Vector<uint8_t> keyIdVec;
672    const size_t kKeyIdSize = 16;
673    keyIdVec.appendArray(keyId, kKeyIdSize);
674
675    Vector<uint8_t> messageVec;
676    messageVec.appendArray(message, messageSize);
677
678    Vector<uint8_t> signatureVec;
679    signatureVec.appendArray(signature, signatureSize);
680
681    bool match;
682    status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
683    if (status == OK) {
684        return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED;
685    }
686    return translateStatus(status);
687}
688
689} // extern "C"
690
691