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