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