• 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]) const {
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 status_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         status_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 (result != OK) {
146             return result;
147         }
148 
149         if (!secure) {
150             reply.read(dstPtr, totalSize);
151         }
152 
153         return OK;
154     }
155 
156 private:
157     DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
158 };
159 
160 IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)164 status_t BnCrypto::onTransact(
165     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
166     switch (code) {
167         case INIT_CHECK:
168         {
169             CHECK_INTERFACE(ICrypto, data, reply);
170             reply->writeInt32(initCheck());
171 
172             return OK;
173         }
174 
175         case IS_CRYPTO_SUPPORTED:
176         {
177             CHECK_INTERFACE(ICrypto, data, reply);
178             uint8_t uuid[16];
179             data.read(uuid, sizeof(uuid));
180             reply->writeInt32(isCryptoSchemeSupported(uuid));
181 
182             return OK;
183         }
184 
185         case CREATE_PLUGIN:
186         {
187             CHECK_INTERFACE(ICrypto, data, reply);
188 
189             uint8_t uuid[16];
190             data.read(uuid, sizeof(uuid));
191 
192             size_t opaqueSize = data.readInt32();
193             void *opaqueData = NULL;
194 
195             if (opaqueSize > 0) {
196                 opaqueData = malloc(opaqueSize);
197                 data.read(opaqueData, opaqueSize);
198             }
199 
200             reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
201 
202             if (opaqueData != NULL) {
203                 free(opaqueData);
204                 opaqueData = NULL;
205             }
206 
207             return OK;
208         }
209 
210         case DESTROY_PLUGIN:
211         {
212             CHECK_INTERFACE(ICrypto, data, reply);
213             reply->writeInt32(destroyPlugin());
214 
215             return OK;
216         }
217 
218         case REQUIRES_SECURE_COMPONENT:
219         {
220             CHECK_INTERFACE(ICrypto, data, reply);
221 
222             const char *mime = data.readCString();
223             reply->writeInt32(requiresSecureDecoderComponent(mime));
224 
225             return OK;
226         }
227 
228         case DECRYPT:
229         {
230             CHECK_INTERFACE(ICrypto, data, reply);
231 
232             bool secure = data.readInt32() != 0;
233             CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
234 
235             uint8_t key[16];
236             data.read(key, sizeof(key));
237 
238             uint8_t iv[16];
239             data.read(iv, sizeof(iv));
240 
241             size_t totalSize = data.readInt32();
242             void *srcData = malloc(totalSize);
243             data.read(srcData, totalSize);
244 
245             int32_t numSubSamples = data.readInt32();
246 
247             CryptoPlugin::SubSample *subSamples =
248                 new CryptoPlugin::SubSample[numSubSamples];
249 
250             data.read(
251                     subSamples,
252                     sizeof(CryptoPlugin::SubSample) * numSubSamples);
253 
254             void *dstPtr;
255             if (secure) {
256                 dstPtr = (void *)data.readIntPtr();
257             } else {
258                 dstPtr = malloc(totalSize);
259             }
260 
261             AString errorDetailMsg;
262 
263             status_t err = decrypt(
264                     secure,
265                     key,
266                     iv,
267                     mode,
268                     srcData,
269                     subSamples, numSubSamples,
270                     dstPtr,
271                     &errorDetailMsg);
272 
273             reply->writeInt32(err);
274 
275             if (err >= ERROR_DRM_VENDOR_MIN
276                     && err <= ERROR_DRM_VENDOR_MAX) {
277                 reply->writeCString(errorDetailMsg.c_str());
278             }
279 
280             if (!secure) {
281                 if (err == OK) {
282                     reply->write(dstPtr, totalSize);
283                 }
284 
285                 free(dstPtr);
286                 dstPtr = NULL;
287             }
288 
289             delete[] subSamples;
290             subSamples = NULL;
291 
292             free(srcData);
293             srcData = NULL;
294 
295             return OK;
296         }
297 
298         default:
299             return BBinder::onTransact(code, data, reply, flags);
300     }
301 }
302 
303 }  // namespace android
304 
305