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