Improve support for decryption of full sample encrypted cbcs

1. Allow encryption pattern of 0:0, which is treated as 1:0;
2. Remove the special handling of pattern 1:0 in pattern cryptor
   which may not always be correct;
3. Allow senc/saio/saiz boxes to be absent.

Change-Id: I372e61182ec577107e39cb601c3aed80616b036d
This commit is contained in:
Kongqun Yang 2016-10-13 14:29:15 -07:00 committed by KongQun Yang
parent e7393fcc22
commit 4c6e5f4fa6
4 changed files with 25 additions and 62 deletions

View File

@ -23,11 +23,9 @@ AesPatternCryptor::AesPatternCryptor(uint8_t crypt_byte_block,
skip_byte_block_(skip_byte_block), skip_byte_block_(skip_byte_block),
encryption_mode_(encryption_mode), encryption_mode_(encryption_mode),
cryptor_(std::move(cryptor)) { cryptor_(std::move(cryptor)) {
// |crypt_byte_block_| should never be 0. |skip_byte_block_| can be 0 to allow // Treat pattern 0:0 as 1:0.
// a special pattern of 1:0, which is the pattern for the case of pattern if (crypt_byte_block_ == 0 && skip_byte_block_ == 0)
// encryption when applied to non video tracks. crypt_byte_block_ = 1;
DCHECK_NE(crypt_byte_block_, 0u);
DCHECK(skip_byte_block_ != 0 || crypt_byte_block_ == 1);
DCHECK(cryptor_); DCHECK(cryptor_);
DCHECK(!cryptor_->use_constant_iv()); DCHECK(!cryptor_->use_constant_iv());
} }
@ -51,17 +49,6 @@ bool AesPatternCryptor::CryptInternal(const uint8_t* text,
} }
*crypt_text_size = text_size; *crypt_text_size = text_size;
// Handle the special pattern 1:0.
if (skip_byte_block_ == 0) {
DCHECK_EQ(crypt_byte_block_, 1u);
const size_t crypt_byte_size = text_size / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
if (!cryptor_->Crypt(text, crypt_byte_size, crypt_text))
return false;
memcpy(crypt_text + crypt_byte_size, text + crypt_byte_size,
text_size - crypt_byte_size);
return true;
}
while (text_size > 0) { while (text_size > 0) {
const size_t crypt_byte_size = crypt_byte_block_ * AES_BLOCK_SIZE; const size_t crypt_byte_size = crypt_byte_block_ * AES_BLOCK_SIZE;
if (NeedEncrypt(text_size, crypt_byte_size)) { if (NeedEncrypt(text_size, crypt_byte_size)) {

View File

@ -72,7 +72,7 @@ class AesPatternCryptor : public AesCryptor {
bool NeedEncrypt(size_t input_size, size_t target_data_size); bool NeedEncrypt(size_t input_size, size_t target_data_size);
const uint8_t crypt_byte_block_; uint8_t crypt_byte_block_;
const uint8_t skip_byte_block_; const uint8_t skip_byte_block_;
const PatternEncryptionMode encryption_mode_; const PatternEncryptionMode encryption_mode_;
std::unique_ptr<AesCryptor> cryptor_; std::unique_ptr<AesCryptor> cryptor_;

View File

@ -219,35 +219,5 @@ TEST(SampleAesPatternCryptor, MoreThan16Bytes) {
ASSERT_TRUE(pattern_cryptor.Crypt("0123456789abcdef012", &crypt_text)); ASSERT_TRUE(pattern_cryptor.Crypt("0123456789abcdef012", &crypt_text));
} }
TEST(FullSampleSpecialPatternTest, Test) {
MockAesCryptor* mock_cryptor = new MockAesCryptor();
EXPECT_CALL(*mock_cryptor, CryptInternal(_, 96u, _, _))
.WillOnce(Invoke([](const uint8_t* text, size_t text_size,
uint8_t* crypt_text, size_t* crypt_text_size) {
*crypt_text_size = text_size;
for (size_t i = 0; i < text_size; ++i)
*crypt_text++ = 'e';
return true;
}));
const uint8_t kFulLSampleCryptBlock = 1;
const uint8_t kFullSampleSkipBlock = 0;
AesPatternCryptor pattern_cryptor(
kFulLSampleCryptBlock, kFullSampleSkipBlock,
AesPatternCryptor::kSkipIfCryptByteBlockRemaining,
AesPatternCryptor::kUseConstantIv,
std::unique_ptr<MockAesCryptor>(mock_cryptor));
std::vector<uint8_t> iv(8, 'i');
// SetIv will be called only once by AesPatternCryptor::SetIv.
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
std::string input_text(100, 'c');
std::string crypt_text;
// More than 16 bytes so mock's CryptInternal should be called.
ASSERT_TRUE(pattern_cryptor.Crypt(input_text, &crypt_text));
EXPECT_EQ(std::string(96, 'e') + std::string(4, 'c'), crypt_text);
}
} // namespace media } // namespace media
} // namespace shaka } // namespace shaka

View File

@ -589,24 +589,30 @@ const TrackEncryption& TrackRunIterator::track_encryption() const {
} }
std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); std::vector<uint8_t> iv;
DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size()); std::vector<SubsampleEntry> subsamples;
const SampleEncryptionEntry& sample_encryption_entry =
run_itr_->sample_encryption_entries[sample_idx];
DCHECK(is_encrypted());
DCHECK(!AuxInfoNeedsToBeCached());
const size_t total_size_of_subsamples = size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
sample_encryption_entry.GetTotalSizeOfSubsamples(); if (sample_idx < run_itr_->sample_encryption_entries.size()) {
if (total_size_of_subsamples != 0 && const SampleEncryptionEntry& sample_encryption_entry =
total_size_of_subsamples != static_cast<size_t>(sample_size())) { run_itr_->sample_encryption_entries[sample_idx];
LOG(ERROR) << "Incorrect CENC subsample size."; DCHECK(is_encrypted());
return std::unique_ptr<DecryptConfig>(); DCHECK(!AuxInfoNeedsToBeCached());
const size_t total_size_of_subsamples =
sample_encryption_entry.GetTotalSizeOfSubsamples();
if (total_size_of_subsamples != 0 &&
total_size_of_subsamples != static_cast<size_t>(sample_size())) {
LOG(ERROR) << "Incorrect CENC subsample size.";
return std::unique_ptr<DecryptConfig>();
}
iv = sample_encryption_entry.initialization_vector;
subsamples = sample_encryption_entry.subsamples;
} }
FourCC protection_scheme = is_audio() ? audio_description().sinf.type.type FourCC protection_scheme = is_audio() ? audio_description().sinf.type.type
: video_description().sinf.type.type; : video_description().sinf.type.type;
std::vector<uint8_t> iv = sample_encryption_entry.initialization_vector;
if (iv.empty()) { if (iv.empty()) {
if (protection_scheme != FOURCC_cbcs) { if (protection_scheme != FOURCC_cbcs) {
LOG(WARNING) LOG(WARNING)
@ -619,8 +625,8 @@ std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
} }
} }
return std::unique_ptr<DecryptConfig>(new DecryptConfig( return std::unique_ptr<DecryptConfig>(new DecryptConfig(
track_encryption().default_kid, iv, sample_encryption_entry.subsamples, track_encryption().default_kid, iv, subsamples, protection_scheme,
protection_scheme, track_encryption().default_crypt_byte_block, track_encryption().default_crypt_byte_block,
track_encryption().default_skip_byte_block)); track_encryption().default_skip_byte_block));
} }