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