Add support for "AES 128-bit Cipher Block Chaining (CBC-128) Encryption"
- Part 1. - Add packager command line argument "protection_scheme" to specify protection scheme. Plumb through packager code to enable CBC encryption/decryption. - Add scheme type "cbc1" to sinf. - Refactor AES encryptor and decryptor. - Need more work in the subsample handling. Issue #77 Change-Id: I3a9304d89adf5efbfb226b6e805a3077b6cb8c68
This commit is contained in:
parent
ef81be5f7b
commit
e39c3572af
|
@ -25,6 +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/key_source.h"
|
||||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/base/muxer_util.h"
|
||||
|
@ -104,6 +105,18 @@ std::string DetermineTextFileFormat(const std::string& file) {
|
|||
return "";
|
||||
}
|
||||
|
||||
edash_packager::media::EncryptionMode GetEncryptionMode(
|
||||
const std::string& protection_scheme) {
|
||||
if (protection_scheme == "cenc") {
|
||||
return edash_packager::media::kEncryptionModeAesCtr;
|
||||
} else if (protection_scheme == "cbc1") {
|
||||
return edash_packager::media::kEncryptionModeAesCbc;
|
||||
} else {
|
||||
LOG(ERROR) << "Protection scheme is unknown.";
|
||||
return edash_packager::media::kEncryptionModeUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
|
@ -296,7 +309,8 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
|||
muxer->SetKeySource(key_source,
|
||||
FLAGS_max_sd_pixels,
|
||||
FLAGS_clear_lead,
|
||||
FLAGS_crypto_period_duration);
|
||||
FLAGS_crypto_period_duration,
|
||||
GetEncryptionMode(FLAGS_protection_scheme));
|
||||
}
|
||||
|
||||
scoped_ptr<MuxerListener> muxer_listener;
|
||||
|
@ -360,6 +374,10 @@ 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)
|
||||
return false;
|
||||
|
||||
if (!AssignFlagsFromProfile())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -50,6 +50,10 @@ DEFINE_int32(crypto_period_duration,
|
|||
0,
|
||||
"Crypto period duration in seconds. If it is non-zero, key "
|
||||
"rotation is enabled.");
|
||||
DEFINE_string(protection_scheme,
|
||||
"cenc",
|
||||
"Choose protection scheme. Currently support cenc and cbc1. "
|
||||
"Default is cenc.");
|
||||
|
||||
namespace edash_packager {
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ DECLARE_string(aes_signing_key);
|
|||
DECLARE_string(aes_signing_iv);
|
||||
DECLARE_string(rsa_signing_key_path);
|
||||
DECLARE_int32(crypto_period_duration);
|
||||
DECLARE_string(protection_scheme);
|
||||
|
||||
namespace edash_packager {
|
||||
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
// 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
|
||||
|
||||
#include "packager/media/base/aes_decryptor.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// AES defines three key sizes: 128, 192 and 256 bits.
|
||||
bool IsKeySizeValidForAes(size_t key_size) {
|
||||
return key_size == 16 || key_size == 24 || key_size == 32;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesDecryptor::AesDecryptor() {}
|
||||
AesDecryptor::~AesDecryptor() {}
|
||||
|
||||
AesCtrDecryptor::AesCtrDecryptor() {}
|
||||
|
||||
AesCtrDecryptor::~AesCtrDecryptor() {}
|
||||
|
||||
bool AesCtrDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
encryptor_.reset(new AesCtrEncryptor);
|
||||
return encryptor_->InitializeWithIv(key, iv);
|
||||
}
|
||||
|
||||
// For AES CTR, encryption and decryption are identical.
|
||||
bool AesCtrDecryptor::Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) {
|
||||
DCHECK(encryptor_);
|
||||
return encryptor_->EncryptData(ciphertext, ciphertext_size, plaintext);
|
||||
}
|
||||
|
||||
bool AesCtrDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
DCHECK(encryptor_);
|
||||
return encryptor_->Encrypt(ciphertext, plaintext);
|
||||
}
|
||||
|
||||
bool AesCtrDecryptor::Decrypt(const std::string& ciphertext,
|
||||
std::string* plaintext) {
|
||||
DCHECK(encryptor_);
|
||||
return encryptor_->Encrypt(ciphertext, plaintext);
|
||||
}
|
||||
|
||||
bool AesCtrDecryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
DCHECK(encryptor_);
|
||||
return encryptor_->SetIv(iv);
|
||||
}
|
||||
|
||||
AesCbcPkcs5Decryptor::AesCbcPkcs5Decryptor() {}
|
||||
AesCbcPkcs5Decryptor::~AesCbcPkcs5Decryptor() {}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
if (!IsKeySizeValidForAes(key.size())) {
|
||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||
return false;
|
||||
}
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
aes_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::Decrypt(const std::string& ciphertext,
|
||||
std::string* plaintext) {
|
||||
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
|
||||
LOG(ERROR) << "Expecting cipher text size to be multiple of "
|
||||
<< AES_BLOCK_SIZE << ", got " << ciphertext.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(plaintext);
|
||||
DCHECK(aes_key_);
|
||||
|
||||
plaintext->resize(ciphertext.size());
|
||||
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
|
||||
ciphertext.size(),
|
||||
aes_key_.get(),
|
||||
&iv_[0],
|
||||
AES_DECRYPT);
|
||||
|
||||
// Strip off PKCS5 padding bytes.
|
||||
const uint8_t num_padding_bytes = (*plaintext)[plaintext->size() - 1];
|
||||
if (num_padding_bytes > AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Padding length is too large : "
|
||||
<< static_cast<int>(num_padding_bytes);
|
||||
return false;
|
||||
}
|
||||
plaintext->resize(plaintext->size() - num_padding_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
AesCbcCtsDecryptor::AesCbcCtsDecryptor() {}
|
||||
AesCbcCtsDecryptor::~AesCbcCtsDecryptor() {}
|
||||
|
||||
bool AesCbcCtsDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
if (!IsKeySizeValidForAes(key.size())) {
|
||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||
return false;
|
||||
}
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
aes_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcCtsDecryptor::Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) {
|
||||
DCHECK(ciphertext);
|
||||
DCHECK(plaintext);
|
||||
|
||||
if (ciphertext_size < AES_BLOCK_SIZE) {
|
||||
// Don't have a full block, leave unencrypted.
|
||||
memcpy(plaintext, ciphertext, ciphertext_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> iv(iv_);
|
||||
size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
|
||||
|
||||
if (residual_block_size == 0) {
|
||||
// No residual block. No need to do ciphertext stealing.
|
||||
AES_cbc_encrypt(ciphertext,
|
||||
plaintext,
|
||||
ciphertext_size,
|
||||
aes_key_.get(),
|
||||
&iv[0],
|
||||
AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
// AES-CBC decrypt everything up to the next-to-last full block.
|
||||
size_t cbc_size = ciphertext_size - residual_block_size;
|
||||
if (cbc_size > AES_BLOCK_SIZE) {
|
||||
AES_cbc_encrypt(ciphertext,
|
||||
plaintext,
|
||||
cbc_size - AES_BLOCK_SIZE,
|
||||
aes_key_.get(),
|
||||
&iv[0],
|
||||
AES_DECRYPT);
|
||||
}
|
||||
|
||||
// Determine what the last IV should be so that we can "skip ahead" in the
|
||||
// CBC decryption.
|
||||
std::vector<uint8_t> last_iv(
|
||||
ciphertext + ciphertext_size - residual_block_size,
|
||||
ciphertext + ciphertext_size);
|
||||
last_iv.resize(AES_BLOCK_SIZE, 0);
|
||||
|
||||
// Decrypt the next-to-last block using the IV determined above. This decrypts
|
||||
// the residual block bits.
|
||||
AES_cbc_encrypt(
|
||||
ciphertext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
|
||||
plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE, aes_key_.get(), &last_iv[0], AES_DECRYPT);
|
||||
|
||||
// Swap back the residual block bits and the next-to-last full block.
|
||||
if (plaintext == ciphertext) {
|
||||
uint8_t* ptr1 = plaintext + ciphertext_size - residual_block_size;
|
||||
uint8_t* ptr2 = plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
|
||||
for (size_t i = 0; i < residual_block_size; ++i) {
|
||||
uint8_t temp = *ptr1;
|
||||
*ptr1 = *ptr2;
|
||||
*ptr2 = temp;
|
||||
++ptr1;
|
||||
++ptr2;
|
||||
}
|
||||
} else {
|
||||
uint8_t* residual_plaintext_block =
|
||||
plaintext + ciphertext_size - residual_block_size;
|
||||
memcpy(residual_plaintext_block, residual_plaintext_block - AES_BLOCK_SIZE,
|
||||
residual_block_size);
|
||||
memcpy(residual_plaintext_block - AES_BLOCK_SIZE,
|
||||
ciphertext + ciphertext_size - residual_block_size,
|
||||
residual_block_size);
|
||||
}
|
||||
|
||||
// Decrypt the last full block.
|
||||
AES_cbc_encrypt(
|
||||
plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
|
||||
plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE, aes_key_.get(), &iv[0], AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcCtsDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
DCHECK(plaintext);
|
||||
|
||||
plaintext->resize(ciphertext.size(), 0);
|
||||
if (ciphertext.empty())
|
||||
return true;
|
||||
|
||||
return Decrypt(ciphertext.data(), ciphertext.size(), &(*plaintext)[0]);
|
||||
}
|
||||
|
||||
bool AesCbcCtsDecryptor::Decrypt(const std::string& ciphertext,
|
||||
std::string* plaintext) {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AesCbcCtsDecryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -0,0 +1,153 @@
|
|||
// 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
|
||||
//
|
||||
// AES Decryptor implementation using openssl.
|
||||
|
||||
#ifndef MEDIA_BASE_AES_DECRYPTOR_H_
|
||||
#define MEDIA_BASE_AES_DECRYPTOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/memory/scoped_ptr.h"
|
||||
#include "packager/base/stl_util.h"
|
||||
#include "packager/media/base/aes_encryptor.h"
|
||||
|
||||
struct aes_key_st;
|
||||
typedef struct aes_key_st AES_KEY;
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class AesDecryptor {
|
||||
public:
|
||||
AesDecryptor();
|
||||
virtual ~AesDecryptor();
|
||||
|
||||
virtual bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) = 0;
|
||||
|
||||
/// @name Various forms of decrypt calls.
|
||||
/// The plaintext and ciphertext pointers can be the same address.
|
||||
/// @{
|
||||
virtual bool Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) = 0;
|
||||
|
||||
virtual bool Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) = 0;
|
||||
|
||||
virtual bool Decrypt(const std::string& ciphertext,
|
||||
std::string* plaintext) = 0;
|
||||
/// @}
|
||||
|
||||
/// Set IV. @a block_offset_ is reset to 0 on success.
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
|
||||
protected:
|
||||
// Initialization vector, with size 8 or 16.
|
||||
std::vector<uint8_t> iv_;
|
||||
// Openssl AES_KEY.
|
||||
scoped_ptr<AES_KEY> aes_key_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AesDecryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CTR counter-mode decryption.
|
||||
class AesCtrDecryptor : public AesDecryptor {
|
||||
public:
|
||||
AesCtrDecryptor();
|
||||
~AesCtrDecryptor() override;
|
||||
|
||||
/// @name AesDecryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
bool Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::string& ciphertext, std::string* plaintext) override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
uint32_t block_offset() const { return encryptor_->block_offset(); }
|
||||
|
||||
private:
|
||||
scoped_ptr<AesCtrEncryptor> encryptor_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCtrDecryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||
// PKCS#5 padding.
|
||||
class AesCbcPkcs5Decryptor : public AesDecryptor {
|
||||
public:
|
||||
AesCbcPkcs5Decryptor();
|
||||
~AesCbcPkcs5Decryptor() override;
|
||||
|
||||
/// @name AesDecryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
bool Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::string& ciphertext, std::string* plaintext) override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcPkcs5Decryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||
// Ciphertext stealing.
|
||||
class AesCbcCtsDecryptor : public AesDecryptor {
|
||||
public:
|
||||
AesCbcCtsDecryptor();
|
||||
~AesCbcCtsDecryptor() override;
|
||||
|
||||
/// @name AesDecryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
bool Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) override;
|
||||
|
||||
bool Decrypt(const std::string& ciphertext, std::string* plaintext) override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcCtsDecryptor);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
||||
#endif // MEDIA_BASE_AES_DECRYPTOR_H_
|
|
@ -40,17 +40,11 @@ const uint32_t kCencKeySize = 16;
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesCtrEncryptor::AesCtrEncryptor()
|
||||
: block_offset_(0),
|
||||
encrypted_counter_(AES_BLOCK_SIZE, 0),
|
||||
counter_overflow_(false) {
|
||||
COMPILE_ASSERT(AES_BLOCK_SIZE == kCencKeySize,
|
||||
cenc_key_size_should_be_the_same_as_aes_block_size);
|
||||
}
|
||||
AesEncryptor::AesEncryptor() {}
|
||||
AesEncryptor::~AesEncryptor() {}
|
||||
|
||||
AesCtrEncryptor::~AesCtrEncryptor() {}
|
||||
|
||||
bool AesCtrEncryptor::InitializeWithRandomIv(const std::vector<uint8_t>& key,
|
||||
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[0], iv_size) != 1) {
|
||||
|
@ -61,6 +55,32 @@ bool AesCtrEncryptor::InitializeWithRandomIv(const std::vector<uint8_t>& key,
|
|||
return InitializeWithIv(key, iv);
|
||||
}
|
||||
|
||||
bool AesEncryptor::Encrypt(const std::vector<uint8_t>& plaintext,
|
||||
std::vector<uint8_t>* ciphertext) {
|
||||
if (plaintext.empty())
|
||||
return true;
|
||||
ciphertext->resize(plaintext.size() + NumPaddingBytes(plaintext.size()));
|
||||
return EncryptData(plaintext.data(), plaintext.size(), ciphertext->data());
|
||||
}
|
||||
|
||||
bool AesEncryptor::Encrypt(const std::string& plaintext,
|
||||
std::string* ciphertext) {
|
||||
ciphertext->resize(plaintext.size() + NumPaddingBytes(plaintext.size()));
|
||||
return EncryptData(reinterpret_cast<const uint8_t*>(plaintext.data()),
|
||||
plaintext.size(),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(ciphertext)));
|
||||
}
|
||||
|
||||
AesCtrEncryptor::AesCtrEncryptor()
|
||||
: block_offset_(0),
|
||||
encrypted_counter_(AES_BLOCK_SIZE, 0),
|
||||
counter_overflow_(false) {
|
||||
COMPILE_ASSERT(AES_BLOCK_SIZE == kCencKeySize,
|
||||
cenc_key_size_should_be_the_same_as_aes_block_size);
|
||||
}
|
||||
|
||||
AesCtrEncryptor::~AesCtrEncryptor() {}
|
||||
|
||||
bool AesCtrEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
if (key.size() != kCencKeySize) {
|
||||
|
@ -77,7 +97,11 @@ bool AesCtrEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|||
return SetIv(iv);
|
||||
}
|
||||
|
||||
bool AesCtrEncryptor::Encrypt(const uint8_t* plaintext,
|
||||
size_t AesCtrEncryptor::NumPaddingBytes(size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AesCtrEncryptor::EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext) {
|
||||
DCHECK(plaintext);
|
||||
|
@ -156,34 +180,40 @@ bool AesCbcPkcs5Encryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|||
return false;
|
||||
}
|
||||
|
||||
encrypt_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, encrypt_key_.get()), 0);
|
||||
aes_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcPkcs5Encryptor::Encrypt(const std::string& plaintext,
|
||||
std::string* ciphertext) {
|
||||
size_t AesCbcPkcs5Encryptor::NumPaddingBytes(size_t size) {
|
||||
return AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Encryptor::EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext) {
|
||||
DCHECK(ciphertext);
|
||||
DCHECK(encrypt_key_);
|
||||
DCHECK(aes_key_);
|
||||
|
||||
// Pad the input with PKCS5 padding.
|
||||
const size_t num_padding_bytes =
|
||||
AES_BLOCK_SIZE - (plaintext.size() % AES_BLOCK_SIZE);
|
||||
std::string padded_text = plaintext;
|
||||
padded_text.append(num_padding_bytes, static_cast<char>(num_padding_bytes));
|
||||
// TODO(kqyang): Consider more efficient implementation.
|
||||
memcpy(ciphertext, plaintext, plaintext_size);
|
||||
for (size_t i = plaintext_size;
|
||||
i < plaintext_size + NumPaddingBytes(plaintext_size); ++i) {
|
||||
ciphertext[i] = NumPaddingBytes(plaintext_size);
|
||||
}
|
||||
|
||||
ciphertext->resize(padded_text.size());
|
||||
std::vector<uint8_t> iv(iv_);
|
||||
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(padded_text.data()),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(ciphertext)),
|
||||
padded_text.size(),
|
||||
encrypt_key_.get(),
|
||||
&iv[0],
|
||||
AES_ENCRYPT);
|
||||
AES_cbc_encrypt(ciphertext, ciphertext,
|
||||
plaintext_size + NumPaddingBytes(plaintext_size),
|
||||
aes_key_.get(), &iv[0], AES_ENCRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcPkcs5Encryptor::UpdateIv() {}
|
||||
|
||||
bool AesCbcPkcs5Encryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
|
@ -194,67 +224,6 @@ bool AesCbcPkcs5Encryptor::SetIv(const std::vector<uint8_t>& iv) {
|
|||
return true;
|
||||
}
|
||||
|
||||
AesCbcPkcs5Decryptor::AesCbcPkcs5Decryptor() {}
|
||||
AesCbcPkcs5Decryptor::~AesCbcPkcs5Decryptor() {}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
if (!IsKeySizeValidForAes(key.size())) {
|
||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||
return false;
|
||||
}
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
decrypt_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, decrypt_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::Decrypt(const std::string& ciphertext,
|
||||
std::string* plaintext) {
|
||||
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
|
||||
LOG(ERROR) << "Expecting cipher text size to be multiple of "
|
||||
<< AES_BLOCK_SIZE << ", got " << ciphertext.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(plaintext);
|
||||
DCHECK(decrypt_key_);
|
||||
|
||||
plaintext->resize(ciphertext.size());
|
||||
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
|
||||
ciphertext.size(),
|
||||
decrypt_key_.get(),
|
||||
&iv_[0],
|
||||
AES_DECRYPT);
|
||||
|
||||
// Strip off PKCS5 padding bytes.
|
||||
const uint8_t num_padding_bytes = (*plaintext)[plaintext->size() - 1];
|
||||
if (num_padding_bytes > AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Padding length is too large : "
|
||||
<< static_cast<int>(num_padding_bytes);
|
||||
return false;
|
||||
}
|
||||
plaintext->resize(plaintext->size() - num_padding_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcPkcs5Decryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
AesCbcCtsEncryptor::AesCbcCtsEncryptor() {}
|
||||
AesCbcCtsEncryptor::~AesCbcCtsEncryptor() {}
|
||||
|
||||
|
@ -269,14 +238,18 @@ bool AesCbcCtsEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|||
return false;
|
||||
}
|
||||
|
||||
encrypt_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, encrypt_key_.get()), 0);
|
||||
aes_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
|
||||
size_t AesCbcCtsEncryptor::NumPaddingBytes(size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AesCbcCtsEncryptor::EncryptData(const uint8_t* plaintext,
|
||||
size_t size,
|
||||
uint8_t* ciphertext) {
|
||||
DCHECK(plaintext);
|
||||
|
@ -285,7 +258,7 @@ void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
|
|||
if (size < AES_BLOCK_SIZE) {
|
||||
// Don't have a full block, leave unencrypted.
|
||||
memcpy(ciphertext, plaintext, size);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> iv(iv_);
|
||||
|
@ -296,12 +269,12 @@ void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
|
|||
AES_cbc_encrypt(plaintext,
|
||||
ciphertext,
|
||||
cbc_size,
|
||||
encrypt_key_.get(),
|
||||
aes_key_.get(),
|
||||
&iv[0],
|
||||
AES_ENCRYPT);
|
||||
if (residual_block_size == 0) {
|
||||
// No residual block. No need to do ciphertext stealing.
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Zero-pad the residual block and encrypt using CBC.
|
||||
|
@ -311,7 +284,7 @@ void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
|
|||
AES_cbc_encrypt(&residual_block[0],
|
||||
&residual_block[0],
|
||||
AES_BLOCK_SIZE,
|
||||
encrypt_key_.get(),
|
||||
aes_key_.get(),
|
||||
&iv[0],
|
||||
AES_ENCRYPT);
|
||||
|
||||
|
@ -327,18 +300,10 @@ void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
|
|||
memcpy(residual_ciphertext_block - AES_BLOCK_SIZE,
|
||||
residual_block.data(),
|
||||
AES_BLOCK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcCtsEncryptor::Encrypt(const std::vector<uint8_t>& plaintext,
|
||||
std::vector<uint8_t>* ciphertext) {
|
||||
DCHECK(ciphertext);
|
||||
|
||||
ciphertext->resize(plaintext.size(), 0);
|
||||
if (plaintext.empty())
|
||||
return;
|
||||
|
||||
Encrypt(plaintext.data(), plaintext.size(), &(*ciphertext)[0]);
|
||||
}
|
||||
void AesCbcCtsEncryptor::UpdateIv() {}
|
||||
|
||||
bool AesCbcCtsEncryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
|
@ -350,129 +315,5 @@ bool AesCbcCtsEncryptor::SetIv(const std::vector<uint8_t>& iv) {
|
|||
return true;
|
||||
}
|
||||
|
||||
AesCbcCtsDecryptor::AesCbcCtsDecryptor() {}
|
||||
AesCbcCtsDecryptor::~AesCbcCtsDecryptor() {}
|
||||
|
||||
bool AesCbcCtsDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
if (!IsKeySizeValidForAes(key.size())) {
|
||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||
return false;
|
||||
}
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
decrypt_key_.reset(new AES_KEY());
|
||||
CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, decrypt_key_.get()), 0);
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcCtsDecryptor::Decrypt(const uint8_t* ciphertext,
|
||||
size_t size,
|
||||
uint8_t* plaintext) {
|
||||
DCHECK(ciphertext);
|
||||
DCHECK(plaintext);
|
||||
|
||||
if (size < AES_BLOCK_SIZE) {
|
||||
// Don't have a full block, leave unencrypted.
|
||||
memcpy(plaintext, ciphertext, size);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> iv(iv_);
|
||||
size_t residual_block_size = size % AES_BLOCK_SIZE;
|
||||
|
||||
if (residual_block_size == 0) {
|
||||
// No residual block. No need to do ciphertext stealing.
|
||||
AES_cbc_encrypt(ciphertext,
|
||||
plaintext,
|
||||
size,
|
||||
decrypt_key_.get(),
|
||||
&iv[0],
|
||||
AES_DECRYPT);
|
||||
return;
|
||||
}
|
||||
|
||||
// AES-CBC decrypt everything up to the next-to-last full block.
|
||||
size_t cbc_size = size - residual_block_size;
|
||||
if (cbc_size > AES_BLOCK_SIZE) {
|
||||
AES_cbc_encrypt(ciphertext,
|
||||
plaintext,
|
||||
cbc_size - AES_BLOCK_SIZE,
|
||||
decrypt_key_.get(),
|
||||
&iv[0],
|
||||
AES_DECRYPT);
|
||||
}
|
||||
|
||||
// Determine what the last IV should be so that we can "skip ahead" in the
|
||||
// CBC decryption.
|
||||
std::vector<uint8_t> last_iv(ciphertext + size - residual_block_size,
|
||||
ciphertext + size);
|
||||
last_iv.resize(AES_BLOCK_SIZE, 0);
|
||||
|
||||
// Decrypt the next-to-last block using the IV determined above. This decrypts
|
||||
// the residual block bits.
|
||||
AES_cbc_encrypt(ciphertext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||
plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE,
|
||||
decrypt_key_.get(),
|
||||
&last_iv[0],
|
||||
AES_DECRYPT);
|
||||
|
||||
// Swap back the residual block bits and the next-to-last full block.
|
||||
if (plaintext == ciphertext) {
|
||||
uint8_t* ptr1 = plaintext + size - residual_block_size;
|
||||
uint8_t* ptr2 = plaintext + size - residual_block_size - AES_BLOCK_SIZE;
|
||||
for (size_t i = 0; i < residual_block_size; ++i) {
|
||||
uint8_t temp = *ptr1;
|
||||
*ptr1 = *ptr2;
|
||||
*ptr2 = temp;
|
||||
++ptr1;
|
||||
++ptr2;
|
||||
}
|
||||
} else {
|
||||
uint8_t* residual_plaintext_block = plaintext + size - residual_block_size;
|
||||
memcpy(residual_plaintext_block,
|
||||
residual_plaintext_block - AES_BLOCK_SIZE,
|
||||
residual_block_size);
|
||||
memcpy(residual_plaintext_block - AES_BLOCK_SIZE,
|
||||
ciphertext + size - residual_block_size,
|
||||
residual_block_size);
|
||||
}
|
||||
|
||||
// Decrypt the last full block.
|
||||
AES_cbc_encrypt(plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||
plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||
AES_BLOCK_SIZE,
|
||||
decrypt_key_.get(),
|
||||
&iv[0],
|
||||
AES_DECRYPT);
|
||||
}
|
||||
|
||||
void AesCbcCtsDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
DCHECK(plaintext);
|
||||
|
||||
plaintext->resize(ciphertext.size(), 0);
|
||||
if (ciphertext.empty())
|
||||
return;
|
||||
|
||||
Decrypt(ciphertext.data(), ciphertext.size(), &(*plaintext)[0]);
|
||||
}
|
||||
|
||||
bool AesCbcCtsDecryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
iv_ = iv;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -21,86 +21,93 @@ typedef struct aes_key_st AES_KEY;
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
// Class which implements AES-CTR counter-mode encryption/decryption.
|
||||
class AesCtrEncryptor {
|
||||
class AesEncryptor {
|
||||
public:
|
||||
AesCtrEncryptor();
|
||||
~AesCtrEncryptor();
|
||||
AesEncryptor();
|
||||
virtual ~AesEncryptor();
|
||||
|
||||
/// Initialize the encryptor with specified key and a random generated IV
|
||||
/// of the specified size. block_offset() is reset to 0 on success.
|
||||
/// of the specified size.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
virtual 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.
|
||||
virtual bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) = 0;
|
||||
|
||||
virtual size_t NumPaddingBytes(size_t size) = 0;
|
||||
|
||||
/// @name Various forms of encrypt and decrypt calls.
|
||||
/// The plaintext and ciphertext pointers can be the same address.
|
||||
/// @{
|
||||
virtual bool EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext) = 0;
|
||||
|
||||
bool Encrypt(const std::vector<uint8_t>& plaintext,
|
||||
std::vector<uint8_t>* ciphertext);
|
||||
|
||||
bool Encrypt(const std::string& plaintext, std::string* ciphertext);
|
||||
/// @}
|
||||
|
||||
/// Update IV for next sample.
|
||||
/// As recommended in ISO/IEC FDIS 23001-7:
|
||||
/// IV need to be updated per sample for CENC.
|
||||
/// IV need not be unique per sample for CBC mode.
|
||||
virtual void UpdateIv() = 0;
|
||||
|
||||
/// Set IV.
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
|
||||
protected:
|
||||
// Initialization vector, with size 8 or 16.
|
||||
std::vector<uint8_t> iv_;
|
||||
// Openssl AES_KEY.
|
||||
scoped_ptr<AES_KEY> aes_key_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AesEncryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CTR counter-mode encryption/decryption.
|
||||
class AesCtrEncryptor : public AesEncryptor {
|
||||
public:
|
||||
AesCtrEncryptor();
|
||||
~AesCtrEncryptor() override;
|
||||
|
||||
/// @name AesEncryptor implementation overrides.
|
||||
/// @{
|
||||
/// @param key should be 16 bytes in size as specified in CENC spec.
|
||||
/// @param iv_size should be either 8 or 16 as specified in CENC spec.
|
||||
/// @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. block_offset() is
|
||||
/// reset to 0 on success.
|
||||
/// @param key should be 16 bytes in size as specified in CENC spec.
|
||||
/// @param iv should be 8 bytes or 16 bytes in size as specified in CENC spec.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv);
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
/// @name Various forms of encrypt calls.
|
||||
/// block_offset() will be updated according to input plaintext size.
|
||||
/// The plaintext and ciphertext pointers can be the same address.
|
||||
/// @{
|
||||
bool Encrypt(const uint8_t* plaintext,
|
||||
size_t NumPaddingBytes(size_t size) override;
|
||||
|
||||
bool EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext);
|
||||
|
||||
bool Encrypt(const std::vector<uint8_t>& plaintext,
|
||||
std::vector<uint8_t>* ciphertext) {
|
||||
ciphertext->resize(plaintext.size());
|
||||
return Encrypt(&plaintext[0], plaintext.size(), &(*ciphertext)[0]);
|
||||
}
|
||||
|
||||
bool Encrypt(const std::string& plaintext, std::string* ciphertext) {
|
||||
ciphertext->resize(plaintext.size());
|
||||
return Encrypt(reinterpret_cast<const uint8_t*>(plaintext.data()),
|
||||
plaintext.size(),
|
||||
reinterpret_cast<uint8_t*>(string_as_array(ciphertext)));
|
||||
}
|
||||
/// @}
|
||||
|
||||
// For AES CTR, encryption and decryption are identical.
|
||||
bool Decrypt(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext) {
|
||||
return Encrypt(ciphertext, ciphertext_size, plaintext);
|
||||
}
|
||||
|
||||
bool Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
return Encrypt(ciphertext, plaintext);
|
||||
}
|
||||
|
||||
bool Decrypt(const std::string& ciphertext, std::string* plaintext) {
|
||||
return Encrypt(ciphertext, plaintext);
|
||||
}
|
||||
uint8_t* ciphertext) override;
|
||||
|
||||
/// Update IV for next sample. @a block_offset_ is reset to 0.
|
||||
/// As recommended in ISO/IEC FDIS 23001-7: CENC spec,
|
||||
/// For 64-bit IV size, new_iv = old_iv + 1;
|
||||
/// For 128-bit IV size, new_iv = old_iv + previous_sample_block_count.
|
||||
void UpdateIv();
|
||||
void UpdateIv() override;
|
||||
|
||||
/// Set IV. @a block_offset_ is reset to 0 on success.
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
uint32_t block_offset() const { return block_offset_; }
|
||||
|
||||
private:
|
||||
// Initialization vector, with size 8 or 16.
|
||||
std::vector<uint8_t> iv_;
|
||||
// Current block offset.
|
||||
uint32_t block_offset_;
|
||||
// Openssl AES_KEY.
|
||||
scoped_ptr<AES_KEY> aes_key_;
|
||||
// Current AES-CTR counter.
|
||||
std::vector<uint8_t> counter_;
|
||||
// Encrypted counter.
|
||||
|
@ -113,148 +120,58 @@ class AesCtrEncryptor {
|
|||
|
||||
// Class which implements AES-CBC (Cipher block chaining) encryption with
|
||||
// PKCS#5 padding.
|
||||
class AesCbcPkcs5Encryptor {
|
||||
class AesCbcPkcs5Encryptor : public AesEncryptor {
|
||||
public:
|
||||
AesCbcPkcs5Encryptor();
|
||||
~AesCbcPkcs5Encryptor();
|
||||
~AesCbcPkcs5Encryptor() override;
|
||||
|
||||
/// Initialize the encryptor with specified key and IV.
|
||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||
/// in AES spec.
|
||||
/// @param iv should be 16 bytes in size.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
/// @name AesEncryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv);
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
/// @param plaintext will be PKCS5 padded before being encrypted.
|
||||
/// @param ciphertext should not be NULL.
|
||||
void Encrypt(const std::string& plaintext, std::string* ciphertext);
|
||||
size_t NumPaddingBytes(size_t size) override;
|
||||
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
bool EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext) override;
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
void UpdateIv() override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> iv_;
|
||||
scoped_ptr<AES_KEY> encrypt_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcPkcs5Encryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||
// PKCS#5 padding.
|
||||
class AesCbcPkcs5Decryptor {
|
||||
public:
|
||||
AesCbcPkcs5Decryptor();
|
||||
~AesCbcPkcs5Decryptor();
|
||||
|
||||
/// Initialize the decryptor with specified key and IV.
|
||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||
/// in AES spec.
|
||||
/// @param iv should be 16 bytes in size.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv);
|
||||
|
||||
/// @param ciphertext is expected to be padded with PKCS5 padding.
|
||||
/// @param plaintext should not be NULL.
|
||||
/// @return true on success, false otherwise.
|
||||
bool Decrypt(const std::string& ciphertext, std::string* plaintext);
|
||||
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> iv_;
|
||||
scoped_ptr<AES_KEY> decrypt_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcPkcs5Decryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) encryption with
|
||||
// Ciphertext stealing.
|
||||
class AesCbcCtsEncryptor {
|
||||
class AesCbcCtsEncryptor : public AesEncryptor {
|
||||
public:
|
||||
AesCbcCtsEncryptor();
|
||||
~AesCbcCtsEncryptor();
|
||||
~AesCbcCtsEncryptor() override;
|
||||
|
||||
/// Initialize the encryptor with specified key and IV.
|
||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||
/// in AES spec.
|
||||
/// @param iv should be 16 bytes in size.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
/// @name AesEncryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv);
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
|
||||
/// @param plaintext points to the data to be encrypted.
|
||||
/// @param size is the number of bytes to be encrypted. If less than 16
|
||||
/// bytes, it will be copied in the clear.
|
||||
/// @param ciphertext should not be NULL. The buffer should be at least
|
||||
/// @a size bytes in length.
|
||||
void Encrypt(const uint8_t* plaintext, size_t size, uint8_t* ciphertext);
|
||||
size_t NumPaddingBytes(size_t size) override;
|
||||
|
||||
/// @param plaintext contains the data to be encrypted. If less than 16
|
||||
/// bytes in size, it will be copied in the clear.
|
||||
/// @param ciphertext should not be NULL. Caller retains ownership.
|
||||
void Encrypt(const std::vector<uint8_t>& plaintext,
|
||||
std::vector<uint8_t>* ciphertext);
|
||||
bool EncryptData(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext) override;
|
||||
|
||||
/// @param iv is the initialization vector. Should be 16 bytes in size.
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
void UpdateIv() override;
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> iv_;
|
||||
scoped_ptr<AES_KEY> encrypt_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcCtsEncryptor);
|
||||
};
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||
// Ciphertext stealing.
|
||||
class AesCbcCtsDecryptor {
|
||||
public:
|
||||
AesCbcCtsDecryptor();
|
||||
~AesCbcCtsDecryptor();
|
||||
|
||||
/// Initialize the decryptor with specified key and IV.
|
||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||
/// in AES spec.
|
||||
/// @param iv should be 16 bytes in size.
|
||||
/// @return true on successful initialization, false otherwise.
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv);
|
||||
|
||||
/// @param ciphertext points to the data to be decrypted.
|
||||
/// @param size is the number of bytes to be decrypted. If less than 16
|
||||
/// bytes, it will be copied in the clear.
|
||||
/// @param plaintext should not be NULL. The buffer should be at least
|
||||
/// @a size bytes in length.
|
||||
void Decrypt(const uint8_t* ciphertext, size_t size, uint8_t* plaintext);
|
||||
|
||||
/// @param ciphertext contains the data to be decrypted. If less than 16
|
||||
/// bytes in size, it will be copied in the clear.
|
||||
/// @param plaintext should not be NULL. Caller retains ownership.
|
||||
void Decrypt(const std::vector<uint8_t>& ciphertext,
|
||||
std::vector<uint8_t>* plaintext);
|
||||
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> iv_;
|
||||
scoped_ptr<AES_KEY> decrypt_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcCtsDecryptor);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "packager/base/memory/scoped_ptr.h"
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/media/base/aes_encryptor.h"
|
||||
#include "packager/media/base/aes_decryptor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -144,6 +145,7 @@ class AesCtrEncryptorTest : public testing::Test {
|
|||
kAesCtrCiphertext + arraysize(kAesCtrCiphertext));
|
||||
|
||||
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_));
|
||||
ASSERT_TRUE(decryptor_.InitializeWithIv(key_, iv_));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -152,6 +154,7 @@ class AesCtrEncryptorTest : public testing::Test {
|
|||
std::vector<uint8_t> plaintext_;
|
||||
std::vector<uint8_t> ciphertext_;
|
||||
AesCtrEncryptor encryptor_;
|
||||
AesCtrDecryptor decryptor_;
|
||||
};
|
||||
|
||||
TEST_F(AesCtrEncryptorTest, NistTestCase) {
|
||||
|
@ -159,19 +162,19 @@ TEST_F(AesCtrEncryptorTest, NistTestCase) {
|
|||
EXPECT_TRUE(encryptor_.Encrypt(plaintext_, &encrypted));
|
||||
EXPECT_EQ(ciphertext_, encrypted);
|
||||
|
||||
EXPECT_TRUE(encryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(decryptor_.SetIv(iv_));
|
||||
std::vector<uint8_t> decrypted;
|
||||
EXPECT_TRUE(encryptor_.Decrypt(encrypted, &decrypted));
|
||||
EXPECT_TRUE(decryptor_.Decrypt(encrypted, &decrypted));
|
||||
EXPECT_EQ(plaintext_, decrypted);
|
||||
}
|
||||
|
||||
TEST_F(AesCtrEncryptorTest, NistTestCaseInplaceEncryptionDecryption) {
|
||||
std::vector<uint8_t> buffer = plaintext_;
|
||||
EXPECT_TRUE(encryptor_.Encrypt(&buffer[0], buffer.size(), &buffer[0]));
|
||||
EXPECT_TRUE(encryptor_.EncryptData(&buffer[0], buffer.size(), &buffer[0]));
|
||||
EXPECT_EQ(ciphertext_, buffer);
|
||||
|
||||
EXPECT_TRUE(encryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(encryptor_.Decrypt(&buffer[0], buffer.size(), &buffer[0]));
|
||||
EXPECT_TRUE(decryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(decryptor_.Decrypt(&buffer[0], buffer.size(), &buffer[0]));
|
||||
EXPECT_EQ(plaintext_, buffer);
|
||||
}
|
||||
|
||||
|
@ -186,8 +189,8 @@ TEST_F(AesCtrEncryptorTest, EncryptDecryptString) {
|
|||
base::HexEncode(ciphertext.data(), ciphertext.size()));
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(encryptor_.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_TRUE(decryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(decryptor_.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(kPlaintext, decrypted);
|
||||
}
|
||||
|
||||
|
@ -208,11 +211,11 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
|
|||
|
||||
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_max64));
|
||||
std::vector<uint8_t> encrypted_verify(plaintext_.size(), 0);
|
||||
EXPECT_TRUE(
|
||||
encryptor_.Encrypt(&plaintext_[0], kAesBlockSize, &encrypted_verify[0]));
|
||||
EXPECT_TRUE(encryptor_.EncryptData(&plaintext_[0], kAesBlockSize,
|
||||
&encrypted_verify[0]));
|
||||
std::vector<uint8_t> iv_zero(kIv128Zero, kIv128Zero + arraysize(kIv128Zero));
|
||||
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_zero));
|
||||
EXPECT_TRUE(encryptor_.Encrypt(&plaintext_[kAesBlockSize],
|
||||
EXPECT_TRUE(encryptor_.EncryptData(&plaintext_[kAesBlockSize],
|
||||
kAesBlockSize * 3,
|
||||
&encrypted_verify[kAesBlockSize]));
|
||||
EXPECT_EQ(encrypted, encrypted_verify);
|
||||
|
@ -251,20 +254,20 @@ TEST_P(AesCtrEncryptorSubsampleTest, NistTestCaseSubsamples) {
|
|||
for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) {
|
||||
uint32_t len = test_case->subsample_sizes[i];
|
||||
EXPECT_TRUE(
|
||||
encryptor_.Encrypt(&plaintext_[offset], len, &encrypted[offset]));
|
||||
encryptor_.EncryptData(&plaintext_[offset], len, &encrypted[offset]));
|
||||
offset += len;
|
||||
EXPECT_EQ(offset % kAesBlockSize, encryptor_.block_offset());
|
||||
}
|
||||
EXPECT_EQ(ciphertext_, encrypted);
|
||||
|
||||
EXPECT_TRUE(encryptor_.SetIv(iv_));
|
||||
EXPECT_TRUE(decryptor_.SetIv(iv_));
|
||||
std::vector<uint8_t> decrypted(encrypted.size(), 0);
|
||||
for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) {
|
||||
uint32_t len = test_case->subsample_sizes[i];
|
||||
EXPECT_TRUE(
|
||||
encryptor_.Decrypt(&encrypted[offset], len, &decrypted[offset]));
|
||||
decryptor_.Decrypt(&encrypted[offset], len, &decrypted[offset]));
|
||||
offset += len;
|
||||
EXPECT_EQ(offset % kAesBlockSize, encryptor_.block_offset());
|
||||
EXPECT_EQ(offset % kAesBlockSize, decryptor_.block_offset());
|
||||
}
|
||||
EXPECT_EQ(plaintext_, decrypted);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,12 @@ namespace media {
|
|||
|
||||
DecryptConfig::DecryptConfig(const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& iv,
|
||||
const std::vector<SubsampleEntry>& subsamples)
|
||||
: key_id_(key_id), iv_(iv), subsamples_(subsamples) {
|
||||
const std::vector<SubsampleEntry>& subsamples,
|
||||
EncryptionMode decryption_mode)
|
||||
: key_id_(key_id),
|
||||
iv_(iv),
|
||||
subsamples_(subsamples),
|
||||
decryption_mode_(decryption_mode) {
|
||||
CHECK_GT(key_id.size(), 0u);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "packager/base/memory/scoped_ptr.h"
|
||||
#include "packager/media/base/encryption_modes.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
@ -46,14 +47,18 @@ class DecryptConfig {
|
|||
/// @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);
|
||||
const std::vector<SubsampleEntry>& subsamples,
|
||||
EncryptionMode decryption_mode);
|
||||
~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_; }
|
||||
|
||||
private:
|
||||
const std::vector<uint8_t> key_id_;
|
||||
|
@ -65,6 +70,8 @@ class DecryptConfig {
|
|||
// (less data ignored by data_offset_) is encrypted.
|
||||
const std::vector<SubsampleEntry> subsamples_;
|
||||
|
||||
EncryptionMode decryption_mode_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DecryptConfig);
|
||||
};
|
||||
|
||||
|
|
|
@ -27,22 +27,36 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
|
|||
DCHECK(buffer);
|
||||
|
||||
// Get the decryptor object.
|
||||
AesCtrEncryptor* decryptor;
|
||||
AesDecryptor* decryptor;
|
||||
auto found = decryptor_map_.find(decrypt_config->key_id());
|
||||
if (found == decryptor_map_.end()) {
|
||||
// Create new AesCtrEncryptor
|
||||
// Create new AesDecryptor based on decryption mode.
|
||||
EncryptionKey key;
|
||||
Status status(key_source_->GetKey(decrypt_config->key_id(), &key));
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Error retrieving decryption key: " << status;
|
||||
return false;
|
||||
}
|
||||
scoped_ptr<AesCtrEncryptor> aes_ctr_encryptor(new AesCtrEncryptor);
|
||||
if (!aes_ctr_encryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
|
||||
LOG(ERROR) << "Failed to initialize AesCtrEncryptor for decryption.";
|
||||
|
||||
scoped_ptr<AesDecryptor> aes_decryptor;
|
||||
switch (decrypt_config->decryption_mode()) {
|
||||
case kEncryptionModeAesCtr:
|
||||
aes_decryptor.reset(new AesCtrDecryptor);
|
||||
break;
|
||||
case kEncryptionModeAesCbc:
|
||||
aes_decryptor.reset(new AesCbcPkcs5Decryptor);
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unsupported Decryption Mode: "
|
||||
<< decrypt_config->decryption_mode();
|
||||
return false;
|
||||
}
|
||||
decryptor = aes_ctr_encryptor.release();
|
||||
|
||||
if (!aes_decryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
|
||||
LOG(ERROR) << "Failed to initialize AesDecryptor for decryption.";
|
||||
return false;
|
||||
}
|
||||
decryptor = aes_decryptor.release();
|
||||
decryptor_map_[decrypt_config->key_id()] = decryptor;
|
||||
} else {
|
||||
decryptor = found->second;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/base/aes_encryptor.h"
|
||||
#include "packager/media/base/aes_decryptor.h"
|
||||
#include "packager/media/base/decrypt_config.h"
|
||||
#include "packager/media/base/key_source.h"
|
||||
|
||||
|
@ -29,7 +29,7 @@ class DecryptorSource {
|
|||
|
||||
private:
|
||||
KeySource* key_source_;
|
||||
std::map<std::vector<uint8_t>, AesCtrEncryptor*> decryptor_map_;
|
||||
std::map<std::vector<uint8_t>, AesDecryptor*> decryptor_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DecryptorSource);
|
||||
};
|
||||
|
|
|
@ -80,7 +80,8 @@ TEST_F(DecryptorSourceTest, FullSampleDecryption) {
|
|||
|
||||
DecryptConfig decrypt_config(key_id_,
|
||||
std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
|
||||
std::vector<SubsampleEntry>());
|
||||
std::vector<SubsampleEntry>(),
|
||||
kEncryptionModeAesCtr);
|
||||
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(&decrypt_config, &buffer_[0],
|
||||
buffer_.size()));
|
||||
EXPECT_EQ(std::vector<uint8_t>(
|
||||
|
@ -93,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>());
|
||||
std::vector<SubsampleEntry>(), kEncryptionModeAesCtr);
|
||||
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(
|
||||
&decrypt_config2, &buffer_[0], buffer_.size()));
|
||||
EXPECT_EQ(std::vector<uint8_t>(kExpectedDecryptedBuffer2,
|
||||
|
@ -128,7 +129,8 @@ TEST_F(DecryptorSourceTest, SubsampleDecryption) {
|
|||
DecryptConfig decrypt_config(
|
||||
key_id_, std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
|
||||
std::vector<SubsampleEntry>(kSubsamples,
|
||||
kSubsamples + arraysize(kSubsamples)));
|
||||
kSubsamples + arraysize(kSubsamples)),
|
||||
kEncryptionModeAesCtr);
|
||||
ASSERT_TRUE(decryptor_source_.DecryptSampleBuffer(
|
||||
&decrypt_config, &buffer_[0], buffer_.size()));
|
||||
EXPECT_EQ(std::vector<uint8_t>(
|
||||
|
@ -152,7 +154,8 @@ TEST_F(DecryptorSourceTest, SubsampleDecryptionSizeValidation) {
|
|||
DecryptConfig decrypt_config(
|
||||
key_id_, std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
|
||||
std::vector<SubsampleEntry>(kSubsamples,
|
||||
kSubsamples + arraysize(kSubsamples)));
|
||||
kSubsamples + arraysize(kSubsamples)),
|
||||
kEncryptionModeAesCtr);
|
||||
ASSERT_FALSE(decryptor_source_.DecryptSampleBuffer(
|
||||
&decrypt_config, &buffer_[0], buffer_.size()));
|
||||
}
|
||||
|
@ -163,7 +166,8 @@ TEST_F(DecryptorSourceTest, DecryptFailedIfGetKeyFailed) {
|
|||
|
||||
DecryptConfig decrypt_config(key_id_,
|
||||
std::vector<uint8_t>(kIv, kIv + arraysize(kIv)),
|
||||
std::vector<SubsampleEntry>());
|
||||
std::vector<SubsampleEntry>(),
|
||||
kEncryptionModeAesCtr);
|
||||
ASSERT_FALSE(decryptor_source_.DecryptSampleBuffer(
|
||||
&decrypt_config, &buffer_[0], buffer_.size()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// 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_
|
|
@ -13,6 +13,8 @@
|
|||
'target_name': 'media_base',
|
||||
'type': '<(component)',
|
||||
'sources': [
|
||||
'aes_decryptor.cc',
|
||||
'aes_decryptor.h',
|
||||
'aes_encryptor.cc',
|
||||
'aes_encryptor.h',
|
||||
'audio_stream_info.cc',
|
||||
|
@ -37,6 +39,7 @@
|
|||
'decrypt_config.h',
|
||||
'decryptor_source.cc',
|
||||
'decryptor_source.h',
|
||||
'encryption_modes.h',
|
||||
'http_key_fetcher.cc',
|
||||
'http_key_fetcher.h',
|
||||
'key_fetcher.cc',
|
||||
|
|
|
@ -19,6 +19,7 @@ Muxer::Muxer(const MuxerOptions& options)
|
|||
max_sd_pixels_(0),
|
||||
clear_lead_in_seconds_(0),
|
||||
crypto_period_duration_in_seconds_(0),
|
||||
encryption_mode_(kEncryptionModeUnknown),
|
||||
cancelled_(false),
|
||||
clock_(NULL) {}
|
||||
|
||||
|
@ -27,12 +28,14 @@ Muxer::~Muxer() {}
|
|||
void Muxer::SetKeySource(KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds) {
|
||||
double crypto_period_duration_in_seconds,
|
||||
EncryptionMode encryption_mode) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Muxer::AddStream(MediaStream* stream) {
|
||||
|
|
|
@ -14,6 +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/muxer_options.h"
|
||||
#include "packager/media/base/status.h"
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
|
@ -47,7 +48,8 @@ class Muxer {
|
|||
void SetKeySource(KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds);
|
||||
double crypto_period_duration_in_seconds,
|
||||
EncryptionMode encryption_mode);
|
||||
|
||||
/// Add video/audio stream.
|
||||
void AddStream(MediaStream* stream);
|
||||
|
@ -92,6 +94,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_; }
|
||||
|
||||
private:
|
||||
friend class MediaStream; // Needed to access AddSample.
|
||||
|
@ -117,6 +120,7 @@ class Muxer {
|
|||
uint32_t max_sd_pixels_;
|
||||
double clear_lead_in_seconds_;
|
||||
double crypto_period_duration_in_seconds_;
|
||||
EncryptionMode encryption_mode_;
|
||||
bool cancelled_;
|
||||
|
||||
scoped_ptr<MuxerListener> muxer_listener_;
|
||||
|
|
|
@ -450,7 +450,7 @@ bool ProtectionSchemeInfo::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
buffer->PrepareChildren() &&
|
||||
buffer->ReadWriteChild(&format) &&
|
||||
buffer->ReadWriteChild(&type));
|
||||
if (type.type == FOURCC_CENC)
|
||||
if (type.type == FOURCC_CENC || type.type == FOURCC_CBC1)
|
||||
RCHECK(buffer->ReadWriteChild(&info));
|
||||
// Other protection schemes are silently ignored. Since the protection scheme
|
||||
// type can't be determined until this box is opened, we return 'true' for
|
||||
|
@ -1300,7 +1300,7 @@ bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
if (buffer->Reading()) {
|
||||
// Continue scanning until a recognized protection scheme is found,
|
||||
// or until we run out of protection schemes.
|
||||
while (sinf.type.type != FOURCC_CENC) {
|
||||
while (sinf.type.type != FOURCC_CENC && sinf.type.type != FOURCC_CBC1) {
|
||||
if (!buffer->ReadWriteChild(&sinf))
|
||||
return false;
|
||||
}
|
||||
|
@ -1485,7 +1485,7 @@ bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
if (buffer->Reading()) {
|
||||
// Continue scanning until a recognized protection scheme is found,
|
||||
// or until we run out of protection schemes.
|
||||
while (sinf.type.type != FOURCC_CENC) {
|
||||
while (sinf.type.type != FOURCC_CENC && sinf.type.type != FOURCC_CBC1) {
|
||||
if (!buffer->ReadWriteChild(&sinf))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -64,12 +64,14 @@ EncryptingFragmenter::EncryptingFragmenter(
|
|||
scoped_refptr<StreamInfo> info,
|
||||
TrackFragment* traf,
|
||||
scoped_ptr<EncryptionKey> encryption_key,
|
||||
int64_t clear_time)
|
||||
int64_t clear_time,
|
||||
EncryptionMode encryption_mode)
|
||||
: Fragmenter(traf),
|
||||
info_(info),
|
||||
encryption_key_(encryption_key.Pass()),
|
||||
nalu_length_size_(GetNaluLengthSize(*info)),
|
||||
clear_time_(clear_time) {
|
||||
clear_time_(clear_time),
|
||||
encryption_mode_(encryption_mode) {
|
||||
DCHECK(encryption_key_);
|
||||
VideoCodec video_codec = GetVideoCodec(*info);
|
||||
if (video_codec == kCodecVP8) {
|
||||
|
@ -168,8 +170,14 @@ void EncryptingFragmenter::FinalizeFragmentForEncryption() {
|
|||
|
||||
Status EncryptingFragmenter::CreateEncryptor() {
|
||||
DCHECK(encryption_key_);
|
||||
|
||||
scoped_ptr<AesCtrEncryptor> encryptor(new AesCtrEncryptor());
|
||||
scoped_ptr<AesEncryptor> encryptor;
|
||||
if (encryption_mode_ == kEncryptionModeAesCtr) {
|
||||
encryptor.reset(new AesCtrEncryptor);
|
||||
} else if (encryption_mode_ == kEncryptionModeAesCbc) {
|
||||
encryptor.reset(new AesCbcPkcs5Encryptor);
|
||||
} else {
|
||||
return Status(error::MUXER_FAILURE, "Unsupported encryption mode.");
|
||||
}
|
||||
const bool initialized = encryption_key_->iv.empty()
|
||||
? encryptor->InitializeWithRandomIv(
|
||||
encryption_key_->key, kDefaultIvSize)
|
||||
|
@ -183,7 +191,7 @@ Status EncryptingFragmenter::CreateEncryptor() {
|
|||
|
||||
void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
|
||||
DCHECK(encryptor_);
|
||||
CHECK(encryptor_->Encrypt(data, size, data));
|
||||
CHECK(encryptor_->EncryptData(data, size, data));
|
||||
}
|
||||
|
||||
Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {
|
||||
|
|
|
@ -9,6 +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/filters/vpx_parser.h"
|
||||
#include "packager/media/formats/mp4/fragmenter.h"
|
||||
#include "packager/media/formats/mp4/video_slice_header_parser.h"
|
||||
|
@ -16,7 +17,7 @@
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class AesCtrEncryptor;
|
||||
class AesEncryptor;
|
||||
class StreamInfo;
|
||||
struct EncryptionKey;
|
||||
|
||||
|
@ -32,7 +33,8 @@ class EncryptingFragmenter : public Fragmenter {
|
|||
EncryptingFragmenter(scoped_refptr<StreamInfo> info,
|
||||
TrackFragment* traf,
|
||||
scoped_ptr<EncryptionKey> encryption_key,
|
||||
int64_t clear_time);
|
||||
int64_t clear_time,
|
||||
EncryptionMode encryption_mode);
|
||||
|
||||
~EncryptingFragmenter() override;
|
||||
|
||||
|
@ -56,7 +58,7 @@ class EncryptingFragmenter : public Fragmenter {
|
|||
Status CreateEncryptor();
|
||||
|
||||
EncryptionKey* encryption_key() { return encryption_key_.get(); }
|
||||
AesCtrEncryptor* encryptor() { return encryptor_.get(); }
|
||||
AesEncryptor* encryptor() { return encryptor_.get(); }
|
||||
|
||||
void set_encryption_key(scoped_ptr<EncryptionKey> encryption_key) {
|
||||
encryption_key_ = encryption_key.Pass();
|
||||
|
@ -71,12 +73,13 @@ class EncryptingFragmenter : public Fragmenter {
|
|||
|
||||
scoped_refptr<StreamInfo> info_;
|
||||
scoped_ptr<EncryptionKey> encryption_key_;
|
||||
scoped_ptr<AesCtrEncryptor> encryptor_;
|
||||
scoped_ptr<AesEncryptor> 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_;
|
||||
int64_t clear_time_;
|
||||
EncryptionMode encryption_mode_;
|
||||
|
||||
scoped_ptr<VPxParser> vpx_parser_;
|
||||
scoped_ptr<VideoSliceHeaderParser> header_parser_;
|
||||
|
|
|
@ -20,6 +20,7 @@ enum FourCC {
|
|||
FOURCC_AVC1 = 0x61766331,
|
||||
FOURCC_AVCC = 0x61766343,
|
||||
FOURCC_BLOC = 0x626C6F63,
|
||||
FOURCC_CBC1 = 0x63626331,
|
||||
FOURCC_CENC = 0x63656e63,
|
||||
FOURCC_CO64 = 0x636f3634,
|
||||
FOURCC_CTTS = 0x63747473,
|
||||
|
|
|
@ -24,11 +24,13 @@ KeyRotationFragmenter::KeyRotationFragmenter(MovieFragment* moof,
|
|||
KeySource::TrackType track_type,
|
||||
int64_t crypto_period_duration,
|
||||
int64_t clear_time,
|
||||
MuxerListener* muxer_listener)
|
||||
MuxerListener* muxer_listener,
|
||||
EncryptionMode encryption_mode)
|
||||
: EncryptingFragmenter(info,
|
||||
traf,
|
||||
scoped_ptr<EncryptionKey>(new EncryptionKey()),
|
||||
clear_time),
|
||||
clear_time,
|
||||
encryption_mode),
|
||||
moof_(moof),
|
||||
encryption_key_source_(encryption_key_source),
|
||||
track_type_(track_type),
|
||||
|
|
|
@ -7,6 +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/key_source.h"
|
||||
#include "packager/media/event/muxer_listener.h"
|
||||
#include "packager/media/formats/mp4/encrypting_fragmenter.h"
|
||||
|
@ -40,7 +41,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
|
|||
KeySource::TrackType track_type,
|
||||
int64_t crypto_period_duration,
|
||||
int64_t clear_time,
|
||||
MuxerListener* muxer_listener);
|
||||
MuxerListener* muxer_listener,
|
||||
EncryptionMode encryption_mode);
|
||||
~KeyRotationFragmenter() override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -154,7 +154,8 @@ Status MP4Muxer::Initialize() {
|
|||
encryption_key_source(),
|
||||
max_sd_pixels(),
|
||||
clear_lead_in_seconds(),
|
||||
crypto_period_duration_in_seconds());
|
||||
crypto_period_duration_in_seconds(),
|
||||
encryption_mode());
|
||||
|
||||
if (!segmenter_initialized.ok())
|
||||
return segmenter_initialized;
|
||||
|
|
|
@ -38,6 +38,7 @@ const uint8_t kKeyRotationDefaultKeyId[] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
COMPILE_ASSERT(arraysize(kKeyRotationDefaultKeyId) == kCencKeyIdSize,
|
||||
cenc_key_id_must_be_size_16);
|
||||
|
||||
|
@ -49,9 +50,16 @@ uint64_t Rescale(uint64_t time_in_old_scale,
|
|||
|
||||
void GenerateSinf(const EncryptionKey& encryption_key,
|
||||
FourCC old_type,
|
||||
EncryptionMode encryption_mode,
|
||||
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;
|
||||
}
|
||||
|
||||
sinf->type.version = kCencSchemeVersion;
|
||||
sinf->info.track_encryption.is_encrypted = true;
|
||||
sinf->info.track_encryption.default_iv_size =
|
||||
|
@ -61,6 +69,7 @@ void GenerateSinf(const EncryptionKey& encryption_key,
|
|||
|
||||
void GenerateEncryptedSampleEntry(const EncryptionKey& encryption_key,
|
||||
double clear_lead_in_seconds,
|
||||
EncryptionMode encryption_mode,
|
||||
SampleDescription* description) {
|
||||
DCHECK(description);
|
||||
if (description->type == kVideo) {
|
||||
|
@ -72,7 +81,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, &entry.sinf);
|
||||
GenerateSinf(encryption_key, entry.format, encryption_mode, &entry.sinf);
|
||||
entry.format = FOURCC_ENCV;
|
||||
} else {
|
||||
DCHECK_EQ(kAudio, description->type);
|
||||
|
@ -84,7 +93,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, &entry.sinf);
|
||||
GenerateSinf(encryption_key, entry.format, encryption_mode, &entry.sinf);
|
||||
entry.format = FOURCC_ENCA;
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +136,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds) {
|
||||
double crypto_period_duration_in_seconds,
|
||||
EncryptionMode encryption_mode) {
|
||||
DCHECK_LT(0u, streams.size());
|
||||
muxer_listener_ = muxer_listener;
|
||||
progress_listener_ = progress_listener;
|
||||
|
@ -164,8 +174,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
kKeyRotationDefaultKeyId,
|
||||
kKeyRotationDefaultKeyId + arraysize(kKeyRotationDefaultKeyId));
|
||||
GenerateEncryptedSampleEntry(encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
|
||||
encryption_mode, &description);
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo, encryption_key.key_id,
|
||||
|
@ -177,7 +186,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_);
|
||||
muxer_listener_, encryption_mode);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -188,7 +197,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
return status;
|
||||
|
||||
GenerateEncryptedSampleEntry(*encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
encryption_mode, &description);
|
||||
|
||||
if (moov_->pssh.empty()) {
|
||||
moov_->pssh.resize(encryption_key->key_system_info.size());
|
||||
|
@ -205,7 +214,8 @@ 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());
|
||||
clear_lead_in_seconds * streams[i]->info()->time_scale(),
|
||||
encryption_mode);
|
||||
}
|
||||
|
||||
// Choose the first stream if there is no VIDEO.
|
||||
|
|
|
@ -12,6 +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/status.h"
|
||||
#include "packager/media/formats/mp4/box_definitions.h"
|
||||
|
||||
|
@ -65,7 +66,8 @@ class Segmenter {
|
|||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds);
|
||||
double crypto_period_duration_in_seconds,
|
||||
EncryptionMode encryption_mode);
|
||||
|
||||
/// Finalize the segmenter.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <limits>
|
||||
|
||||
#include "packager/media/base/buffer_reader.h"
|
||||
#include "packager/media/base/encryption_modes.h"
|
||||
#include "packager/media/formats/mp4/chunk_info_iterator.h"
|
||||
#include "packager/media/formats/mp4/composition_offset_iterator.h"
|
||||
#include "packager/media/formats/mp4/decoding_time_iterator.h"
|
||||
|
@ -597,10 +598,26 @@ scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
|
|||
return scoped_ptr<DecryptConfig>();
|
||||
}
|
||||
|
||||
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));
|
||||
sample_encryption_entry.subsamples,
|
||||
decryption_mode));
|
||||
}
|
||||
|
||||
} // namespace mp4
|
||||
|
|
|
@ -78,7 +78,7 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
|
|||
uint8_t* sample_data = sample->writable_data();
|
||||
|
||||
// Encrypt the data in-place.
|
||||
if (!encryptor_->Encrypt(sample_data, sample_size, sample_data)) {
|
||||
if (!encryptor_->EncryptData(sample_data, sample_size, sample_data)) {
|
||||
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame.");
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/base/sys_byteorder.h"
|
||||
#include "packager/media/base/decrypt_config.h"
|
||||
#include "packager/media/base/encryption_modes.h"
|
||||
#include "packager/media/formats/webm/webm_constants.h"
|
||||
|
||||
namespace edash_packager {
|
||||
|
@ -56,7 +56,8 @@ 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>()));
|
||||
std::vector<SubsampleEntry>(),
|
||||
kEncryptionModeAesCtr));
|
||||
*data_offset = frame_offset;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -30,6 +30,14 @@ Status WebMMuxer::Initialize() {
|
|||
"Key rotation is not implemented for WebM");
|
||||
}
|
||||
|
||||
if (encryption_key_source() && (encryption_mode() != kEncryptionModeAesCtr)) {
|
||||
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.");
|
||||
}
|
||||
|
||||
scoped_ptr<MkvWriter> writer(new MkvWriter);
|
||||
Status status = writer->Open(options().output_file_name);
|
||||
if (!status.ok())
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/media/base/aes_encryptor.h"
|
||||
#include "packager/media/base/aes_decryptor.h"
|
||||
#include "packager/media/base/audio_stream_info.h"
|
||||
#include "packager/media/base/key_source.h"
|
||||
#include "packager/media/base/media_sample.h"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#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/key_source.h"
|
||||
#include "packager/media/base/media_stream.h"
|
||||
#include "packager/media/base/muxer.h"
|
||||
|
@ -180,7 +181,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
muxer_video->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD,
|
||||
kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds);
|
||||
kCryptoDurationInSeconds,
|
||||
kEncryptionModeAesCtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +203,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
muxer_audio->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD,
|
||||
kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds);
|
||||
kCryptoDurationInSeconds,
|
||||
kEncryptionModeAesCtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue