7 #include "packager/media/formats/webm/encryptor.h"
9 #include <gflags/gflags.h>
10 #include "packager/media/base/aes_encryptor.h"
11 #include "packager/media/base/buffer_writer.h"
12 #include "packager/media/base/fourccs.h"
13 #include "packager/media/base/media_sample.h"
14 #include "packager/media/codecs/vp9_parser.h"
15 #include "packager/media/formats/webm/webm_constants.h"
22 const size_t kAesBlockSize = 16;
24 Status CreateContentEncryption(mkvmuxer::Track* track, EncryptionKey* key) {
25 if (!track->AddContentEncoding()) {
26 return Status(error::INTERNAL_ERROR,
27 "Could not add ContentEncoding to track.");
30 mkvmuxer::ContentEncoding*
const encoding =
31 track->GetContentEncodingByIndex(0);
33 return Status(error::INTERNAL_ERROR,
34 "Could not add ContentEncoding to track.");
37 mkvmuxer::ContentEncAESSettings*
const aes = encoding->enc_aes_settings();
39 return Status(error::INTERNAL_ERROR,
40 "Error getting ContentEncAESSettings.");
42 if (aes->cipher_mode() != mkvmuxer::ContentEncAESSettings::kCTR) {
43 return Status(error::INTERNAL_ERROR,
"Cipher Mode is not CTR.");
46 if (!key->key_id.empty() &&
47 !encoding->SetEncryptionID(
48 reinterpret_cast<const uint8_t*>(key->key_id.data()),
49 key->key_id.size())) {
50 return Status(error::INTERNAL_ERROR,
"Error setting encryption ID.");
57 Encryptor::Encryptor() {}
59 Encryptor::~Encryptor() {}
62 KeySource::TrackType track_type,
65 bool webm_subsample_encryption) {
67 return CreateEncryptor(muxer_listener, track_type, codec, key_source,
68 webm_subsample_encryption);
73 return CreateContentEncryption(track, key_.get());
80 const size_t sample_size = sample->data_size();
84 std::vector<VPxFrameInfo> vpx_frames;
86 if (!vpx_parser_->Parse(sample->data(), sample_size, &vpx_frames)) {
87 return Status(error::MUXER_FAILURE,
"Failed to parse VPx frame.");
92 const size_t iv_size = encryptor_->iv().size();
93 if (iv_size != kWebMIvSize) {
94 return Status(error::MUXER_FAILURE,
95 "Incorrect size WebM encryption IV.");
97 if (vpx_frames.size()) {
101 if (vpx_frames.size() > kWebMMaxSubsamples) {
102 return Status(error::MUXER_FAILURE,
103 "Maximum number of VPx encryption partitions exceeded.");
105 size_t num_partitions =
106 vpx_frames.size() == 1 ? 1 : vpx_frames.size() * 2;
107 size_t header_size = kWebMSignalByteSize + iv_size +
108 kWebMNumPartitionsSize +
109 (kWebMPartitionOffsetSize * num_partitions);
110 sample->resize_data(header_size + sample_size);
111 uint8_t* sample_data = sample->writable_data();
112 memmove(sample_data + header_size, sample_data, sample_size);
113 sample_data[0] = kWebMEncryptedSignal | kWebMPartitionedSignal;
114 memcpy(sample_data + kWebMSignalByteSize, encryptor_->iv().data(),
116 sample_data[kWebMSignalByteSize + kWebMIvSize] =
117 static_cast<uint8_t
>(num_partitions);
118 uint32_t partition_offset = 0;
119 BufferWriter offsets_buffer(kWebMPartitionOffsetSize * num_partitions);
120 for (
const auto& vpx_frame : vpx_frames) {
121 uint32_t encrypted_size =
static_cast<uint32_t
>(
122 vpx_frame.frame_size - vpx_frame.uncompressed_header_size);
123 encrypted_size -= encrypted_size % kAesBlockSize;
124 uint32_t clear_size =
125 static_cast<uint32_t
>(vpx_frame.frame_size - encrypted_size);
126 partition_offset += clear_size;
127 offsets_buffer.
AppendInt(partition_offset);
128 if (encrypted_size > 0) {
129 uint8_t* encrypted_ptr = sample_data + header_size + partition_offset;
130 if (!encryptor_->Crypt(encrypted_ptr, encrypted_size, encrypted_ptr)) {
131 return Status(error::MUXER_FAILURE,
"Failed to encrypt the frame.");
133 partition_offset += encrypted_size;
135 if (num_partitions > 1) {
136 offsets_buffer.
AppendInt(partition_offset);
139 DCHECK_EQ(num_partitions * kWebMPartitionOffsetSize,
140 offsets_buffer.Size());
141 memcpy(sample_data + kWebMSignalByteSize + kWebMIvSize +
142 kWebMNumPartitionsSize,
143 offsets_buffer.
Buffer(), offsets_buffer.Size());
147 sample->resize_data(sample_size + iv_size + kWebMSignalByteSize);
148 uint8_t* sample_data = sample->writable_data();
151 if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) {
152 return Status(error::MUXER_FAILURE,
"Failed to encrypt the frame.");
157 memmove(sample_data + iv_size + kWebMSignalByteSize, sample_data,
159 sample_data[0] = kWebMEncryptedSignal;
160 memcpy(sample_data + 1, encryptor_->iv().data(), iv_size);
162 encryptor_->UpdateIv();
165 sample->resize_data(sample_size + 1);
166 uint8_t* sample_data = sample->writable_data();
167 memmove(sample_data + 1, sample_data, sample_size);
168 sample_data[0] = 0x00;
175 KeySource::TrackType track_type,
178 bool webm_subsample_encryption) {
179 std::unique_ptr<EncryptionKey> encryption_key(
new EncryptionKey());
180 Status status = key_source->
GetKey(track_type, encryption_key.get());
183 if (encryption_key->iv.empty()) {
185 return Status(error::INTERNAL_ERROR,
"Failed to generate random iv.");
187 DCHECK_EQ(kWebMIvSize, encryption_key->iv.size());
189 const bool initialized =
190 encryptor->InitializeWithIv(encryption_key->key, encryption_key->iv);
192 return Status(error::INTERNAL_ERROR,
"Failed to create the encryptor.");
194 if (webm_subsample_encryption && codec == kCodecVP9) {
199 if (muxer_listener) {
200 const bool kInitialEncryptionInfo =
true;
202 kInitialEncryptionInfo, FOURCC_cenc, encryption_key->key_id,
203 encryptor->iv(), encryption_key->key_system_info);
206 key_ = std::move(encryption_key);
207 encryptor_ = std::move(encryptor);