ICrypto.cpp revision 0be134af061566c7d68c0c4f868a677daf85f550
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            AString msg = reply.readCString();
153            if (errorDetailMsg) {
154                *errorDetailMsg = msg;
155            }
156        }
157
158        return result;
159    }
160
161    virtual void notifyResolution(
162        uint32_t width, uint32_t height) {
163        Parcel data, reply;
164        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
165        data.writeInt32(width);
166        data.writeInt32(height);
167        remote()->transact(NOTIFY_RESOLUTION, data, &reply);
168    }
169
170    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
171        Parcel data, reply;
172        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
173
174        writeVector(data, sessionId);
175        remote()->transact(SET_MEDIADRM_SESSION, data, &reply);
176
177        return reply.readInt32();
178    }
179
180private:
181    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
182        uint32_t size = reply.readInt32();
183        vector.insertAt((size_t)0, size);
184        reply.read(vector.editArray(), size);
185    }
186
187    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
188        data.writeInt32(vector.size());
189        data.write(vector.array(), vector.size());
190    }
191
192    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
193};
194
195IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
196
197////////////////////////////////////////////////////////////////////////////////
198
199void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
200    uint32_t size = data.readInt32();
201    vector.insertAt((size_t)0, size);
202    data.read(vector.editArray(), size);
203}
204
205void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
206    reply->writeInt32(vector.size());
207    reply->write(vector.array(), vector.size());
208}
209
210status_t BnCrypto::onTransact(
211    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
212    switch (code) {
213        case INIT_CHECK:
214        {
215            CHECK_INTERFACE(ICrypto, data, reply);
216            reply->writeInt32(initCheck());
217
218            return OK;
219        }
220
221        case IS_CRYPTO_SUPPORTED:
222        {
223            CHECK_INTERFACE(ICrypto, data, reply);
224            uint8_t uuid[16];
225            data.read(uuid, sizeof(uuid));
226            reply->writeInt32(isCryptoSchemeSupported(uuid));
227
228            return OK;
229        }
230
231        case CREATE_PLUGIN:
232        {
233            CHECK_INTERFACE(ICrypto, data, reply);
234
235            uint8_t uuid[16];
236            data.read(uuid, sizeof(uuid));
237
238            size_t opaqueSize = data.readInt32();
239            void *opaqueData = NULL;
240
241            if (opaqueSize > 0) {
242                opaqueData = malloc(opaqueSize);
243                data.read(opaqueData, opaqueSize);
244            }
245
246            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
247
248            if (opaqueData != NULL) {
249                free(opaqueData);
250                opaqueData = NULL;
251            }
252
253            return OK;
254        }
255
256        case DESTROY_PLUGIN:
257        {
258            CHECK_INTERFACE(ICrypto, data, reply);
259            reply->writeInt32(destroyPlugin());
260
261            return OK;
262        }
263
264        case REQUIRES_SECURE_COMPONENT:
265        {
266            CHECK_INTERFACE(ICrypto, data, reply);
267
268            const char *mime = data.readCString();
269            if (mime == NULL) {
270                reply->writeInt32(BAD_VALUE);
271            } else {
272                reply->writeInt32(requiresSecureDecoderComponent(mime));
273            }
274
275            return OK;
276        }
277
278        case DECRYPT:
279        {
280            CHECK_INTERFACE(ICrypto, data, reply);
281
282            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
283            CryptoPlugin::Pattern pattern;
284            pattern.mEncryptBlocks = data.readInt32();
285            pattern.mSkipBlocks = data.readInt32();
286
287            uint8_t key[16];
288            data.read(key, sizeof(key));
289
290            uint8_t iv[16];
291            data.read(iv, sizeof(iv));
292
293            size_t totalSize = data.readInt32();
294            sp<IMemory> source =
295                interface_cast<IMemory>(data.readStrongBinder());
296            if (source == NULL) {
297                reply->writeInt32(BAD_VALUE);
298                return OK;
299            }
300            int32_t offset = data.readInt32();
301
302            int32_t numSubSamples = data.readInt32();
303            if (numSubSamples < 0 || numSubSamples > 0xffff) {
304                reply->writeInt32(BAD_VALUE);
305                return OK;
306            }
307
308            CryptoPlugin::SubSample *subSamples =
309                    new CryptoPlugin::SubSample[numSubSamples];
310
311            data.read(subSamples,
312                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
313
314            DestinationBuffer destination;
315            destination.mType = (DestinationType)data.readInt32();
316            if (destination.mType == kDestinationTypeNativeHandle) {
317                destination.mHandle = data.readNativeHandle();
318                if (destination.mHandle == NULL) {
319                    reply->writeInt32(BAD_VALUE);
320                    return OK;
321                }
322            } else if (destination.mType == kDestinationTypeSharedMemory) {
323                destination.mSharedMemory =
324                        interface_cast<IMemory>(data.readStrongBinder());
325                if (destination.mSharedMemory == NULL) {
326                    reply->writeInt32(BAD_VALUE);
327                    return OK;
328                }
329            }
330
331            AString errorDetailMsg;
332            ssize_t result;
333
334            size_t sumSubsampleSizes = 0;
335            bool overflow = false;
336            for (int32_t i = 0; i < numSubSamples; ++i) {
337                CryptoPlugin::SubSample &ss = subSamples[i];
338                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
339                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
340                } else {
341                    overflow = true;
342                }
343                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
344                    sumSubsampleSizes += ss.mNumBytesOfClearData;
345                } else {
346                    overflow = true;
347                }
348            }
349
350            if (overflow || sumSubsampleSizes != totalSize) {
351                result = -EINVAL;
352            } else if (totalSize > source->size()) {
353                result = -EINVAL;
354            } else if ((size_t)offset > source->size() - totalSize) {
355                result = -EINVAL;
356            } else {
357                result = decrypt(key, iv, mode, pattern, source, offset,
358                        subSamples, numSubSamples, destination, &errorDetailMsg);
359            }
360
361            reply->writeInt32(result);
362
363            if (isCryptoError(result)) {
364                reply->writeCString(errorDetailMsg.c_str());
365            }
366
367            if (destination.mType == kDestinationTypeNativeHandle) {
368                int err;
369                if ((err = native_handle_close(destination.mHandle)) < 0) {
370                    ALOGW("secure buffer native_handle_close failed: %d", err);
371                }
372                if ((err = native_handle_delete(destination.mHandle)) < 0) {
373                    ALOGW("secure buffer native_handle_delete failed: %d", err);
374                }
375            }
376
377            delete[] subSamples;
378            subSamples = NULL;
379
380            return OK;
381        }
382
383        case NOTIFY_RESOLUTION:
384        {
385            CHECK_INTERFACE(ICrypto, data, reply);
386
387            int32_t width = data.readInt32();
388            int32_t height = data.readInt32();
389            notifyResolution(width, height);
390
391            return OK;
392        }
393
394        case SET_MEDIADRM_SESSION:
395        {
396            CHECK_INTERFACE(IDrm, data, reply);
397            Vector<uint8_t> sessionId;
398            readVector(data, sessionId);
399            reply->writeInt32(setMediaDrmSession(sessionId));
400            return OK;
401        }
402
403        default:
404            return BBinder::onTransact(code, data, reply, flags);
405    }
406}
407
408}  // namespace android
409