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