1 /*
2  * Copyright (C) 2014 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 "ClearKeyCryptoPlugin"
19 #include <utils/Log.h>
20 
21 #include <media/stagefright/MediaErrors.h>
22 
23 #include "CryptoPlugin.h"
24 #include "SessionLibrary.h"
25 
26 namespace clearkeydrm {
27 
28 using android::Vector;
29 using android::AString;
30 using android::status_t;
31 
32 // Returns negative values for error code and positive values for the size of
33 // decrypted data.  In theory, the output size can be larger than the input
34 // size, but in practice this will never happen for AES-CTR.
decrypt(bool secure,const KeyId keyId,const Iv iv,Mode mode,const Pattern &,const void * srcPtr,const SubSample * subSamples,size_t numSubSamples,void * dstPtr,AString * errorDetailMsg)35 ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
36                               Mode mode, const Pattern &/* pattern */, const void* srcPtr,
37                               const SubSample* subSamples, size_t numSubSamples,
38                               void* dstPtr, AString* errorDetailMsg) {
39     if (secure) {
40         errorDetailMsg->setTo("Secure decryption is not supported with "
41                               "ClearKey.");
42         return android::ERROR_DRM_CANNOT_HANDLE;
43     }
44 
45     if (mode == kMode_Unencrypted) {
46         size_t offset = 0;
47         for (size_t i = 0; i < numSubSamples; ++i) {
48             const SubSample& subSample = subSamples[i];
49 
50             if (subSample.mNumBytesOfEncryptedData != 0) {
51                 errorDetailMsg->setTo(
52                         "Encrypted subsamples found in allegedly unencrypted "
53                         "data.");
54                 return android::ERROR_DRM_DECRYPT;
55             }
56 
57             if (subSample.mNumBytesOfClearData != 0) {
58                 memcpy(reinterpret_cast<uint8_t*>(dstPtr) + offset,
59                        reinterpret_cast<const uint8_t*>(srcPtr) + offset,
60                        subSample.mNumBytesOfClearData);
61                 offset += subSample.mNumBytesOfClearData;
62             }
63         }
64         return static_cast<ssize_t>(offset);
65     } else if (mode == kMode_AES_CTR) {
66         size_t bytesDecrypted;
67         status_t res = mSession->decrypt(keyId, iv, srcPtr, dstPtr, subSamples,
68                                          numSubSamples, &bytesDecrypted);
69         if (res == android::OK) {
70             return static_cast<ssize_t>(bytesDecrypted);
71         } else {
72             errorDetailMsg->setTo("Decryption Error");
73             return static_cast<ssize_t>(res);
74         }
75     } else {
76         errorDetailMsg->setTo(
77                 "Selected encryption mode is not supported by the ClearKey DRM "
78                 "Plugin.");
79         return android::ERROR_DRM_CANNOT_HANDLE;
80     }
81 }
82 
setMediaDrmSession(const android::Vector<uint8_t> & sessionId)83 android::status_t CryptoPlugin::setMediaDrmSession(
84         const android::Vector<uint8_t>& sessionId) {
85     if (!sessionId.size()) {
86         mSession.clear();
87     } else {
88         mSession = SessionLibrary::get()->findSession(sessionId);
89         if (!mSession.get()) {
90             return android::ERROR_DRM_SESSION_NOT_OPENED;
91         }
92     }
93     return android::OK;
94 }
95 
96 
97 }  // namespace clearkeydrm
98