123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "media/cdm/cenc_decryptor.h"
- #include <stdint.h>
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/logging.h"
- #include "base/strings/string_piece.h"
- #include "crypto/encryptor.h"
- #include "crypto/symmetric_key.h"
- #include "media/base/decoder_buffer.h"
- #include "media/base/decrypt_config.h"
- #include "media/base/subsample_entry.h"
- namespace media {
- namespace {
- enum ClearBytesBufferSel { kSrcContainsClearBytes, kDstContainsClearBytes };
- // Copy the cypher bytes as specified by |subsamples| from |src| to |dst|.
- // If |sel| == kSrcContainsClearBytes, then |src| is expected to contain any
- // clear bytes specified by |subsamples| and will be skipped. This is used
- // when copying all the protected data out of a sample. If |sel| ==
- // kDstContainsClearBytes, then any clear bytes mentioned in |subsamples|
- // will be skipped in |dst|. This is used when copying the decrypted bytes
- // back into the buffer, replacing the encrypted portions.
- void CopySubsamples(const std::vector<SubsampleEntry>& subsamples,
- const ClearBytesBufferSel sel,
- const uint8_t* src,
- uint8_t* dst) {
- for (size_t i = 0; i < subsamples.size(); i++) {
- const SubsampleEntry& subsample = subsamples[i];
- if (sel == kSrcContainsClearBytes) {
- src += subsample.clear_bytes;
- } else {
- dst += subsample.clear_bytes;
- }
- memcpy(dst, src, subsample.cypher_bytes);
- src += subsample.cypher_bytes;
- dst += subsample.cypher_bytes;
- }
- }
- // TODO(crbug.com/840983): This should be done in DecoderBuffer so that
- // additional fields are more easily handled.
- void CopyExtraSettings(const DecoderBuffer& input, DecoderBuffer* output) {
- output->set_timestamp(input.timestamp());
- output->set_duration(input.duration());
- output->set_is_key_frame(input.is_key_frame());
- output->CopySideDataFrom(input.side_data(), input.side_data_size());
- }
- } // namespace
- scoped_refptr<DecoderBuffer> DecryptCencBuffer(
- const DecoderBuffer& input,
- const crypto::SymmetricKey& key) {
- const char* sample = reinterpret_cast<const char*>(input.data());
- const size_t sample_size = input.data_size();
- DCHECK(sample_size) << "No data to decrypt.";
- const DecryptConfig* decrypt_config = input.decrypt_config();
- DCHECK(decrypt_config) << "No need to call Decrypt() on unencrypted buffer.";
- DCHECK_EQ(EncryptionScheme::kCenc, decrypt_config->encryption_scheme());
- const std::string& iv = decrypt_config->iv();
- DCHECK_EQ(iv.size(), static_cast<size_t>(DecryptConfig::kDecryptionKeySize));
- crypto::Encryptor encryptor;
- if (!encryptor.Init(&key, crypto::Encryptor::CTR, "")) {
- DVLOG(1) << "Could not initialize decryptor.";
- return nullptr;
- }
- if (!encryptor.SetCounter(iv)) {
- DVLOG(1) << "Could not set counter block.";
- return nullptr;
- }
- const std::vector<SubsampleEntry>& subsamples = decrypt_config->subsamples();
- if (subsamples.empty()) {
- std::string decrypted_text;
- base::StringPiece encrypted_text(sample, sample_size);
- if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
- DVLOG(1) << "Could not decrypt data.";
- return nullptr;
- }
- // TODO(xhwang): Find a way to avoid this data copy.
- auto output = DecoderBuffer::CopyFrom(
- reinterpret_cast<const uint8_t*>(decrypted_text.data()),
- decrypted_text.size());
- CopyExtraSettings(input, output.get());
- return output;
- }
- if (!VerifySubsamplesMatchSize(subsamples, sample_size)) {
- DVLOG(1) << "Subsample sizes do not equal input size";
- return nullptr;
- }
- // Compute the size of the encrypted portion. Overflow, etc. checked by
- // the call to VerifySubsamplesMatchSize().
- size_t total_encrypted_size = 0;
- for (const auto& subsample : subsamples)
- total_encrypted_size += subsample.cypher_bytes;
- // No need to decrypt if there is no encrypted data.
- if (total_encrypted_size == 0) {
- auto output = DecoderBuffer::CopyFrom(input.data(), sample_size);
- CopyExtraSettings(input, output.get());
- return output;
- }
- // The encrypted portions of all subsamples must form a contiguous block,
- // such that an encrypted subsample that ends away from a block boundary is
- // immediately followed by the start of the next encrypted subsample. We
- // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
- // copy the decrypted bytes over the encrypted bytes in the output.
- // TODO(strobe): attempt to reduce number of memory copies
- std::unique_ptr<uint8_t[]> encrypted_bytes(new uint8_t[total_encrypted_size]);
- CopySubsamples(subsamples, kSrcContainsClearBytes,
- reinterpret_cast<const uint8_t*>(sample),
- encrypted_bytes.get());
- base::StringPiece encrypted_text(
- reinterpret_cast<const char*>(encrypted_bytes.get()),
- total_encrypted_size);
- std::string decrypted_text;
- if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
- DVLOG(1) << "Could not decrypt data.";
- return nullptr;
- }
- DCHECK_EQ(decrypted_text.size(), encrypted_text.size());
- scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom(
- reinterpret_cast<const uint8_t*>(sample), sample_size);
- CopySubsamples(subsamples, kDstContainsClearBytes,
- reinterpret_cast<const uint8_t*>(decrypted_text.data()),
- output->writable_data());
- CopyExtraSettings(input, output.get());
- return output;
- }
- } // namespace media
|