tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ClearKeyDecryptionManager.cpp (10018B)


      1 /*
      2 * Copyright 2015, Mozilla Foundation and contributors
      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 #include "ClearKeyDecryptionManager.h"
     18 
     19 #include <assert.h>
     20 #include <string.h>
     21 
     22 #include <algorithm>
     23 #include <vector>
     24 
     25 #include "mozilla/CheckedInt.h"
     26 #include "mozilla/Span.h"
     27 #include "psshparser/PsshParser.h"
     28 
     29 using namespace cdm;
     30 
     31 bool AllZero(const std::vector<uint32_t>& aBytes) {
     32  return std::all_of(aBytes.begin(), aBytes.end(),
     33                     [](uint32_t b) { return b == 0; });
     34 }
     35 
     36 class ClearKeyDecryptor : public RefCounted {
     37 public:
     38  ClearKeyDecryptor();
     39 
     40  void InitKey(const Key& aKey);
     41  bool HasKey() const { return !mKey.empty(); }
     42 
     43  Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
     44                 const CryptoMetaData& aMetadata);
     45 
     46  const Key& DecryptionKey() const { return mKey; }
     47 
     48 private:
     49  ~ClearKeyDecryptor();
     50 
     51  Key mKey;
     52 };
     53 
     54 /* static */
     55 ClearKeyDecryptionManager* ClearKeyDecryptionManager::sInstance = nullptr;
     56 
     57 /* static */
     58 ClearKeyDecryptionManager* ClearKeyDecryptionManager::Get() {
     59  if (!sInstance) {
     60    sInstance = new ClearKeyDecryptionManager();
     61  }
     62  return sInstance;
     63 }
     64 
     65 ClearKeyDecryptionManager::ClearKeyDecryptionManager() {
     66  CK_LOGD("ClearKeyDecryptionManager::ClearKeyDecryptionManager");
     67 }
     68 
     69 ClearKeyDecryptionManager::~ClearKeyDecryptionManager() {
     70  CK_LOGD("ClearKeyDecryptionManager::~ClearKeyDecryptionManager");
     71 
     72  sInstance = nullptr;
     73 
     74  for (auto it = mDecryptors.begin(); it != mDecryptors.end(); it++) {
     75    it->second->Release();
     76  }
     77  mDecryptors.clear();
     78 }
     79 
     80 bool ClearKeyDecryptionManager::HasSeenKeyId(const KeyId& aKeyId) const {
     81  CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s",
     82          mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f");
     83  return mDecryptors.find(aKeyId) != mDecryptors.end();
     84 }
     85 
     86 bool ClearKeyDecryptionManager::IsExpectingKeyForKeyId(
     87    const KeyId& aKeyId) const {
     88  CK_LOGARRAY("ClearKeyDecryptionManager::IsExpectingKeyForId ", aKeyId.data(),
     89              aKeyId.size());
     90  const auto& decryptor = mDecryptors.find(aKeyId);
     91  return decryptor != mDecryptors.end() && !decryptor->second->HasKey();
     92 }
     93 
     94 bool ClearKeyDecryptionManager::HasKeyForKeyId(const KeyId& aKeyId) const {
     95  CK_LOGD("ClearKeyDecryptionManager::HasKeyForKeyId");
     96  const auto& decryptor = mDecryptors.find(aKeyId);
     97  return decryptor != mDecryptors.end() && decryptor->second->HasKey();
     98 }
     99 
    100 const Key& ClearKeyDecryptionManager::GetDecryptionKey(const KeyId& aKeyId) {
    101  assert(HasKeyForKeyId(aKeyId));
    102  return mDecryptors[aKeyId]->DecryptionKey();
    103 }
    104 
    105 void ClearKeyDecryptionManager::InitKey(KeyId aKeyId, Key aKey) {
    106  CK_LOGD("ClearKeyDecryptionManager::InitKey ", aKeyId.data(), aKeyId.size());
    107  if (IsExpectingKeyForKeyId(aKeyId)) {
    108    CK_LOGARRAY("Initialized Key ", aKeyId.data(), aKeyId.size());
    109    mDecryptors[aKeyId]->InitKey(aKey);
    110  } else {
    111    CK_LOGARRAY("Failed to initialize key ", aKeyId.data(), aKeyId.size());
    112  }
    113 }
    114 
    115 void ClearKeyDecryptionManager::ExpectKeyId(KeyId aKeyId) {
    116  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId ", aKeyId.data(),
    117          aKeyId.size());
    118  if (!HasSeenKeyId(aKeyId)) {
    119    mDecryptors[aKeyId] = new ClearKeyDecryptor();
    120  }
    121  mDecryptors[aKeyId]->AddRef();
    122 }
    123 
    124 void ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId) {
    125  CK_LOGD("ClearKeyDecryptionManager::ReleaseKeyId");
    126  assert(HasSeenKeyId(aKeyId));
    127 
    128  ClearKeyDecryptor* decryptor = mDecryptors[aKeyId];
    129  if (!decryptor->Release()) {
    130    mDecryptors.erase(aKeyId);
    131  }
    132 }
    133 
    134 Status ClearKeyDecryptionManager::Decrypt(std::vector<uint8_t>& aBuffer,
    135                                          const CryptoMetaData& aMetadata) {
    136  return Decrypt(aBuffer.data(), aBuffer.size(), aMetadata);
    137 }
    138 
    139 Status ClearKeyDecryptionManager::Decrypt(uint8_t* aBuffer,
    140                                          uint32_t aBufferSize,
    141                                          const CryptoMetaData& aMetadata) {
    142  CK_LOGD("ClearKeyDecryptionManager::Decrypt");
    143  if (!HasKeyForKeyId(aMetadata.mKeyId)) {
    144    CK_LOGARRAY("Unable to find decryptor for keyId: ", aMetadata.mKeyId.data(),
    145                aMetadata.mKeyId.size());
    146    return Status::kNoKey;
    147  }
    148 
    149  CK_LOGARRAY("Found decryptor for keyId: ", aMetadata.mKeyId.data(),
    150              aMetadata.mKeyId.size());
    151  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, aBufferSize,
    152                                                aMetadata);
    153 }
    154 
    155 ClearKeyDecryptor::ClearKeyDecryptor() { CK_LOGD("ClearKeyDecryptor ctor"); }
    156 
    157 ClearKeyDecryptor::~ClearKeyDecryptor() {
    158  if (HasKey()) {
    159    CK_LOGARRAY("ClearKeyDecryptor dtor; key = ", mKey.data(), mKey.size());
    160  } else {
    161    CK_LOGD("ClearKeyDecryptor dtor");
    162  }
    163 }
    164 
    165 void ClearKeyDecryptor::InitKey(const Key& aKey) { mKey = aKey; }
    166 
    167 Status ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
    168                                  const CryptoMetaData& aMetadata) {
    169  CK_LOGD("ClearKeyDecryptor::Decrypt");
    170  if (aBufferSize == 0) {
    171    // Nothing to decrypt.
    172    return Status::kSuccess;
    173  }
    174 
    175  // If the sample is split up into multiple encrypted subsamples, we need to
    176  // stitch them into one continuous buffer for decryption.
    177  std::vector<uint8_t> tmp(aBufferSize);
    178  static_assert(sizeof(uintptr_t) == sizeof(uint8_t*),
    179                "We need uintptr_t to be exactly the same size as a pointer");
    180 
    181  // Decrypt CBCS case:
    182  if (aMetadata.mEncryptionScheme == EncryptionScheme::kCbcs) {
    183    mozilla::CheckedInt<uintptr_t> data = reinterpret_cast<uintptr_t>(aBuffer);
    184    if (!data.isValid()) {
    185      return Status::kDecryptError;
    186    }
    187    const uintptr_t endBuffer =
    188        reinterpret_cast<uintptr_t>(aBuffer + aBufferSize);
    189 
    190    if (aMetadata.NumSubsamples() == 0) {
    191      if (data.value() > endBuffer) {
    192        return Status::kDecryptError;
    193      }
    194      mozilla::Span<uint8_t> encryptedSpan =
    195          mozilla::Span(reinterpret_cast<uint8_t*>(data.value()), aBufferSize);
    196      if (!ClearKeyUtils::DecryptCbcs(mKey, aMetadata.mIV, encryptedSpan,
    197                                      aMetadata.mCryptByteBlock,
    198                                      aMetadata.mSkipByteBlock)) {
    199        return Status::kDecryptError;
    200      }
    201      return Status::kSuccess;
    202    }
    203 
    204    for (size_t i = 0; i < aMetadata.NumSubsamples(); i++) {
    205      data += aMetadata.mClearBytes[i];
    206      if (!data.isValid() || data.value() > endBuffer) {
    207        return Status::kDecryptError;
    208      }
    209      mozilla::CheckedInt<uintptr_t> dataAfterCipher =
    210          data + aMetadata.mCipherBytes[i];
    211      if (!dataAfterCipher.isValid() || dataAfterCipher.value() > endBuffer) {
    212        // Trying to read past the end of the buffer!
    213        return Status::kDecryptError;
    214      }
    215      mozilla::Span<uint8_t> encryptedSpan = mozilla::Span(
    216          reinterpret_cast<uint8_t*>(data.value()), aMetadata.mCipherBytes[i]);
    217      if (!ClearKeyUtils::DecryptCbcs(mKey, aMetadata.mIV, encryptedSpan,
    218                                      aMetadata.mCryptByteBlock,
    219                                      aMetadata.mSkipByteBlock)) {
    220        return Status::kDecryptError;
    221      }
    222      data += aMetadata.mCipherBytes[i];
    223      if (!data.isValid()) {
    224        return Status::kDecryptError;
    225      }
    226    }
    227    return Status::kSuccess;
    228  }
    229 
    230  // Decrypt CENC case:
    231  if (aMetadata.NumSubsamples()) {
    232    // Take all encrypted parts of subsamples and stitch them into one
    233    // continuous encrypted buffer.
    234    mozilla::CheckedInt<uintptr_t> data = reinterpret_cast<uintptr_t>(aBuffer);
    235    const uintptr_t endBuffer =
    236        reinterpret_cast<uintptr_t>(aBuffer + aBufferSize);
    237    uint8_t* iter = tmp.data();
    238    for (size_t i = 0; i < aMetadata.NumSubsamples(); i++) {
    239      data += aMetadata.mClearBytes[i];
    240      if (!data.isValid() || data.value() > endBuffer) {
    241        // Trying to read past the end of the buffer!
    242        return Status::kDecryptError;
    243      }
    244      const uint32_t& cipherBytes = aMetadata.mCipherBytes[i];
    245      mozilla::CheckedInt<uintptr_t> dataAfterCipher = data + cipherBytes;
    246      if (!dataAfterCipher.isValid() || dataAfterCipher.value() > endBuffer) {
    247        // Trying to read past the end of the buffer!
    248        return Status::kDecryptError;
    249      }
    250 
    251      memcpy(iter, reinterpret_cast<uint8_t*>(data.value()), cipherBytes);
    252 
    253      data = dataAfterCipher;
    254      iter += cipherBytes;
    255    }
    256 
    257    tmp.resize((size_t)(iter - tmp.data()));
    258  } else {
    259    memcpy(tmp.data(), aBuffer, aBufferSize);
    260  }
    261 
    262  // It is possible that we could be passed an unencrypted sample, if all
    263  // encrypted sample lengths are zero, and in this case, a zero length
    264  // IV is allowed.
    265  assert(aMetadata.mIV.size() == 8 || aMetadata.mIV.size() == 16 ||
    266         (aMetadata.mIV.empty() && AllZero(aMetadata.mCipherBytes)));
    267 
    268  std::vector<uint8_t> iv(aMetadata.mIV);
    269  iv.insert(iv.end(), CENC_KEY_LEN - aMetadata.mIV.size(), 0);
    270 
    271  if (!ClearKeyUtils::DecryptAES(mKey, tmp, iv)) {
    272    return Status::kDecryptError;
    273  }
    274 
    275  if (aMetadata.NumSubsamples()) {
    276    // Take the decrypted buffer, split up into subsamples, and insert those
    277    // subsamples back into their original position in the original buffer.
    278    uint8_t* data = aBuffer;
    279    uint8_t* iter = tmp.data();
    280    for (size_t i = 0; i < aMetadata.NumSubsamples(); i++) {
    281      data += aMetadata.mClearBytes[i];
    282      uint32_t cipherBytes = aMetadata.mCipherBytes[i];
    283 
    284      memcpy(data, iter, cipherBytes);
    285 
    286      data += cipherBytes;
    287      iter += cipherBytes;
    288    }
    289  } else {
    290    memcpy(aBuffer, tmp.data(), aBufferSize);
    291  }
    292 
    293  return Status::kSuccess;
    294 }