ClearKeyCasPlugin.cpp revision 791a1a206b56be8601a6fffd2614926e67d64790
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    : mAppData(appData), mCallback(callback) {
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");
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 %d, 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    AES_KEY contentKey;
360
361    if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled) {
362        // Hold lock to get the key only to avoid contention for decryption
363        Mutex::Autolock _lock(mKeyLock);
364
365        int32_t keyIndex = (scramblingControl & 1);
366        if (!mKeyInfo[keyIndex].valid) {
367            ALOGE("decrypt: key %d is invalid", keyIndex);
368            return ERROR_DRM_DECRYPT;
369        }
370        contentKey = mKeyInfo[keyIndex].contentKey;
371    }
372
373    uint8_t *src = (uint8_t*)srcPtr;
374    uint8_t *dst = (uint8_t*)dstPtr;
375
376    for (size_t i = 0; i < numSubSamples; i++) {
377        size_t numBytesinSubSample = subSamples[i].mNumBytesOfClearData
378                + subSamples[i].mNumBytesOfEncryptedData;
379        if (src != dst) {
380            memcpy(dst, src, numBytesinSubSample);
381        }
382        status_t err = OK;
383        // Don't decrypt if len < AES_BLOCK_SIZE.
384        // The last chunk shorter than AES_BLOCK_SIZE is not encrypted.
385        if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled
386                && subSamples[i].mNumBytesOfEncryptedData >= AES_BLOCK_SIZE) {
387            err = decryptPayload(
388                    contentKey,
389                    numBytesinSubSample,
390                    subSamples[i].mNumBytesOfClearData,
391                    (char *)dst);
392        }
393
394        dst += numBytesinSubSample;
395        src += numBytesinSubSample;
396    }
397    return dst - (uint8_t *)dstPtr;
398}
399
400// Decryption of a TS payload
401status_t ClearKeyCasSession::decryptPayload(
402        const AES_KEY& key, size_t length, size_t offset, char* buffer) const {
403    CHECK(buffer);
404
405    // Invariant: only call decryptPayload with TS packets with at least 16
406    // bytes of payload (AES_BLOCK_SIZE).
407
408    CHECK(length >= offset + AES_BLOCK_SIZE);
409
410    return TpBlockCtsDecrypt(key, length - offset, buffer + offset);
411}
412
413///////////////////////////////////////////////////////////////////////////
414#undef LOG_TAG
415#define LOG_TAG "ClearKeyDescramblerPlugin"
416
417bool ClearKeyDescramblerPlugin::requiresSecureDecoderComponent(
418        const char *mime) const {
419    ALOGV("requiresSecureDecoderComponent: mime=%s", mime);
420    return false;
421}
422
423status_t ClearKeyDescramblerPlugin::setMediaCasSession(
424        const CasSessionId &sessionId) {
425    ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string());
426
427    sp<ClearKeyCasSession> session =
428            ClearKeySessionLibrary::get()->findSession(sessionId);
429
430    if (session == NULL) {
431        ALOGE("ClearKeyDescramblerPlugin: session not found");
432        return ERROR_DRM_SESSION_NOT_OPENED;
433    }
434
435    mCASSession = session;
436    return OK;
437}
438
439ssize_t ClearKeyDescramblerPlugin::descramble(
440        bool secure,
441        ScramblingControl scramblingControl,
442        size_t numSubSamples,
443        const SubSample *subSamples,
444        const void *srcPtr,
445        int32_t srcOffset,
446        void *dstPtr,
447        int32_t dstOffset,
448        AString *errorDetailMsg) {
449
450    ALOGV("descramble: secure=%d, sctrl=%d, subSamples=%s, "
451            "srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d",
452          (int)secure, (int)scramblingControl,
453          subSamplesToString(subSamples, numSubSamples).string(),
454          srcPtr, dstPtr, srcOffset, dstOffset);
455
456    if (mCASSession == NULL) {
457        ALOGE("Uninitialized CAS session!");
458        return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED;
459    }
460
461    return mCASSession->decrypt(
462            secure, scramblingControl,
463            numSubSamples, subSamples,
464            (uint8_t*)srcPtr + srcOffset,
465            dstPtr == NULL ? NULL : ((uint8_t*)dstPtr + dstOffset),
466            errorDetailMsg);
467}
468
469// Conversion utilities
470String8 ClearKeyDescramblerPlugin::arrayToString(
471        uint8_t const *array, size_t len) const
472{
473    String8 result("{ ");
474    for (size_t i = 0; i < len; i++) {
475        result.appendFormat("0x%02x ", array[i]);
476    }
477    result += "}";
478    return result;
479}
480
481String8 ClearKeyDescramblerPlugin::subSamplesToString(
482        SubSample const *subSamples, size_t numSubSamples) const
483{
484    String8 result;
485    for (size_t i = 0; i < numSubSamples; i++) {
486        result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i,
487                            subSamples[i].mNumBytesOfClearData,
488                            subSamples[i].mNumBytesOfEncryptedData);
489    }
490    return result;
491}
492
493} // namespace clearkeycas
494} // namespace android
495