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