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 <binder/IMemory.h>
23 #include <media/ICrypto.h>
24 #include <media/stagefright/MediaErrors.h>
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/AString.h>
27 
28 namespace android {
29 
30 enum {
31     INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
32     IS_CRYPTO_SUPPORTED,
33     CREATE_PLUGIN,
34     DESTROY_PLUGIN,
35     REQUIRES_SECURE_COMPONENT,
36     DECRYPT,
37     NOTIFY_RESOLUTION,
38     SET_MEDIADRM_SESSION,
39 };
40 
41 struct BpCrypto : public BpInterface<ICrypto> {
BpCryptoandroid::BpCrypto42     BpCrypto(const sp<IBinder> &impl)
43         : BpInterface<ICrypto>(impl) {
44     }
45 
initCheckandroid::BpCrypto46     virtual status_t initCheck() const {
47         Parcel data, reply;
48         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
49         remote()->transact(INIT_CHECK, data, &reply);
50 
51         return reply.readInt32();
52     }
53 
isCryptoSchemeSupportedandroid::BpCrypto54     virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
55         Parcel data, reply;
56         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
57         data.write(uuid, 16);
58         remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
59 
60         return reply.readInt32() != 0;
61     }
62 
createPluginandroid::BpCrypto63     virtual status_t createPlugin(
64             const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
65         Parcel data, reply;
66         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
67         data.write(uuid, 16);
68         data.writeInt32(opaqueSize);
69 
70         if (opaqueSize > 0) {
71             data.write(opaqueData, opaqueSize);
72         }
73 
74         remote()->transact(CREATE_PLUGIN, data, &reply);
75 
76         return reply.readInt32();
77     }
78 
destroyPluginandroid::BpCrypto79     virtual status_t destroyPlugin() {
80         Parcel data, reply;
81         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
82         remote()->transact(DESTROY_PLUGIN, data, &reply);
83 
84         return reply.readInt32();
85     }
86 
requiresSecureDecoderComponentandroid::BpCrypto87     virtual bool requiresSecureDecoderComponent(
88             const char *mime) const {
89         Parcel data, reply;
90         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
91         data.writeCString(mime);
92         remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
93 
94         return reply.readInt32() != 0;
95     }
96 
decryptandroid::BpCrypto97     virtual ssize_t decrypt(
98             DestinationType dstType,
99             const uint8_t key[16],
100             const uint8_t iv[16],
101             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
102             const sp<IMemory> &sharedBuffer, size_t offset,
103             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
104             void *dstPtr,
105             AString *errorDetailMsg) {
106         Parcel data, reply;
107         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
108         data.writeInt32((int32_t)dstType);
109         data.writeInt32(mode);
110         data.writeInt32(pattern.mEncryptBlocks);
111         data.writeInt32(pattern.mSkipBlocks);
112 
113         static const uint8_t kDummy[16] = { 0 };
114 
115         if (key == NULL) {
116             key = kDummy;
117         }
118 
119         if (iv == NULL) {
120             iv = kDummy;
121         }
122 
123         data.write(key, 16);
124         data.write(iv, 16);
125 
126         size_t totalSize = 0;
127         for (size_t i = 0; i < numSubSamples; ++i) {
128             totalSize += subSamples[i].mNumBytesOfEncryptedData;
129             totalSize += subSamples[i].mNumBytesOfClearData;
130         }
131 
132         data.writeInt32(totalSize);
133         data.writeStrongBinder(IInterface::asBinder(sharedBuffer));
134         data.writeInt32(offset);
135 
136         data.writeInt32(numSubSamples);
137         data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
138 
139         if (dstType == kDestinationTypeNativeHandle) {
140             data.writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
141         } else if (dstType == kDestinationTypeOpaqueHandle) {
142             data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr)));
143         } else {
144             dstType = kDestinationTypeVmPointer;
145         }
146 
147         remote()->transact(DECRYPT, data, &reply);
148 
149         ssize_t result = reply.readInt32();
150 
151         if (isCryptoError(result)) {
152             errorDetailMsg->setTo(reply.readCString());
153         }
154 
155         if (dstType == kDestinationTypeVmPointer && result >= 0) {
156             reply.read(dstPtr, result);
157         }
158 
159         return result;
160     }
161 
notifyResolutionandroid::BpCrypto162     virtual void notifyResolution(
163         uint32_t width, uint32_t height) {
164         Parcel data, reply;
165         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
166         data.writeInt32(width);
167         data.writeInt32(height);
168         remote()->transact(NOTIFY_RESOLUTION, data, &reply);
169     }
170 
setMediaDrmSessionandroid::BpCrypto171     virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
172         Parcel data, reply;
173         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
174 
175         writeVector(data, sessionId);
176         remote()->transact(SET_MEDIADRM_SESSION, data, &reply);
177 
178         return reply.readInt32();
179     }
180 
181 private:
readVectorandroid::BpCrypto182     void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
183         uint32_t size = reply.readInt32();
184         vector.insertAt((size_t)0, size);
185         reply.read(vector.editArray(), size);
186     }
187 
writeVectorandroid::BpCrypto188     void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
189         data.writeInt32(vector.size());
190         data.write(vector.array(), vector.size());
191     }
192 
193     DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
194 };
195 
196 IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 
readVector(const Parcel & data,Vector<uint8_t> & vector) const200 void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
201     uint32_t size = data.readInt32();
202     vector.insertAt((size_t)0, size);
203     data.read(vector.editArray(), size);
204 }
205 
writeVector(Parcel * reply,Vector<uint8_t> const & vector) const206 void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
207     reply->writeInt32(vector.size());
208     reply->write(vector.array(), vector.size());
209 }
210 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)211 status_t BnCrypto::onTransact(
212     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
213     switch (code) {
214         case INIT_CHECK:
215         {
216             CHECK_INTERFACE(ICrypto, data, reply);
217             reply->writeInt32(initCheck());
218 
219             return OK;
220         }
221 
222         case IS_CRYPTO_SUPPORTED:
223         {
224             CHECK_INTERFACE(ICrypto, data, reply);
225             uint8_t uuid[16];
226             data.read(uuid, sizeof(uuid));
227             reply->writeInt32(isCryptoSchemeSupported(uuid));
228 
229             return OK;
230         }
231 
232         case CREATE_PLUGIN:
233         {
234             CHECK_INTERFACE(ICrypto, data, reply);
235 
236             uint8_t uuid[16];
237             data.read(uuid, sizeof(uuid));
238 
239             size_t opaqueSize = data.readInt32();
240             void *opaqueData = NULL;
241 
242             if (opaqueSize > 0) {
243                 opaqueData = malloc(opaqueSize);
244                 data.read(opaqueData, opaqueSize);
245             }
246 
247             reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
248 
249             if (opaqueData != NULL) {
250                 free(opaqueData);
251                 opaqueData = NULL;
252             }
253 
254             return OK;
255         }
256 
257         case DESTROY_PLUGIN:
258         {
259             CHECK_INTERFACE(ICrypto, data, reply);
260             reply->writeInt32(destroyPlugin());
261 
262             return OK;
263         }
264 
265         case REQUIRES_SECURE_COMPONENT:
266         {
267             CHECK_INTERFACE(ICrypto, data, reply);
268 
269             const char *mime = data.readCString();
270             if (mime == NULL) {
271                 reply->writeInt32(BAD_VALUE);
272             } else {
273                 reply->writeInt32(requiresSecureDecoderComponent(mime));
274             }
275 
276             return OK;
277         }
278 
279         case DECRYPT:
280         {
281             CHECK_INTERFACE(ICrypto, data, reply);
282 
283             DestinationType dstType = (DestinationType)data.readInt32();
284             CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
285             CryptoPlugin::Pattern pattern;
286             pattern.mEncryptBlocks = data.readInt32();
287             pattern.mSkipBlocks = data.readInt32();
288 
289             uint8_t key[16];
290             data.read(key, sizeof(key));
291 
292             uint8_t iv[16];
293             data.read(iv, sizeof(iv));
294 
295             size_t totalSize = data.readInt32();
296             sp<IMemory> sharedBuffer =
297                 interface_cast<IMemory>(data.readStrongBinder());
298             if (sharedBuffer == NULL) {
299                 reply->writeInt32(BAD_VALUE);
300                 return OK;
301             }
302             int32_t offset = data.readInt32();
303 
304             int32_t numSubSamples = data.readInt32();
305 
306             CryptoPlugin::SubSample *subSamples =
307                 new CryptoPlugin::SubSample[numSubSamples];
308 
309             data.read(
310                     subSamples,
311                     sizeof(CryptoPlugin::SubSample) * numSubSamples);
312 
313             native_handle_t *nativeHandle = NULL;
314             void *secureBufferId = NULL, *dstPtr;
315             if (dstType == kDestinationTypeNativeHandle) {
316                 nativeHandle = data.readNativeHandle();
317                 dstPtr = static_cast<void *>(nativeHandle);
318             } else if (dstType == kDestinationTypeOpaqueHandle) {
319                 secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
320                 dstPtr = secureBufferId;
321             } else {
322                 dstType = kDestinationTypeVmPointer;
323                 dstPtr = malloc(totalSize);
324             }
325 
326             AString errorDetailMsg;
327             ssize_t result;
328 
329             size_t sumSubsampleSizes = 0;
330             bool overflow = false;
331             for (int32_t i = 0; i < numSubSamples; ++i) {
332                 CryptoPlugin::SubSample &ss = subSamples[i];
333                 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
334                     sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
335                 } else {
336                     overflow = true;
337                 }
338                 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
339                     sumSubsampleSizes += ss.mNumBytesOfClearData;
340                 } else {
341                     overflow = true;
342                 }
343             }
344 
345             if (overflow || sumSubsampleSizes != totalSize) {
346                 result = -EINVAL;
347             } else if (totalSize > sharedBuffer->size()) {
348                 result = -EINVAL;
349             } else if ((size_t)offset > sharedBuffer->size() - totalSize) {
350                 result = -EINVAL;
351             } else {
352                 result = decrypt(
353                     dstType,
354                     key,
355                     iv,
356                     mode, pattern,
357                     sharedBuffer, offset,
358                     subSamples, numSubSamples,
359                     dstPtr,
360                     &errorDetailMsg);
361             }
362 
363             reply->writeInt32(result);
364 
365             if (isCryptoError(result)) {
366                 reply->writeCString(errorDetailMsg.c_str());
367             }
368 
369             if (dstType == kDestinationTypeVmPointer) {
370                 if (result >= 0) {
371                     CHECK_LE(result, static_cast<ssize_t>(totalSize));
372                     reply->write(dstPtr, result);
373                 }
374                 free(dstPtr);
375                 dstPtr = NULL;
376             } else if (dstType == kDestinationTypeNativeHandle) {
377                 int err;
378                 if ((err = native_handle_close(nativeHandle)) < 0) {
379                     ALOGW("secure buffer native_handle_close failed: %d", err);
380                 }
381                 if ((err = native_handle_delete(nativeHandle)) < 0) {
382                     ALOGW("secure buffer native_handle_delete failed: %d", err);
383                 }
384             }
385 
386             delete[] subSamples;
387             subSamples = NULL;
388 
389             return OK;
390         }
391 
392         case NOTIFY_RESOLUTION:
393         {
394             CHECK_INTERFACE(ICrypto, data, reply);
395 
396             int32_t width = data.readInt32();
397             int32_t height = data.readInt32();
398             notifyResolution(width, height);
399 
400             return OK;
401         }
402 
403         case SET_MEDIADRM_SESSION:
404         {
405             CHECK_INTERFACE(IDrm, data, reply);
406             Vector<uint8_t> sessionId;
407             readVector(data, sessionId);
408             reply->writeInt32(setMediaDrmSession(sessionId));
409             return OK;
410         }
411 
412         default:
413             return BBinder::onTransact(code, data, reply, flags);
414     }
415 }
416 
417 }  // namespace android
418