ICrypto.cpp revision 9247e10531fa3128d5263e3ad605a0fecefcd2d0
1/*
2 * Copyright (C) 2012 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 "ICrypto"
19#include <utils/Log.h>
20
21#include <binder/Parcel.h>
22#include <binder/IMemory.h>
23#include <media/ICrypto.h>
24#include <media/stagefright/MediaErrors.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/foundation/AString.h>
27
28namespace android {
29
30enum {
31    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
32    IS_CRYPTO_SUPPORTED,
33    CREATE_PLUGIN,
34    DESTROY_PLUGIN,
35    REQUIRES_SECURE_COMPONENT,
36    DECRYPT,
37    NOTIFY_RESOLUTION,
38    SET_MEDIADRM_SESSION,
39};
40
41struct BpCrypto : public BpInterface<ICrypto> {
42    explicit BpCrypto(const sp<IBinder> &impl)
43        : BpInterface<ICrypto>(impl) {
44    }
45
46    virtual status_t initCheck() const {
47        Parcel data, reply;
48        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
49        remote()->transact(INIT_CHECK, data, &reply);
50
51        return reply.readInt32();
52    }
53
54    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
55        Parcel data, reply;
56        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
57        data.write(uuid, 16);
58        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
59
60        return reply.readInt32() != 0;
61    }
62
63    virtual status_t createPlugin(
64            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
65        Parcel data, reply;
66        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
67        data.write(uuid, 16);
68        data.writeInt32(opaqueSize);
69
70        if (opaqueSize > 0) {
71            data.write(opaqueData, opaqueSize);
72        }
73
74        remote()->transact(CREATE_PLUGIN, data, &reply);
75
76        return reply.readInt32();
77    }
78
79    virtual status_t destroyPlugin() {
80        Parcel data, reply;
81        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
82        remote()->transact(DESTROY_PLUGIN, data, &reply);
83
84        return reply.readInt32();
85    }
86
87    virtual bool requiresSecureDecoderComponent(
88            const char *mime) const {
89        Parcel data, reply;
90        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
91        data.writeCString(mime);
92        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
93
94        return reply.readInt32() != 0;
95    }
96
97    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
98            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
99            const sp<IMemory> &source, size_t offset,
100            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
101            const DestinationBuffer &destination, AString *errorDetailMsg) {
102        Parcel data, reply;
103        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
104        data.writeInt32(mode);
105        data.writeInt32(pattern.mEncryptBlocks);
106        data.writeInt32(pattern.mSkipBlocks);
107
108        static const uint8_t kDummy[16] = { 0 };
109
110        if (key == NULL) {
111            key = kDummy;
112        }
113
114        if (iv == NULL) {
115            iv = kDummy;
116        }
117
118        data.write(key, 16);
119        data.write(iv, 16);
120
121        size_t totalSize = 0;
122        for (size_t i = 0; i < numSubSamples; ++i) {
123            totalSize += subSamples[i].mNumBytesOfEncryptedData;
124            totalSize += subSamples[i].mNumBytesOfClearData;
125        }
126
127        data.writeInt32(totalSize);
128        data.writeStrongBinder(IInterface::asBinder(source));
129        data.writeInt32(offset);
130
131        data.writeInt32(numSubSamples);
132        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
133
134        data.writeInt32((int32_t)destination.mType);
135        if (destination.mType == kDestinationTypeNativeHandle) {
136            if (destination.mHandle == NULL) {
137                return BAD_VALUE;
138            }
139            data.writeNativeHandle(destination.mHandle);
140        } else {
141            if (destination.mSharedMemory == NULL) {
142                return BAD_VALUE;
143            }
144            data.writeStrongBinder(IInterface::asBinder(destination.mSharedMemory));
145        }
146
147        remote()->transact(DECRYPT, data, &reply);
148
149        ssize_t result = reply.readInt32();
150
151        if (isCryptoError(result)) {
152            errorDetailMsg->setTo(reply.readCString());
153        }
154
155        return result;
156    }
157
158    virtual void notifyResolution(
159        uint32_t width, uint32_t height) {
160        Parcel data, reply;
161        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
162        data.writeInt32(width);
163        data.writeInt32(height);
164        remote()->transact(NOTIFY_RESOLUTION, data, &reply);
165    }
166
167    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
168        Parcel data, reply;
169        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
170
171        writeVector(data, sessionId);
172        remote()->transact(SET_MEDIADRM_SESSION, data, &reply);
173
174        return reply.readInt32();
175    }
176
177private:
178    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
179        uint32_t size = reply.readInt32();
180        vector.insertAt((size_t)0, size);
181        reply.read(vector.editArray(), size);
182    }
183
184    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
185        data.writeInt32(vector.size());
186        data.write(vector.array(), vector.size());
187    }
188
189    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
190};
191
192IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
193
194////////////////////////////////////////////////////////////////////////////////
195
196void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
197    uint32_t size = data.readInt32();
198    vector.insertAt((size_t)0, size);
199    data.read(vector.editArray(), size);
200}
201
202void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
203    reply->writeInt32(vector.size());
204    reply->write(vector.array(), vector.size());
205}
206
207status_t BnCrypto::onTransact(
208    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
209    switch (code) {
210        case INIT_CHECK:
211        {
212            CHECK_INTERFACE(ICrypto, data, reply);
213            reply->writeInt32(initCheck());
214
215            return OK;
216        }
217
218        case IS_CRYPTO_SUPPORTED:
219        {
220            CHECK_INTERFACE(ICrypto, data, reply);
221            uint8_t uuid[16];
222            data.read(uuid, sizeof(uuid));
223            reply->writeInt32(isCryptoSchemeSupported(uuid));
224
225            return OK;
226        }
227
228        case CREATE_PLUGIN:
229        {
230            CHECK_INTERFACE(ICrypto, data, reply);
231
232            uint8_t uuid[16];
233            data.read(uuid, sizeof(uuid));
234
235            size_t opaqueSize = data.readInt32();
236            void *opaqueData = NULL;
237
238            const size_t kMaxOpaqueSize = 100 * 1024;
239            if (opaqueSize > kMaxOpaqueSize) {
240                return BAD_VALUE;
241            }
242
243            opaqueData = malloc(opaqueSize);
244            if (NULL == opaqueData) {
245                return NO_MEMORY;
246            }
247
248            data.read(opaqueData, opaqueSize);
249            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
250
251            free(opaqueData);
252            opaqueData = NULL;
253
254            return OK;
255        }
256
257        case DESTROY_PLUGIN:
258        {
259            CHECK_INTERFACE(ICrypto, data, reply);
260            reply->writeInt32(destroyPlugin());
261
262            return OK;
263        }
264
265        case REQUIRES_SECURE_COMPONENT:
266        {
267            CHECK_INTERFACE(ICrypto, data, reply);
268
269            const char *mime = data.readCString();
270            if (mime == NULL) {
271                reply->writeInt32(BAD_VALUE);
272            } else {
273                reply->writeInt32(requiresSecureDecoderComponent(mime));
274            }
275
276            return OK;
277        }
278
279        case DECRYPT:
280        {
281            CHECK_INTERFACE(ICrypto, data, reply);
282
283            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
284            CryptoPlugin::Pattern pattern;
285            pattern.mEncryptBlocks = data.readInt32();
286            pattern.mSkipBlocks = data.readInt32();
287
288            uint8_t key[16];
289            data.read(key, sizeof(key));
290
291            uint8_t iv[16];
292            data.read(iv, sizeof(iv));
293
294            size_t totalSize = data.readInt32();
295            sp<IMemory> source =
296                interface_cast<IMemory>(data.readStrongBinder());
297            if (source == NULL) {
298                reply->writeInt32(BAD_VALUE);
299                return OK;
300            }
301            int32_t offset = data.readInt32();
302
303            int32_t numSubSamples = data.readInt32();
304            if (numSubSamples < 0 || numSubSamples > 0xffff) {
305                reply->writeInt32(BAD_VALUE);
306                return OK;
307            }
308
309            CryptoPlugin::SubSample *subSamples =
310                    new CryptoPlugin::SubSample[numSubSamples];
311
312            data.read(subSamples,
313                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
314
315            DestinationBuffer destination;
316            destination.mType = (DestinationType)data.readInt32();
317            if (destination.mType == kDestinationTypeNativeHandle) {
318                destination.mHandle = data.readNativeHandle();
319                if (destination.mHandle == NULL) {
320                    reply->writeInt32(BAD_VALUE);
321                    return OK;
322                }
323            } else if (destination.mType == kDestinationTypeSharedMemory) {
324                destination.mSharedMemory =
325                        interface_cast<IMemory>(data.readStrongBinder());
326                if (destination.mSharedMemory == NULL) {
327                    reply->writeInt32(BAD_VALUE);
328                    return OK;
329                }
330            }
331
332            AString errorDetailMsg;
333            ssize_t result;
334
335            size_t sumSubsampleSizes = 0;
336            bool overflow = false;
337            for (int32_t i = 0; i < numSubSamples; ++i) {
338                CryptoPlugin::SubSample &ss = subSamples[i];
339                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
340                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
341                } else {
342                    overflow = true;
343                }
344                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
345                    sumSubsampleSizes += ss.mNumBytesOfClearData;
346                } else {
347                    overflow = true;
348                }
349            }
350
351            if (overflow || sumSubsampleSizes != totalSize) {
352                result = -EINVAL;
353            } else if (totalSize > source->size()) {
354                result = -EINVAL;
355            } else if ((size_t)offset > source->size() - totalSize) {
356                result = -EINVAL;
357            } else {
358                result = decrypt(key, iv, mode, pattern, source, offset,
359                        subSamples, numSubSamples, destination, &errorDetailMsg);
360            }
361
362            reply->writeInt32(result);
363
364            if (isCryptoError(result)) {
365                reply->writeCString(errorDetailMsg.c_str());
366            }
367
368            if (destination.mType == kDestinationTypeNativeHandle) {
369                int err;
370                if ((err = native_handle_close(destination.mHandle)) < 0) {
371                    ALOGW("secure buffer native_handle_close failed: %d", err);
372                }
373                if ((err = native_handle_delete(destination.mHandle)) < 0) {
374                    ALOGW("secure buffer native_handle_delete failed: %d", err);
375                }
376            }
377
378            delete[] subSamples;
379            subSamples = NULL;
380
381            return OK;
382        }
383
384        case NOTIFY_RESOLUTION:
385        {
386            CHECK_INTERFACE(ICrypto, data, reply);
387
388            int32_t width = data.readInt32();
389            int32_t height = data.readInt32();
390            notifyResolution(width, height);
391
392            return OK;
393        }
394
395        case SET_MEDIADRM_SESSION:
396        {
397            CHECK_INTERFACE(IDrm, data, reply);
398            Vector<uint8_t> sessionId;
399            readVector(data, sessionId);
400            reply->writeInt32(setMediaDrmSession(sessionId));
401            return OK;
402        }
403
404        default:
405            return BBinder::onTransact(code, data, reply, flags);
406    }
407}
408
409}  // namespace android
410