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