ClearKeyCasPlugin.cpp revision b01fb48fcc755d6bfad9bc94d8c227349155e1b5
1/* 2 * Copyright (C) 2017 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 "ClearKeyCasPlugin" 19 20#include "ClearKeyFetcher.h" 21#include "ecm.h" 22#include "ClearKeyLicenseFetcher.h" 23#include "ClearKeyCasPlugin.h" 24#include "ClearKeySessionLibrary.h" 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/hexdump.h> 28#include <media/stagefright/MediaErrors.h> 29#include <utils/Log.h> 30 31android::CasFactory* createCasFactory() { 32 return new android::clearkeycas::ClearKeyCasFactory(); 33} 34 35android::DescramblerFactory *createDescramblerFactory() 36{ 37 return new android::clearkeycas::ClearKeyDescramblerFactory(); 38} 39 40namespace android { 41namespace clearkeycas { 42 43static const int32_t sClearKeySystemId = 0xF6D8; 44 45bool ClearKeyCasFactory::isSystemIdSupported(int32_t CA_system_id) const { 46 return CA_system_id == sClearKeySystemId; 47} 48 49status_t ClearKeyCasFactory::queryPlugins( 50 std::vector<CasPluginDescriptor> *descriptors) const { 51 descriptors->clear(); 52 descriptors->push_back({sClearKeySystemId, String8("Clear Key CAS")}); 53 return OK; 54} 55 56status_t ClearKeyCasFactory::createPlugin( 57 int32_t CA_system_id, 58 uint64_t appData, 59 CasPluginCallback callback, 60 CasPlugin **plugin) { 61 if (!isSystemIdSupported(CA_system_id)) { 62 return BAD_VALUE; 63 } 64 65 *plugin = new ClearKeyCasPlugin(appData, callback); 66 return OK; 67} 68/////////////////////////////////////////////////////////////////////////////// 69bool ClearKeyDescramblerFactory::isSystemIdSupported( 70 int32_t CA_system_id) const { 71 return CA_system_id == sClearKeySystemId; 72} 73 74status_t ClearKeyDescramblerFactory::createPlugin( 75 int32_t CA_system_id, DescramblerPlugin** plugin) { 76 if (!isSystemIdSupported(CA_system_id)) { 77 return BAD_VALUE; 78 } 79 80 *plugin = new ClearKeyDescramblerPlugin(); 81 return OK; 82} 83 84/////////////////////////////////////////////////////////////////////////////// 85ClearKeyCasPlugin::ClearKeyCasPlugin( 86 uint64_t appData, CasPluginCallback callback) 87 : mCallback(callback), mAppData(appData) { 88 ALOGV("CTOR"); 89} 90 91ClearKeyCasPlugin::~ClearKeyCasPlugin() { 92 ALOGV("DTOR"); 93 ClearKeySessionLibrary::get()->destroyPlugin(this); 94} 95 96status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) { 97 ALOGV("setPrivateData"); 98 99 return OK; 100} 101 102static String8 sessionIdToString(const std::vector<uint8_t> &array) { 103 String8 result; 104 for (size_t i = 0; i < array.size(); i++) { 105 result.appendFormat("%02x ", array[i]); 106 } 107 if (result.isEmpty()) { 108 result.append("(null)"); 109 } 110 return result; 111} 112 113status_t ClearKeyCasPlugin::openSession( 114 uint16_t program_number, CasSessionId* sessionId) { 115 ALOGV("openSession: program_number=%u", program_number); 116 117 return ClearKeySessionLibrary::get()->addSession( 118 this, program_number, 0, sessionId); 119} 120 121status_t ClearKeyCasPlugin::openSession( 122 uint16_t program_number, 123 uint16_t elementary_PID, 124 CasSessionId *sessionId) { 125 ALOGV("openSession: program_number=%u, elementary_PID=%u", 126 program_number, elementary_PID); 127 128 return ClearKeySessionLibrary::get()->addSession( 129 this, program_number, elementary_PID, sessionId); 130} 131 132status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) { 133 ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string()); 134 sp<ClearKeyCasSession> session = 135 ClearKeySessionLibrary::get()->findSession(sessionId); 136 if (session == NULL) { 137 return ERROR_DRM_SESSION_NOT_OPENED; 138 } 139 140 ClearKeySessionLibrary::get()->destroySession(sessionId); 141 return OK; 142} 143 144status_t ClearKeyCasPlugin::setSessionPrivateData( 145 const CasSessionId &sessionId, const CasData & /*data*/) { 146 ALOGV("setSessionPrivateData: sessionId=%s", 147 sessionIdToString(sessionId).string()); 148 sp<ClearKeyCasSession> session = 149 ClearKeySessionLibrary::get()->findSession(sessionId); 150 if (session == NULL) { 151 return ERROR_DRM_SESSION_NOT_OPENED; 152 } 153 return OK; 154} 155 156status_t ClearKeyCasPlugin::processEcm( 157 const CasSessionId &sessionId, const CasEcm& ecm) { 158 ALOGV("processEcm: sessionId=%s", sessionIdToString(sessionId).string()); 159 sp<ClearKeyCasSession> session = 160 ClearKeySessionLibrary::get()->findSession(sessionId); 161 if (session == NULL) { 162 return ERROR_DRM_SESSION_NOT_OPENED; 163 } 164 165 Mutex::Autolock lock(mKeyFetcherLock); 166 167 return session->updateECM(mKeyFetcher.get(), (void*)ecm.data(), ecm.size()); 168} 169 170status_t ClearKeyCasPlugin::processEmm(const CasEmm& /*emm*/) { 171 ALOGV("processEmm"); 172 Mutex::Autolock lock(mKeyFetcherLock); 173 174 return OK; 175} 176 177status_t ClearKeyCasPlugin::sendEvent( 178 int32_t event, int32_t arg, const CasData &eventData) { 179 ALOGV("sendEvent: event=%d, arg=%d", event, arg); 180 // Echo the received event to the callback. 181 // Clear key plugin doesn't use any event, echo'ing for testing only. 182 if (mCallback != NULL) { 183 mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(), eventData.size()); 184 } 185 return OK; 186} 187 188status_t ClearKeyCasPlugin::provision(const String8 &str) { 189 ALOGV("provision: provisionString=%s", str.string()); 190 Mutex::Autolock lock(mKeyFetcherLock); 191 192 std::unique_ptr<ClearKeyLicenseFetcher> license_fetcher; 193 license_fetcher.reset(new ClearKeyLicenseFetcher()); 194 status_t err = license_fetcher->Init(str.string()); 195 if (err != OK) { 196 ALOGE("provision: failed to init ClearKeyLicenseFetcher (err=%d)", err); 197 return err; 198 } 199 200 std::unique_ptr<ClearKeyFetcher> key_fetcher; 201 key_fetcher.reset(new ClearKeyFetcher(std::move(license_fetcher))); 202 err = key_fetcher->Init(); 203 if (err != OK) { 204 ALOGE("provision: failed to init ClearKeyFetcher (err=%d)", err); 205 return err; 206 } 207 208 ALOGV("provision: using ClearKeyFetcher"); 209 mKeyFetcher = std::move(key_fetcher); 210 211 return OK; 212} 213 214status_t ClearKeyCasPlugin::refreshEntitlements( 215 int32_t refreshType, const CasData &/*refreshData*/) { 216 ALOGV("refreshEntitlements: refreshType=%d", refreshType); 217 Mutex::Autolock lock(mKeyFetcherLock); 218 219 return OK; 220} 221 222/////////////////////////////////////////////////////////////////////// 223 224// AES-128 CBC-CTS decrypt optimized for Transport Packets. |key| is the AES 225// key (odd key or even key), |length| is the data size, and |buffer| is the 226// ciphertext to be decrypted in place. 227status_t TpBlockCtsDecrypt(const AES_KEY& key, size_t length, char* buffer) { 228 CHECK(buffer); 229 230 // Invariant: Packet must be at least 16 bytes. 231 CHECK(length >= AES_BLOCK_SIZE); 232 233 // OpenSSL uses unsigned char. 234 unsigned char* data = reinterpret_cast<unsigned char*>(buffer); 235 236 // Start with zero-filled initialization vector. 237 unsigned char iv[AES_BLOCK_SIZE]; 238 memset(iv, 0, AES_BLOCK_SIZE); 239 240 // Size of partial last block handled via CTS. 241 int cts_byte_count = length % AES_BLOCK_SIZE; 242 243 // If there no is no partial last block, then process using normal CBC. 244 if (cts_byte_count == 0) { 245 AES_cbc_encrypt(data, data, length, &key, iv, 0); 246 return OK; 247 } 248 249 // Cipher text stealing (CTS) - Schneier Figure 9.5 p 196. 250 // In CTS mode, the last two blocks have been swapped. Block[n-1] is really 251 // the original block[n] combined with the low-order bytes of the original 252 // block[n-1], while block[n] is the high-order bytes of the original 253 // block[n-1] padded with zeros. 254 255 // Block[0] - block[n-2] are handled with normal CBC. 256 int cbc_byte_count = length - cts_byte_count - AES_BLOCK_SIZE; 257 if (cbc_byte_count > 0) { 258 AES_cbc_encrypt(data, data, cbc_byte_count, &key, iv, 0); 259 // |data| points to block[n-1]. 260 data += cbc_byte_count; 261 } 262 263 // Save block[n] to use as IV when decrypting block[n-1]. 264 unsigned char block_n[AES_BLOCK_SIZE]; 265 memset(block_n, 0, AES_BLOCK_SIZE); 266 memcpy(block_n, data + AES_BLOCK_SIZE, cts_byte_count); 267 268 // Decrypt block[n-1] using block[n] as IV, consistent with the original 269 // block order. 270 AES_cbc_encrypt(data, data, AES_BLOCK_SIZE, &key, block_n, 0); 271 272 // Return the stolen ciphertext: swap the high-order bytes of block[n] 273 // and block[n-1]. 274 for (int i = 0; i < cts_byte_count; i++) { 275 unsigned char temp = *(data + i); 276 *(data + i) = *(data + AES_BLOCK_SIZE + i); 277 *(data + AES_BLOCK_SIZE + i) = temp; 278 } 279 280 // Decrypt block[n-1] using previous IV. 281 AES_cbc_encrypt(data, data, AES_BLOCK_SIZE, &key, iv, 0); 282 return OK; 283} 284 285// PES header and ECM stream header layout 286// 287// processECM() receives the data_byte portion from the transport packet. 288// Below is the layout of the first 16 bytes of the ECM PES packet. Here 289// we don't parse them, we skip them and go to the ECM container directly. 290// The layout is included here only for reference. 291// 292// 0-2: 0x00 00 01 = start code prefix. 293// 3: 0xf0 = stream type (90 = ECM). 294// 4-5: 0x00 00 = PES length (filled in later, this is the length of the 295// PES header (16) plus the length of the ECM container). 296// 6-7: 0x00 00 = ECM major version. 297// 8-9: 0x00 01 = ECM minor version. 298// 10-11: 0x00 00 = Crypto period ID (filled in later). 299// 12-13: 0x00 00 = ECM container length (filled in later, either 84 or 300// 166). 301// 14-15: 0x00 00 = offset = 0. 302 303const static size_t kEcmHeaderLength = 16; 304const static size_t kUserKeyLength = 16; 305 306status_t ClearKeyCasSession::updateECM( 307 KeyFetcher *keyFetcher, void *ecm, size_t size) { 308 if (keyFetcher == nullptr) { 309 return ERROR_DRM_NOT_PROVISIONED; 310 } 311 312 if (size < kEcmHeaderLength) { 313 ALOGE("updateECM: invalid ecm size %zu", size); 314 return BAD_VALUE; 315 } 316 317 Mutex::Autolock _lock(mKeyLock); 318 319 if (mEcmBuffer != NULL && mEcmBuffer->capacity() == size 320 && !memcmp(mEcmBuffer->base(), ecm, size)) { 321 return OK; 322 } 323 324 mEcmBuffer = ABuffer::CreateAsCopy(ecm, size); 325 mEcmBuffer->setRange(kEcmHeaderLength, size - kEcmHeaderLength); 326 327 uint64_t asset_id; 328 std::vector<KeyFetcher::KeyInfo> keys; 329 status_t err = keyFetcher->ObtainKey(mEcmBuffer, &asset_id, &keys); 330 if (err != OK) { 331 ALOGE("updateECM: failed to obtain key (err=%d)", err); 332 return err; 333 } 334 335 ALOGV("updateECM: %zu key(s) found", keys.size()); 336 for (size_t keyIndex = 0; keyIndex < keys.size(); keyIndex++) { 337 String8 str; 338 339 const sp<ABuffer>& keyBytes = keys[keyIndex].key_bytes; 340 CHECK(keyBytes->size() == kUserKeyLength); 341 342 int result = AES_set_decrypt_key( 343 reinterpret_cast<const uint8_t*>(keyBytes->data()), 344 AES_BLOCK_SIZE * 8, &mKeyInfo[keyIndex].contentKey); 345 mKeyInfo[keyIndex].valid = (result == 0); 346 if (!mKeyInfo[keyIndex].valid) { 347 ALOGE("updateECM: failed to set key %zu, key_id=%d", 348 keyIndex, keys[keyIndex].key_id); 349 } 350 } 351 return OK; 352} 353 354// Decryption of a set of sub-samples 355ssize_t ClearKeyCasSession::decrypt( 356 bool secure, DescramblerPlugin::ScramblingControl scramblingControl, 357 size_t numSubSamples, const DescramblerPlugin::SubSample *subSamples, 358 const void *srcPtr, void *dstPtr, AString * /* errorDetailMsg */) { 359 if (secure) { 360 return ERROR_DRM_CANNOT_HANDLE; 361 } 362 363 AES_KEY contentKey; 364 365 if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled) { 366 // Hold lock to get the key only to avoid contention for decryption 367 Mutex::Autolock _lock(mKeyLock); 368 369 int32_t keyIndex = (scramblingControl & 1); 370 if (!mKeyInfo[keyIndex].valid) { 371 ALOGE("decrypt: key %d is invalid", keyIndex); 372 return ERROR_DRM_DECRYPT; 373 } 374 contentKey = mKeyInfo[keyIndex].contentKey; 375 } 376 377 uint8_t *src = (uint8_t*)srcPtr; 378 uint8_t *dst = (uint8_t*)dstPtr; 379 380 for (size_t i = 0; i < numSubSamples; i++) { 381 size_t numBytesinSubSample = subSamples[i].mNumBytesOfClearData 382 + subSamples[i].mNumBytesOfEncryptedData; 383 if (src != dst) { 384 memcpy(dst, src, numBytesinSubSample); 385 } 386 status_t err = OK; 387 // Don't decrypt if len < AES_BLOCK_SIZE. 388 // The last chunk shorter than AES_BLOCK_SIZE is not encrypted. 389 if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled 390 && subSamples[i].mNumBytesOfEncryptedData >= AES_BLOCK_SIZE) { 391 err = decryptPayload( 392 contentKey, 393 numBytesinSubSample, 394 subSamples[i].mNumBytesOfClearData, 395 (char *)dst); 396 } 397 398 dst += numBytesinSubSample; 399 src += numBytesinSubSample; 400 } 401 return dst - (uint8_t *)dstPtr; 402} 403 404// Decryption of a TS payload 405status_t ClearKeyCasSession::decryptPayload( 406 const AES_KEY& key, size_t length, size_t offset, char* buffer) const { 407 CHECK(buffer); 408 409 // Invariant: only call decryptPayload with TS packets with at least 16 410 // bytes of payload (AES_BLOCK_SIZE). 411 412 CHECK(length >= offset + AES_BLOCK_SIZE); 413 414 return TpBlockCtsDecrypt(key, length - offset, buffer + offset); 415} 416 417/////////////////////////////////////////////////////////////////////////// 418#undef LOG_TAG 419#define LOG_TAG "ClearKeyDescramblerPlugin" 420 421bool ClearKeyDescramblerPlugin::requiresSecureDecoderComponent( 422 const char *mime) const { 423 ALOGV("requiresSecureDecoderComponent: mime=%s", mime); 424 return false; 425} 426 427status_t ClearKeyDescramblerPlugin::setMediaCasSession( 428 const CasSessionId &sessionId) { 429 ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string()); 430 431 sp<ClearKeyCasSession> session = 432 ClearKeySessionLibrary::get()->findSession(sessionId); 433 434 if (session == NULL) { 435 ALOGE("ClearKeyDescramblerPlugin: session not found"); 436 return ERROR_DRM_SESSION_NOT_OPENED; 437 } 438 439 mCASSession = session; 440 return OK; 441} 442 443ssize_t ClearKeyDescramblerPlugin::descramble( 444 bool secure, 445 ScramblingControl scramblingControl, 446 size_t numSubSamples, 447 const SubSample *subSamples, 448 const void *srcPtr, 449 int32_t srcOffset, 450 void *dstPtr, 451 int32_t dstOffset, 452 AString *errorDetailMsg) { 453 454 ALOGV("descramble: secure=%d, sctrl=%d, subSamples=%s, " 455 "srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d", 456 (int)secure, (int)scramblingControl, 457 subSamplesToString(subSamples, numSubSamples).string(), 458 srcPtr, dstPtr, srcOffset, dstOffset); 459 460 if (mCASSession == NULL) { 461 ALOGE("Uninitialized CAS session!"); 462 return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED; 463 } 464 465 return mCASSession->decrypt( 466 secure, scramblingControl, 467 numSubSamples, subSamples, 468 (uint8_t*)srcPtr + srcOffset, 469 dstPtr == NULL ? NULL : ((uint8_t*)dstPtr + dstOffset), 470 errorDetailMsg); 471} 472 473// Conversion utilities 474String8 ClearKeyDescramblerPlugin::arrayToString( 475 uint8_t const *array, size_t len) const 476{ 477 String8 result("{ "); 478 for (size_t i = 0; i < len; i++) { 479 result.appendFormat("0x%02x ", array[i]); 480 } 481 result += "}"; 482 return result; 483} 484 485String8 ClearKeyDescramblerPlugin::subSamplesToString( 486 SubSample const *subSamples, size_t numSubSamples) const 487{ 488 String8 result; 489 for (size_t i = 0; i < numSubSamples; i++) { 490 result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i, 491 subSamples[i].mNumBytesOfClearData, 492 subSamples[i].mNumBytesOfEncryptedData); 493 } 494 return result; 495} 496 497} // namespace clearkeycas 498} // namespace android 499