ICrypto.cpp revision 4b75a9c8b93a90749bc5d22912ad0d96c12f4ecf
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 <media/ICrypto.h>
23#include <media/stagefright/foundation/ADebug.h>
24
25namespace android {
26
27enum {
28    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
29    IS_CRYPTO_SUPPORTED,
30    CREATE_PLUGIN,
31    DESTROY_PLUGIN,
32    REQUIRES_SECURE_COMPONENT,
33    DECRYPT,
34};
35
36struct BpCrypto : public BpInterface<ICrypto> {
37    BpCrypto(const sp<IBinder> &impl)
38        : BpInterface<ICrypto>(impl) {
39    }
40
41    virtual status_t initCheck() const {
42        Parcel data, reply;
43        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
44        remote()->transact(INIT_CHECK, data, &reply);
45
46        return reply.readInt32();
47    }
48
49    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
50        Parcel data, reply;
51        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
52        data.write(uuid, 16);
53        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
54
55        return reply.readInt32() != 0;
56    }
57
58    virtual status_t createPlugin(
59            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
60        Parcel data, reply;
61        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
62        data.write(uuid, 16);
63        data.writeInt32(opaqueSize);
64        data.write(opaqueData, opaqueSize);
65        remote()->transact(CREATE_PLUGIN, data, &reply);
66
67        return reply.readInt32();
68    }
69
70    virtual status_t destroyPlugin() {
71        Parcel data, reply;
72        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
73        remote()->transact(DESTROY_PLUGIN, data, &reply);
74
75        return reply.readInt32();
76    }
77
78    virtual bool requiresSecureDecoderComponent(
79            const char *mime) const {
80        Parcel data, reply;
81        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
82        data.writeCString(mime);
83        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
84
85        return reply.readInt32() != 0;
86    }
87
88    virtual status_t decrypt(
89            bool secure,
90            const uint8_t key[16],
91            const uint8_t iv[16],
92            CryptoPlugin::Mode mode,
93            const void *srcPtr,
94            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
95            void *dstPtr) {
96        Parcel data, reply;
97        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
98        data.writeInt32(secure);
99        data.writeInt32(mode);
100
101        static const uint8_t kDummy[16] = { 0 };
102
103        if (key == NULL) {
104            key = kDummy;
105        }
106
107        if (iv == NULL) {
108            iv = kDummy;
109        }
110
111        data.write(key, 16);
112        data.write(iv, 16);
113
114        size_t totalSize = 0;
115        for (size_t i = 0; i < numSubSamples; ++i) {
116            totalSize += subSamples[i].mNumBytesOfEncryptedData;
117            totalSize += subSamples[i].mNumBytesOfClearData;
118        }
119
120        data.writeInt32(totalSize);
121        data.write(srcPtr, totalSize);
122
123        data.writeInt32(numSubSamples);
124        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
125
126        if (secure) {
127            data.writeIntPtr((intptr_t)dstPtr);
128        }
129
130        remote()->transact(DECRYPT, data, &reply);
131
132        status_t result = reply.readInt32();
133
134        if (result != OK) {
135            return result;
136        }
137
138        if (!secure) {
139            reply.read(dstPtr, totalSize);
140        }
141
142        return OK;
143    }
144
145private:
146    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
147};
148
149IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
150
151////////////////////////////////////////////////////////////////////////////////
152
153status_t BnCrypto::onTransact(
154    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
155    switch (code) {
156        case INIT_CHECK:
157        {
158            CHECK_INTERFACE(ICrypto, data, reply);
159            reply->writeInt32(initCheck());
160
161            return OK;
162        }
163
164        case IS_CRYPTO_SUPPORTED:
165        {
166            CHECK_INTERFACE(ICrypto, data, reply);
167            uint8_t uuid[16];
168            data.read(uuid, sizeof(uuid));
169            reply->writeInt32(isCryptoSchemeSupported(uuid));
170
171            return OK;
172        }
173
174        case CREATE_PLUGIN:
175        {
176            CHECK_INTERFACE(ICrypto, data, reply);
177
178            uint8_t uuid[16];
179            data.read(uuid, sizeof(uuid));
180
181            size_t opaqueSize = data.readInt32();
182            void *opaqueData = malloc(opaqueSize);
183            data.read(opaqueData, opaqueSize);
184
185            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
186
187            free(opaqueData);
188            opaqueData = NULL;
189
190            return OK;
191        }
192
193        case DESTROY_PLUGIN:
194        {
195            CHECK_INTERFACE(ICrypto, data, reply);
196            reply->writeInt32(destroyPlugin());
197
198            return OK;
199        }
200
201        case REQUIRES_SECURE_COMPONENT:
202        {
203            CHECK_INTERFACE(ICrypto, data, reply);
204
205            const char *mime = data.readCString();
206            reply->writeInt32(requiresSecureDecoderComponent(mime));
207
208            return OK;
209        }
210
211        case DECRYPT:
212        {
213            CHECK_INTERFACE(ICrypto, data, reply);
214
215            bool secure = data.readInt32() != 0;
216            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
217
218            uint8_t key[16];
219            data.read(key, sizeof(key));
220
221            uint8_t iv[16];
222            data.read(iv, sizeof(iv));
223
224            size_t totalSize = data.readInt32();
225            void *srcData = malloc(totalSize);
226            data.read(srcData, totalSize);
227
228            int32_t numSubSamples = data.readInt32();
229
230            CryptoPlugin::SubSample *subSamples =
231                new CryptoPlugin::SubSample[numSubSamples];
232
233            data.read(
234                    subSamples,
235                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
236
237            void *dstPtr;
238            if (secure) {
239                dstPtr = (void *)data.readIntPtr();
240            } else {
241                dstPtr = malloc(totalSize);
242            }
243
244            status_t err = decrypt(
245                    secure,
246                    key,
247                    iv,
248                    mode,
249                    srcData,
250                    subSamples, numSubSamples,
251                    dstPtr);
252
253            reply->writeInt32(err);
254
255            if (!secure) {
256                if (err == OK) {
257                    reply->write(dstPtr, totalSize);
258                }
259
260                free(dstPtr);
261                dstPtr = NULL;
262            }
263
264            delete[] subSamples;
265            subSamples = NULL;
266
267            free(srcData);
268            srcData = NULL;
269
270            return OK;
271        }
272
273        default:
274            return BBinder::onTransact(code, data, reply, flags);
275    }
276}
277
278}  // namespace android
279
280