Use FOURCC as protection scheme parameter

- Remove EncryptionMode enums
- Remove AesEncryptor::InitializeWithRandomIv, replaced with
  a static function AesCryptor::GenerateRandomIv, which should
  be called to generate the iv if the iv is empty.

This change is to prepare support for CBCS and CENS pattern-based
protection schemes.

Issue #77

Change-Id: Icba35089d6e451cbea7ebbf5dd5674079f206390
This commit is contained in:
KongQun Yang 2016-04-08 11:41:17 -07:00
parent 0218d9c690
commit 2ac57bf9b9
26 changed files with 197 additions and 204 deletions

View File

@ -25,7 +25,7 @@
#include "packager/base/time/clock.h"
#include "packager/media/base/container_names.h"
#include "packager/media/base/demuxer.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/key_source.h"
#include "packager/media/base/muxer_options.h"
#include "packager/media/base/muxer_util.h"
@ -105,15 +105,19 @@ std::string DetermineTextFileFormat(const std::string& file) {
return "";
}
edash_packager::media::EncryptionMode GetEncryptionMode(
edash_packager::media::FourCC GetProtectionScheme(
const std::string& protection_scheme) {
if (protection_scheme == "cenc") {
return edash_packager::media::kEncryptionModeAesCtr;
return edash_packager::media::FOURCC_cenc;
} else if (protection_scheme == "cens") {
return edash_packager::media::FOURCC_cens;
} else if (protection_scheme == "cbc1") {
return edash_packager::media::kEncryptionModeAesCbc;
return edash_packager::media::FOURCC_cbc1;
} else if (protection_scheme == "cbcs") {
return edash_packager::media::FOURCC_cbcs;
} else {
LOG(ERROR) << "Unknown protection scheme: " << protection_scheme;
return edash_packager::media::kEncryptionModeUnknown;
return edash_packager::media::FOURCC_NULL;
}
}
@ -310,7 +314,7 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
FLAGS_max_sd_pixels,
FLAGS_clear_lead,
FLAGS_crypto_period_duration,
GetEncryptionMode(FLAGS_protection_scheme));
GetProtectionScheme(FLAGS_protection_scheme));
}
scoped_ptr<MuxerListener> muxer_listener;
@ -374,11 +378,11 @@ Status RunRemuxJobs(const std::vector<RemuxJob*>& remux_jobs) {
}
bool RunPackager(const StreamDescriptorList& stream_descriptors) {
EncryptionMode encryption_mode = GetEncryptionMode(FLAGS_protection_scheme);
if (encryption_mode == kEncryptionModeUnknown)
const FourCC protection_scheme = GetProtectionScheme(FLAGS_protection_scheme);
if (protection_scheme == FOURCC_NULL)
return false;
if (encryption_mode == kEncryptionModeAesCbc && !FLAGS_iv.empty()) {
if (FLAGS_iv.size() != 16) {
if (protection_scheme == FOURCC_cbc1 || protection_scheme == FOURCC_cbcs) {
if (!FLAGS_iv.empty() && FLAGS_iv.size() != 16) {
LOG(ERROR) << "Iv size should be 16 bytes for CBC encryption mode.";
return false;
}

View File

@ -7,6 +7,8 @@
#include "packager/media/base/aes_cryptor.h"
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "packager/base/logging.h"
#include "packager/base/stl_util.h"
@ -53,6 +55,25 @@ size_t AesCryptor::NumPaddingBytes(size_t size) const {
return 0;
}
bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
std::vector<uint8_t>* iv) {
// ISO/IEC 23001-7:2016 10.1 and 10.3 For 'cenc' and 'cens'
// default_Per_Sample_IV_Size and Per_Sample_IV_Size SHOULD be 8-bytes.
// There is no official guideline on the iv size for 'cbc1' and 'cbcs',
// but 16-byte provides better security.
const size_t iv_size =
(protection_scheme == FOURCC_cenc || protection_scheme == FOURCC_cens)
? 8
: 16;
iv->resize(iv_size);
if (RAND_bytes(iv->data(), iv_size) != 1) {
LOG(ERROR) << "RAND_bytes failed with error: "
<< ERR_error_string(ERR_get_error(), NULL);
return false;
}
return true;
}
} // namespace media
} // namespace edash_packager

View File

@ -12,6 +12,7 @@
#include "packager/base/macros.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/fourccs.h"
struct aes_key_st;
typedef struct aes_key_st AES_KEY;
@ -58,6 +59,13 @@ class AesCryptor {
/// @return The current iv.
const std::vector<uint8_t>& iv() const { return iv_; }
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
/// 'cbc1', 'cbcs', which is useful to determine the random iv size.
/// @param iv points to generated initialization vector.
/// @return true on success, false otherwise.
static bool GenerateRandomIv(FourCC protection_scheme,
std::vector<uint8_t>* iv);
protected:
void set_iv(const std::vector<uint8_t>& iv) { iv_ = iv; }
const AES_KEY* aes_key() const { return aes_key_.get(); }

View File

@ -220,12 +220,12 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
EXPECT_EQ(encrypted, encrypted_verify);
}
TEST_F(AesCtrEncryptorTest, InitWithRandomIv) {
const uint8_t kIvSize = 8;
ASSERT_TRUE(encryptor_.InitializeWithRandomIv(key_, kIvSize));
ASSERT_EQ(kIvSize, encryptor_.iv().size());
LOG(INFO) << "Random IV: "
<< base::HexEncode(&encryptor_.iv()[0], encryptor_.iv().size());
TEST_F(AesCtrEncryptorTest, GenerateRandomIv) {
const uint8_t kCencIvSize = 8;
std::vector<uint8_t> iv;
ASSERT_TRUE(AesCryptor::GenerateRandomIv(FOURCC_cenc, &iv));
ASSERT_EQ(kCencIvSize, iv.size());
LOG(INFO) << "Random IV: " << base::HexEncode(iv.data(), iv.size());
}
TEST_F(AesCtrEncryptorTest, UnsupportedKeySize) {
@ -238,10 +238,6 @@ TEST_F(AesCtrEncryptorTest, UnsupportedIV) {
ASSERT_FALSE(encryptor_.InitializeWithIv(key_, iv));
}
TEST_F(AesCtrEncryptorTest, IncorrectIvSize) {
ASSERT_FALSE(encryptor_.InitializeWithRandomIv(key_, 15));
}
class AesCtrEncryptorSubsampleTest
: public AesCtrEncryptorTest,
public ::testing::WithParamInterface<SubsampleTestCase> {};

View File

@ -7,8 +7,6 @@
#include "packager/media/base/aes_encryptor.h"
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "packager/base/logging.h"
@ -40,17 +38,6 @@ namespace media {
AesEncryptor::AesEncryptor() {}
AesEncryptor::~AesEncryptor() {}
bool AesEncryptor::InitializeWithRandomIv(const std::vector<uint8_t>& key,
uint8_t iv_size) {
std::vector<uint8_t> iv(iv_size, 0);
if (RAND_bytes(iv.data(), iv_size) != 1) {
LOG(ERROR) << "RAND_bytes failed with error: "
<< ERR_error_string(ERR_get_error(), NULL);
return false;
}
return InitializeWithIv(key, iv);
}
bool AesEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv) {
if (!IsKeySizeValidForAes(key.size())) {

View File

@ -24,11 +24,6 @@ class AesEncryptor : public AesCryptor {
AesEncryptor();
~AesEncryptor() override;
/// Initialize the encryptor with specified key and a random generated IV
/// of the specified size.
/// @return true on successful initialization, false otherwise.
bool InitializeWithRandomIv(const std::vector<uint8_t>& key, uint8_t iv_size);
/// Initialize the encryptor with specified key and IV.
/// @return true on successful initialization, false otherwise.
bool InitializeWithIv(const std::vector<uint8_t>& key,

View File

@ -9,14 +9,19 @@
namespace edash_packager {
namespace media {
DecryptConfig::DecryptConfig(const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<SubsampleEntry>& subsamples)
: DecryptConfig(key_id, iv, subsamples, FOURCC_cenc) {}
DecryptConfig::DecryptConfig(const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<SubsampleEntry>& subsamples,
EncryptionMode decryption_mode)
FourCC protection_scheme)
: key_id_(key_id),
iv_(iv),
subsamples_(subsamples),
decryption_mode_(decryption_mode) {
protection_scheme_(protection_scheme) {
CHECK_GT(key_id.size(), 0u);
}

View File

@ -11,7 +11,7 @@
#include <vector>
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
namespace edash_packager {
namespace media {
@ -42,23 +42,35 @@ class DecryptConfig {
/// Keys are always 128 bits.
static const size_t kDecryptionKeySize = 16;
/// Create a 'cenc' decrypt config.
/// @param key_id is the ID that references the decryption key.
/// @param iv is the initialization vector defined by the encryptor.
/// @param subsamples defines the clear and encrypted portions of the sample
/// as described in SubsampleEntry. A decrypted buffer will be equal
/// in size to the sum of the subsample sizes.
/// @param decryption_mode decryption_mode is to determine which decryptor to
/// use.
DecryptConfig(const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<SubsampleEntry>& subsamples);
/// Create a general decrypt config with possible pattern-based encryption.
/// @param key_id is the ID that references the decryption key.
/// @param iv is the initialization vector defined by the encryptor.
/// @param subsamples defines the clear and encrypted portions of the sample
/// as described in SubsampleEntry. A decrypted buffer will be equal
/// in size to the sum of the subsample sizes.
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
/// 'cbc1', 'cbcs'.
DecryptConfig(const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& iv,
const std::vector<SubsampleEntry>& subsamples,
EncryptionMode decryption_mode);
FourCC protection_scheme);
~DecryptConfig();
const std::vector<uint8_t>& key_id() const { return key_id_; }
const std::vector<uint8_t>& iv() const { return iv_; }
const std::vector<SubsampleEntry>& subsamples() const { return subsamples_; }
EncryptionMode decryption_mode() const { return decryption_mode_; }
FourCC protection_scheme() const { return protection_scheme_; }
private:
const std::vector<uint8_t> key_id_;
@ -70,7 +82,7 @@ class DecryptConfig {
// (less data ignored by data_offset_) is encrypted.
const std::vector<SubsampleEntry> subsamples_;
EncryptionMode decryption_mode_;
const FourCC protection_scheme_;
DISALLOW_COPY_AND_ASSIGN(DecryptConfig);
};

View File

@ -8,6 +8,7 @@
#include "packager/base/logging.h"
#include "packager/base/stl_util.h"
#include "packager/media/base/aes_decryptor.h"
namespace edash_packager {
namespace media {
@ -39,16 +40,16 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
}
scoped_ptr<AesCryptor> aes_decryptor;
switch (decrypt_config->decryption_mode()) {
case kEncryptionModeAesCtr:
switch (decrypt_config->protection_scheme()) {
case FOURCC_cenc:
aes_decryptor.reset(new AesCtrDecryptor);
break;
case kEncryptionModeAesCbc:
case FOURCC_cbc1:
aes_decryptor.reset(new AesCbcDecryptor(kNoPadding, kChainAcrossCalls));
break;
default:
LOG(ERROR) << "Unsupported Decryption Mode: "
<< decrypt_config->decryption_mode();
LOG(ERROR) << "Unsupported protection scheme: "
<< decrypt_config->protection_scheme();
return false;
}

View File

@ -81,10 +81,9 @@ TEST_F(DecryptorSourceTest, FullSampleDecryption) {
DecryptConfig decrypt_config(key_id_,
std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
std::vector<SubsampleEntry>(),
kEncryptionModeAesCtr);
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(&decrypt_config, &buffer_[0],
buffer_.size()));
std::vector<SubsampleEntry>());
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(
&decrypt_config, &buffer_[0], buffer_.size()));
EXPECT_EQ(std::vector<uint8_t>(
kExpectedDecryptedBuffer,
kExpectedDecryptedBuffer + arraysize(kExpectedDecryptedBuffer)),
@ -95,7 +94,7 @@ TEST_F(DecryptorSourceTest, FullSampleDecryption) {
buffer_.assign(kBuffer2, kBuffer2 + arraysize(kBuffer2));
DecryptConfig decrypt_config2(
key_id_, std::vector<uint8_t>(kIv2, kIv2 + arraysize(kIv2)),
std::vector<SubsampleEntry>(), kEncryptionModeAesCtr);
std::vector<SubsampleEntry>());
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(
&decrypt_config2, &buffer_[0], buffer_.size()));
EXPECT_EQ(std::vector<uint8_t>(kExpectedDecryptedBuffer2,
@ -130,8 +129,7 @@ TEST_F(DecryptorSourceTest, SubsampleDecryption) {
DecryptConfig decrypt_config(
key_id_, std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
std::vector<SubsampleEntry>(kSubsamples,
kSubsamples + arraysize(kSubsamples)),
kEncryptionModeAesCtr);
kSubsamples + arraysize(kSubsamples)));
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(
&decrypt_config, &buffer_[0], buffer_.size()));
EXPECT_EQ(std::vector<uint8_t>(
@ -155,8 +153,7 @@ TEST_F(DecryptorSourceTest, SubsampleDecryptionSizeValidation) {
DecryptConfig decrypt_config(
key_id_, std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
std::vector<SubsampleEntry>(kSubsamples,
kSubsamples + arraysize(kSubsamples)),
kEncryptionModeAesCtr);
kSubsamples + arraysize(kSubsamples)));
ASSERT_FALSE(decryptor_source_.DecryptSampleBuffer(
&decrypt_config, &buffer_[0], buffer_.size()));
}
@ -167,8 +164,7 @@ TEST_F(DecryptorSourceTest, DecryptFailedIfGetKeyFailed) {
DecryptConfig decrypt_config(key_id_,
std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
std::vector<SubsampleEntry>(),
kEncryptionModeAesCtr);
std::vector<SubsampleEntry>());
ASSERT_FALSE(decryptor_source_.DecryptSampleBuffer(
&decrypt_config, &buffer_[0], buffer_.size()));
}

View File

@ -1,23 +0,0 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef MEDIA_BASE_ENCRYPTION_MODE_H_
#define MEDIA_BASE_ENCRYPTION_MODE_H_
namespace edash_packager {
namespace media {
/// Supported encryption mode.
enum EncryptionMode {
kEncryptionModeUnknown,
kEncryptionModeAesCtr,
kEncryptionModeAesCbc
};
} // namespace media
} // namespace edash_packager
#endif // MEDIA_BASE_ENCRYPTION_MODE_H_

View File

@ -21,7 +21,9 @@ enum FourCC {
FOURCC_avcC = 0x61766343,
FOURCC_bloc = 0x626C6F63,
FOURCC_cbc1 = 0x63626331,
FOURCC_cbcs = 0x63626373,
FOURCC_cenc = 0x63656e63,
FOURCC_cens = 0x63656e73,
FOURCC_co64 = 0x636f3634,
FOURCC_ctim = 0x6374696d,
FOURCC_ctts = 0x63747473,

View File

@ -6,6 +6,7 @@
#include "packager/media/base/muxer.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/media_sample.h"
#include "packager/media/base/media_stream.h"
@ -19,7 +20,7 @@ Muxer::Muxer(const MuxerOptions& options)
max_sd_pixels_(0),
clear_lead_in_seconds_(0),
crypto_period_duration_in_seconds_(0),
encryption_mode_(kEncryptionModeUnknown),
protection_scheme_(FOURCC_NULL),
cancelled_(false),
clock_(NULL) {}
@ -29,13 +30,13 @@ void Muxer::SetKeySource(KeySource* encryption_key_source,
uint32_t max_sd_pixels,
double clear_lead_in_seconds,
double crypto_period_duration_in_seconds,
EncryptionMode encryption_mode) {
FourCC protection_scheme) {
DCHECK(encryption_key_source);
encryption_key_source_ = encryption_key_source;
max_sd_pixels_ = max_sd_pixels;
clear_lead_in_seconds_ = clear_lead_in_seconds;
crypto_period_duration_in_seconds_ = crypto_period_duration_in_seconds;
encryption_mode_ = encryption_mode;
protection_scheme_ = protection_scheme;
}
void Muxer::AddStream(MediaStream* stream) {

View File

@ -14,7 +14,7 @@
#include "packager/base/memory/ref_counted.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/base/time/clock.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/muxer_options.h"
#include "packager/media/base/status.h"
#include "packager/media/event/muxer_listener.h"
@ -45,11 +45,13 @@ class Muxer {
/// @param crypto_period_duration_in_seconds specifies crypto period duration
/// in seconds. A positive value means key rotation is enabled, the
/// key source must support key rotation in this case.
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
/// 'cbc1', 'cbcs'.
void SetKeySource(KeySource* encryption_key_source,
uint32_t max_sd_pixels,
double clear_lead_in_seconds,
double crypto_period_duration_in_seconds,
EncryptionMode encryption_mode);
FourCC protection_scheme);
/// Add video/audio stream.
void AddStream(MediaStream* stream);
@ -94,7 +96,7 @@ class Muxer {
MuxerListener* muxer_listener() { return muxer_listener_.get(); }
ProgressListener* progress_listener() { return progress_listener_.get(); }
base::Clock* clock() { return clock_; }
EncryptionMode encryption_mode() const { return encryption_mode_; }
FourCC protection_scheme() const { return protection_scheme_; }
private:
friend class MediaStream; // Needed to access AddSample.
@ -120,7 +122,7 @@ class Muxer {
uint32_t max_sd_pixels_;
double clear_lead_in_seconds_;
double crypto_period_duration_in_seconds_;
EncryptionMode encryption_mode_;
FourCC protection_scheme_;
bool cancelled_;
scoped_ptr<MuxerListener> muxer_listener_;

View File

@ -22,9 +22,6 @@ namespace media {
namespace mp4 {
namespace {
// Generate 64bit IV by default.
const size_t kDefaultIvSizeForCtr = 8u;
const size_t kDefaultIvSizeForCbc = 16u;
const size_t kCencBlockSize = 16u;
// Adds one or more subsamples to |*subsamples|. This may add more than one
@ -66,14 +63,14 @@ EncryptingFragmenter::EncryptingFragmenter(
TrackFragment* traf,
scoped_ptr<EncryptionKey> encryption_key,
int64_t clear_time,
EncryptionMode encryption_mode)
FourCC protection_scheme)
: Fragmenter(traf),
info_(info),
encryption_key_(encryption_key.Pass()),
nalu_length_size_(GetNaluLengthSize(*info)),
video_codec_(GetVideoCodec(*info)),
clear_time_(clear_time),
encryption_mode_(encryption_mode) {
protection_scheme_(protection_scheme) {
DCHECK(encryption_key_);
if (video_codec_ == kCodecVP8) {
vpx_parser_.reset(new VP8Parser);
@ -175,22 +172,21 @@ void EncryptingFragmenter::FinalizeFragmentForEncryption() {
Status EncryptingFragmenter::CreateEncryptor() {
DCHECK(encryption_key_);
scoped_ptr<AesEncryptor> encryptor;
size_t default_iv_size = 0;
if (encryption_mode_ == kEncryptionModeAesCtr) {
encryptor.reset(new AesCtrEncryptor);
default_iv_size = kDefaultIvSizeForCtr;
} else if (encryption_mode_ == kEncryptionModeAesCbc) {
encryptor.reset(new AesCbcEncryptor(kNoPadding, kChainAcrossCalls));
default_iv_size = kDefaultIvSizeForCbc;
} else {
return Status(error::MUXER_FAILURE, "Unsupported encryption mode.");
scoped_ptr<AesCryptor> encryptor;
switch (protection_scheme_) {
case FOURCC_cenc:
encryptor.reset(new AesCtrEncryptor);
break;
case FOURCC_cbc1:
encryptor.reset(new AesCbcEncryptor(kNoPadding, kChainAcrossCalls));
break;
default:
return Status(error::MUXER_FAILURE, "Unsupported protection scheme.");
}
const bool initialized = encryption_key_->iv.empty()
? encryptor->InitializeWithRandomIv(
encryption_key_->key, default_iv_size)
: encryptor->InitializeWithIv(
encryption_key_->key, encryption_key_->iv);
DCHECK(!encryption_key_->iv.empty());
const bool initialized =
encryptor->InitializeWithIv(encryption_key_->key, encryption_key_->iv);
if (!initialized)
return Status(error::MUXER_FAILURE, "Failed to create the encryptor.");
encryptor_ = encryptor.Pass();
@ -229,7 +225,7 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
// within the superframe.
// For AES-CBC mode 'cbc1' scheme, clear data is sized appropriately so
// that the cipher data is block aligned.
if (is_superframe || encryption_mode_ == kEncryptionModeAesCbc) {
if (is_superframe || protection_scheme_ == FOURCC_cbc1) {
const uint16_t misalign_bytes =
subsample.cipher_bytes % kCencBlockSize;
subsample.clear_bytes += misalign_bytes;
@ -271,7 +267,7 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
// For AES-CBC mode 'cbc1' scheme, clear data is sized appropriately
// so that the cipher data is block aligned.
if (encryption_mode_ == kEncryptionModeAesCbc) {
if (protection_scheme_ == FOURCC_cbc1) {
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
current_clear_bytes += misalign_bytes;
cipher_bytes -= misalign_bytes;
@ -303,7 +299,7 @@ Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
uint64_t encryption_data_size = sample->data_size();
// AES-CBC mode requires all encrypted cipher blocks to be 16 bytes. The
// partial blocks are left unencrypted.
if (encryption_mode_ == kEncryptionModeAesCbc)
if (protection_scheme_ == FOURCC_cbc1)
encryption_data_size -= encryption_data_size % kCencBlockSize;
EncryptBytes(data, encryption_data_size);
}

View File

@ -9,7 +9,7 @@
#include "packager/base/memory/ref_counted.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/filters/vpx_parser.h"
#include "packager/media/formats/mp4/fragmenter.h"
#include "packager/media/formats/mp4/video_slice_header_parser.h"
@ -17,7 +17,7 @@
namespace edash_packager {
namespace media {
class AesEncryptor;
class AesCryptor;
class StreamInfo;
struct EncryptionKey;
@ -30,11 +30,13 @@ class EncryptingFragmenter : public Fragmenter {
/// @param encryption_key contains the encryption parameters.
/// @param clear_time specifies clear lead duration in units of the current
/// track's timescale.
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
/// 'cbc1', 'cbcs'.
EncryptingFragmenter(scoped_refptr<StreamInfo> info,
TrackFragment* traf,
scoped_ptr<EncryptionKey> encryption_key,
int64_t clear_time,
EncryptionMode encryption_mode);
FourCC protection_scheme);
~EncryptingFragmenter() override;
@ -57,8 +59,9 @@ class EncryptingFragmenter : public Fragmenter {
/// @return OK on success, an error status otherwise.
Status CreateEncryptor();
EncryptionKey* encryption_key() { return encryption_key_.get(); }
AesEncryptor* encryptor() { return encryptor_.get(); }
const EncryptionKey* encryption_key() const { return encryption_key_.get(); }
AesCryptor* encryptor() { return encryptor_.get(); }
FourCC protection_scheme() const { return protection_scheme_; }
void set_encryption_key(scoped_ptr<EncryptionKey> encryption_key) {
encryption_key_ = encryption_key.Pass();
@ -73,14 +76,14 @@ class EncryptingFragmenter : public Fragmenter {
scoped_refptr<StreamInfo> info_;
scoped_ptr<EncryptionKey> encryption_key_;
scoped_ptr<AesEncryptor> encryptor_;
scoped_ptr<AesCryptor> encryptor_;
// If this stream contains AVC, subsample encryption specifies that the size
// and type of NAL units remain unencrypted. This function returns the size of
// the size field in bytes. Can be 1, 2 or 4 bytes.
const uint8_t nalu_length_size_;
const VideoCodec video_codec_;
int64_t clear_time_;
EncryptionMode encryption_mode_;
FourCC protection_scheme_;
scoped_ptr<VPxParser> vpx_parser_;
scoped_ptr<VideoSliceHeaderParser> header_parser_;

View File

@ -24,13 +24,13 @@ KeyRotationFragmenter::KeyRotationFragmenter(MovieFragment* moof,
KeySource::TrackType track_type,
int64_t crypto_period_duration,
int64_t clear_time,
MuxerListener* muxer_listener,
EncryptionMode encryption_mode)
FourCC protection_scheme,
MuxerListener* muxer_listener)
: EncryptingFragmenter(info,
traf,
scoped_ptr<EncryptionKey>(new EncryptionKey()),
clear_time,
encryption_mode),
protection_scheme),
moof_(moof),
encryption_key_source_(encryption_key_source),
track_type_(track_type),
@ -55,6 +55,12 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption(
current_crypto_period_index, track_type_, encryption_key.get());
if (!status.ok())
return status;
if (encryption_key->iv.empty()) {
if (!AesCryptor::GenerateRandomIv(protection_scheme(),
&encryption_key->iv)) {
return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
}
}
set_encryption_key(encryption_key.Pass());
prev_crypto_period_index_ = current_crypto_period_index;
need_to_refresh_encryptor = true;

View File

@ -7,7 +7,7 @@
#ifndef MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_
#define MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/key_source.h"
#include "packager/media/event/muxer_listener.h"
#include "packager/media/formats/mp4/encrypting_fragmenter.h"
@ -32,6 +32,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
/// of the current track's timescale.
/// @param clear_time specifies clear lead duration in units of the current
/// track's timescale.
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
/// 'cbc1', 'cbcs'.
/// @param muxer_listener is a pointer to MuxerListener for notifying
/// muxer related events. This may be null.
KeyRotationFragmenter(MovieFragment* moof,
@ -41,8 +43,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
KeySource::TrackType track_type,
int64_t crypto_period_duration,
int64_t clear_time,
MuxerListener* muxer_listener,
EncryptionMode encryption_mode);
FourCC protection_scheme,
MuxerListener* muxer_listener);
~KeyRotationFragmenter() override;
protected:

View File

@ -147,15 +147,10 @@ Status MP4Muxer::Initialize() {
new MultiSegmentSegmenter(options(), ftyp.Pass(), moov.Pass()));
}
Status segmenter_initialized =
segmenter_->Initialize(streams(),
muxer_listener(),
progress_listener(),
encryption_key_source(),
max_sd_pixels(),
clear_lead_in_seconds(),
crypto_period_duration_in_seconds(),
encryption_mode());
const Status segmenter_initialized = segmenter_->Initialize(
streams(), muxer_listener(), progress_listener(), encryption_key_source(),
max_sd_pixels(), clear_lead_in_seconds(),
crypto_period_duration_in_seconds(), protection_scheme());
if (!segmenter_initialized.ok())
return segmenter_initialized;

View File

@ -9,6 +9,7 @@
#include <algorithm>
#include "packager/base/stl_util.h"
#include "packager/media/base/aes_cryptor.h"
#include "packager/media/base/buffer_writer.h"
#include "packager/media/base/key_source.h"
#include "packager/media/base/media_sample.h"
@ -26,8 +27,6 @@ namespace mp4 {
namespace {
// Generate 64bit IV by default.
const size_t kDefaultIvSize = 8u;
const size_t kCencKeyIdSize = 16u;
// The version of cenc implemented here. CENC 4.
@ -50,26 +49,24 @@ uint64_t Rescale(uint64_t time_in_old_scale,
void GenerateSinf(const EncryptionKey& encryption_key,
FourCC old_type,
EncryptionMode encryption_mode,
FourCC protection_scheme,
ProtectionSchemeInfo* sinf) {
sinf->format.format = old_type;
if (encryption_mode == kEncryptionModeAesCtr){
sinf->type.type = FOURCC_cenc;
} else if (encryption_mode == kEncryptionModeAesCbc) {
sinf->type.type = FOURCC_cbc1;
}
DCHECK_NE(protection_scheme, FOURCC_NULL);
sinf->type.type = protection_scheme;
sinf->type.version = kCencSchemeVersion;
sinf->info.track_encryption.is_encrypted = true;
sinf->info.track_encryption.default_iv_size =
encryption_key.iv.empty() ? kDefaultIvSize : encryption_key.iv.size();
sinf->info.track_encryption.default_kid = encryption_key.key_id;
auto& track_encryption = sinf->info.track_encryption;
track_encryption.is_encrypted = true;
DCHECK(!encryption_key.iv.empty());
track_encryption.default_iv_size = encryption_key.iv.size();
track_encryption.default_kid = encryption_key.key_id;
}
void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key,
double clear_lead_in_seconds,
EncryptionMode encryption_mode,
FourCC protection_scheme,
SampleDescription* description) {
DCHECK(description);
if (description->type == kVideo) {
@ -81,7 +78,7 @@ void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key,
// Convert the first entry to an encrypted entry.
VideoSampleEntry& entry = description->video_entries[0];
GenerateSinf(encryption_key, entry.format, encryption_mode, &entry.sinf);
GenerateSinf(encryption_key, entry.format, protection_scheme, &entry.sinf);
entry.format = FOURCC_encv;
} else {
DCHECK_EQ(kAudio, description->type);
@ -93,7 +90,7 @@ void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key,
// Convert the first entry to an encrypted entry.
AudioSampleEntry& entry = description->audio_entries[0];
GenerateSinf(encryption_key, entry.format, encryption_mode, &entry.sinf);
GenerateSinf(encryption_key, entry.format, protection_scheme, &entry.sinf);
entry.format = FOURCC_enca;
}
}
@ -137,7 +134,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
uint32_t max_sd_pixels,
double clear_lead_in_seconds,
double crypto_period_duration_in_seconds,
EncryptionMode encryption_mode) {
FourCC protection_scheme) {
DCHECK_LT(0u, streams.size());
muxer_listener_ = muxer_listener;
progress_listener_ = progress_listener;
@ -173,8 +170,10 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
encryption_key.key_id.assign(
kKeyRotationDefaultKeyId,
kKeyRotationDefaultKeyId + arraysize(kKeyRotationDefaultKeyId));
if (!AesCryptor::GenerateRandomIv(protection_scheme, &encryption_key.iv))
return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
GenerateEncryptedSampleEntry(encryption_key, clear_lead_in_seconds,
encryption_mode, &description);
protection_scheme, &description);
if (muxer_listener_) {
muxer_listener_->OnEncryptionInfoReady(
kInitialEncryptionInfo, encryption_key.key_id,
@ -186,7 +185,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
encryption_key_source, track_type,
crypto_period_duration_in_seconds * streams[i]->info()->time_scale(),
clear_lead_in_seconds * streams[i]->info()->time_scale(),
muxer_listener_, encryption_mode);
protection_scheme, muxer_listener_);
continue;
}
@ -195,9 +194,13 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
encryption_key_source->GetKey(track_type, encryption_key.get());
if (!status.ok())
return status;
if (encryption_key->iv.empty()) {
if (!AesCryptor::GenerateRandomIv(protection_scheme, &encryption_key->iv))
return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
}
GenerateEncryptedSampleEntry(*encryption_key, clear_lead_in_seconds,
encryption_mode, &description);
protection_scheme, &description);
if (moov_->pssh.empty()) {
moov_->pssh.resize(encryption_key->key_system_info.size());
@ -215,7 +218,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
fragmenters_[i] = new EncryptingFragmenter(
streams[i]->info(), &moof_->tracks[i], encryption_key.Pass(),
clear_lead_in_seconds * streams[i]->info()->time_scale(),
encryption_mode);
protection_scheme);
}
// Choose the first stream if there is no VIDEO.

View File

@ -12,7 +12,7 @@
#include "packager/base/memory/ref_counted.h"
#include "packager/base/memory/scoped_ptr.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/status.h"
#include "packager/media/formats/mp4/box_definitions.h"
@ -59,6 +59,8 @@ class Segmenter {
/// pixels per frame than max_sd_pixels, it is HD, SD otherwise.
/// @param clear_time specifies clear lead duration in seconds.
/// @param crypto_period_duration specifies crypto period duration in seconds.
/// @param protection_scheme specifies the protection scheme: 'senc', 'sens',
/// 'cbc1', 'cbcs'.
/// @return OK on success, an error status otherwise.
Status Initialize(const std::vector<MediaStream*>& streams,
MuxerListener* muxer_listener,
@ -67,7 +69,7 @@ class Segmenter {
uint32_t max_sd_pixels,
double clear_lead_in_seconds,
double crypto_period_duration_in_seconds,
EncryptionMode encryption_mode);
FourCC protection_scheme);
/// Finalize the segmenter.
/// @return OK on success, an error status otherwise.

View File

@ -8,7 +8,7 @@
#include <limits>
#include "packager/media/base/buffer_reader.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/rcheck.h"
#include "packager/media/formats/mp4/chunk_info_iterator.h"
#include "packager/media/formats/mp4/composition_offset_iterator.h"
@ -600,24 +600,10 @@ scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
FourCC protection_scheme = is_audio() ? audio_description().sinf.type.type
: video_description().sinf.type.type;
EncryptionMode decryption_mode;
switch (protection_scheme) {
case FOURCC_cenc:
decryption_mode = kEncryptionModeAesCtr;
break;
case FOURCC_cbc1:
decryption_mode = kEncryptionModeAesCbc;
break;
default:
LOG(ERROR) << "Unsupported protection scheme.";
return scoped_ptr<DecryptConfig>();
}
return scoped_ptr<DecryptConfig>(new DecryptConfig(
track_encryption().default_kid,
sample_encryption_entry.initialization_vector,
sample_encryption_entry.subsamples,
decryption_mode));
return scoped_ptr<DecryptConfig>(
new DecryptConfig(track_encryption().default_kid,
sample_encryption_entry.initialization_vector,
sample_encryption_entry.subsamples, protection_scheme));
}
} // namespace mp4

View File

@ -7,6 +7,7 @@
#include "packager/media/formats/webm/encryptor.h"
#include "packager/media/base/aes_encryptor.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/media_sample.h"
namespace edash_packager {
@ -14,9 +15,6 @@ namespace media {
namespace webm {
namespace {
// Generate 64bit IV by default.
const size_t kDefaultIvSize = 8u;
Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) {
if (!track->AddContentEncoding()) {
return Status(error::INTERNAL_ERROR,
@ -107,13 +105,14 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
Status status = key_source->GetKey(track_type, encryption_key.get());
if (!status.ok())
return status;
if (encryption_key->iv.empty()) {
if (!AesCryptor::GenerateRandomIv(FOURCC_cenc, &encryption_key->iv))
return Status(error::INTERNAL_ERROR, "Failed to generate random iv.");
}
scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
const bool initialized = encryption_key->iv.empty()
? encryptor->InitializeWithRandomIv(
encryption_key->key, kDefaultIvSize)
: encryptor->InitializeWithIv(
encryption_key->key, encryption_key->iv);
const bool initialized =
encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv);
if (!initialized)
return Status(error::INTERNAL_ERROR, "Failed to create the encryptor.");

View File

@ -6,7 +6,6 @@
#include "packager/base/logging.h"
#include "packager/base/sys_byteorder.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/formats/webm/webm_constants.h"
namespace edash_packager {
@ -56,8 +55,7 @@ bool WebMCreateDecryptConfig(const uint8_t* data,
decrypt_config->reset(new DecryptConfig(
std::vector<uint8_t>(key_id, key_id + key_id_size),
std::vector<uint8_t>(counter_block.begin(), counter_block.end()),
std::vector<SubsampleEntry>(),
kEncryptionModeAesCtr));
std::vector<SubsampleEntry>()));
*data_offset = frame_offset;
return true;

View File

@ -6,6 +6,7 @@
#include "packager/media/formats/webm/webm_muxer.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/media_sample.h"
#include "packager/media/base/media_stream.h"
#include "packager/media/base/stream_info.h"
@ -30,12 +31,11 @@ Status WebMMuxer::Initialize() {
"Key rotation is not implemented for WebM");
}
if (encryption_key_source() && (encryption_mode() != kEncryptionModeAesCtr)) {
if (encryption_key_source() && (protection_scheme() != FOURCC_cenc)) {
NOTIMPLEMENTED()
<< "WebM muxer does not support encryption mode other than AES-CTR.";
return Status(
error::UNIMPLEMENTED,
"WebM muxer does not support encryption mode other than AES-CTR.");
<< "WebM does not support protection scheme other than 'cenc'.";
return Status(error::UNIMPLEMENTED,
"WebM does not support protection scheme other than 'cenc'.");
}
scoped_ptr<MkvWriter> writer(new MkvWriter);

View File

@ -11,8 +11,8 @@
#include "packager/base/strings/stringprintf.h"
#include "packager/base/time/clock.h"
#include "packager/media/base/demuxer.h"
#include "packager/media/base/encryption_modes.h"
#include "packager/media/base/fixed_key_source.h"
#include "packager/media/base/fourccs.h"
#include "packager/media/base/media_stream.h"
#include "packager/media/base/muxer.h"
#include "packager/media/base/stream_info.h"
@ -174,10 +174,8 @@ void PackagerTestBasic::Remux(const std::string& input,
if (enable_encryption) {
muxer_video->SetKeySource(encryption_key_source.get(),
KeySource::TRACK_TYPE_SD,
kClearLeadInSeconds,
kCryptoDurationInSeconds,
kEncryptionModeAesCtr);
KeySource::TRACK_TYPE_SD, kClearLeadInSeconds,
kCryptoDurationInSeconds, FOURCC_cenc);
}
}
@ -196,10 +194,8 @@ void PackagerTestBasic::Remux(const std::string& input,
if (enable_encryption) {
muxer_audio->SetKeySource(encryption_key_source.get(),
KeySource::TRACK_TYPE_SD,
kClearLeadInSeconds,
kCryptoDurationInSeconds,
kEncryptionModeAesCtr);
KeySource::TRACK_TYPE_SD, kClearLeadInSeconds,
kCryptoDurationInSeconds, FOURCC_cenc);
}
}