• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace android {
28 
29 enum {
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 
38 struct BpCrypto : public BpInterface<ICrypto> {
BpCryptoandroid::BpCrypto39     BpCrypto(const sp<IBinder> &impl)
40         : BpInterface<ICrypto>(impl) {
41     }
42 
initCheckandroid::BpCrypto43     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 
isCryptoSchemeSupportedandroid::BpCrypto51     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 
createPluginandroid::BpCrypto60     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 
destroyPluginandroid::BpCrypto76     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 
requiresSecureDecoderComponentandroid::BpCrypto84     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 
decryptandroid::BpCrypto94     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 
152 private:
153     DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
154 };
155 
156 IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)160 status_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