Shaka Packager SDK
raw_key_source.cc
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/base/raw_key_source.h"
8 
9 #include <algorithm>
10 #include "packager/base/logging.h"
11 #include "packager/base/strings/string_number_conversions.h"
12 
13 namespace {
14 const char kEmptyDrmLabel[] = "";
15 } // namespace
16 
17 namespace shaka {
18 namespace media {
19 
20 RawKeySource::~RawKeySource() {}
21 
22 Status RawKeySource::FetchKeys(EmeInitDataType init_data_type,
23  const std::vector<uint8_t>& init_data) {
24  // Do nothing for raw key encryption/decryption.
25  return Status::OK;
26 }
27 
28 Status RawKeySource::GetKey(const std::string& stream_label,
29  EncryptionKey* key) {
30  DCHECK(key);
31  // Try to find the key with label |stream_label|. If it is not available,
32  // fall back to the default empty label if it is available.
33  auto iter = encryption_key_map_.find(stream_label);
34  if (iter == encryption_key_map_.end()) {
35  iter = encryption_key_map_.find(kEmptyDrmLabel);
36  if (iter == encryption_key_map_.end()) {
37  return Status(error::NOT_FOUND,
38  "Key for '" + stream_label + "' was not found.");
39  }
40  }
41  *key = *iter->second;
42  return Status::OK;
43 }
44 
45 Status RawKeySource::GetKey(const std::vector<uint8_t>& key_id,
46  EncryptionKey* key) {
47  DCHECK(key);
48  for (const auto& pair : encryption_key_map_) {
49  if (pair.second->key_id == key_id) {
50  *key = *pair.second;
51  return Status::OK;
52  }
53  }
54  return Status(error::INTERNAL_ERROR,
55  "Key for key_id=" + base::HexEncode(&key_id[0], key_id.size()) +
56  " was not found.");
57 }
58 
59 Status RawKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
60  const std::string& stream_label,
61  EncryptionKey* key) {
62  Status status = GetKey(stream_label, key);
63  if (!status.ok())
64  return status;
65 
66  // A naive key rotation algorithm is implemented here by left rotating the
67  // key, key_id and pssh. Note that this implementation is only intended for
68  // testing purpose. The actual key rotation algorithm can be much more
69  // complicated.
70  LOG(WARNING)
71  << "This naive key rotation algorithm should not be used in production.";
72  std::rotate(key->key_id.begin(),
73  key->key_id.begin() + (crypto_period_index % key->key_id.size()),
74  key->key_id.end());
75  std::rotate(key->key.begin(),
76  key->key.begin() + (crypto_period_index % key->key.size()),
77  key->key.end());
78 
79  for (auto& key_system : key->key_system_info) {
80  std::vector<uint8_t> pssh_data = key_system.pssh_data();
81  if (!pssh_data.empty()) {
82  std::rotate(pssh_data.begin(),
83  pssh_data.begin() + (crypto_period_index % pssh_data.size()),
84  pssh_data.end());
85  key_system.set_pssh_data(pssh_data);
86  }
87 
88  // Rotate the key_ids in pssh as well if exists.
89  // Save a local copy of the key ids before clearing the key ids in
90  // |key_system|. The key ids will be updated and added back later.
91  std::vector<std::vector<uint8_t>> key_ids_copy = key_system.key_ids();
92  key_system.clear_key_ids();
93  for (std::vector<uint8_t>& key_id : key_ids_copy) {
94  std::rotate(key_id.begin(),
95  key_id.begin() + (crypto_period_index % key_id.size()),
96  key_id.end());
97  key_system.add_key_id(key_id);
98  }
99  }
100 
101  return Status::OK;
102 }
103 
104 std::unique_ptr<RawKeySource> RawKeySource::Create(
105  const RawKeyParams& raw_key) {
106  std::vector<ProtectionSystemSpecificInfo> key_system_info;
107  if (!raw_key.pssh.empty()) {
109  raw_key.pssh.data(), raw_key.pssh.size(), &key_system_info)) {
110  LOG(ERROR) << "--pssh argument should be full PSSH boxes.";
111  return std::unique_ptr<RawKeySource>();
112  }
113  } else {
114  // If there aren't any PSSH boxes given, create one with the common system
115  // ID.
116  key_system_info.resize(1);
117  for (const auto& entry : raw_key.key_map) {
118  const RawKeyParams::KeyInfo& key_pair = entry.second;
119  key_system_info.back().add_key_id(key_pair.key_id);
120  }
121  key_system_info.back().set_system_id(kCommonSystemId,
122  arraysize(kCommonSystemId));
123  key_system_info.back().set_pssh_box_version(1);
124  }
125 
126  EncryptionKeyMap encryption_key_map;
127  for (const auto& entry : raw_key.key_map) {
128  const std::string& drm_label = entry.first;
129  const RawKeyParams::KeyInfo& key_pair = entry.second;
130 
131  if (key_pair.key_id.size() != 16) {
132  LOG(ERROR) << "Invalid key ID size '" << key_pair.key_id.size()
133  << "', must be 16 bytes.";
134  return std::unique_ptr<RawKeySource>();
135  }
136  if (key_pair.key.size() != 16) {
137  // CENC only supports AES-128, i.e. 16 bytes.
138  LOG(ERROR) << "Invalid key size '" << key_pair.key.size()
139  << "', must be 16 bytes.";
140  return std::unique_ptr<RawKeySource>();
141  }
142 
143  std::unique_ptr<EncryptionKey> encryption_key(new EncryptionKey);
144  encryption_key->key_id = key_pair.key_id;
145  encryption_key->key = key_pair.key;
146  encryption_key->iv = raw_key.iv;
147  encryption_key->key_system_info = key_system_info;
148  encryption_key_map[drm_label] = std::move(encryption_key);
149  }
150 
151  return std::unique_ptr<RawKeySource>(
152  new RawKeySource(std::move(encryption_key_map)));
153 }
154 
155 RawKeySource::RawKeySource() {}
156 RawKeySource::RawKeySource(EncryptionKeyMap&& encryption_key_map)
157  : encryption_key_map_(std::move(encryption_key_map)) {}
158 
159 } // namespace media
160 } // namespace shaka
Status GetCryptoPeriodKey(uint32_t crypto_period_index, const std::string &stream_label, EncryptionKey *key) override
All the methods that are virtual are virtual for mocking.
static bool ParseBoxes(const uint8_t *data, size_t data_size, std::vector< ProtectionSystemSpecificInfo > *pssh_boxes)
Raw key encryption/decryption parameters, i.e. with key parameters provided.
Definition: crypto_params.h:99
std::map< StreamLabel, KeyInfo > key_map
std::vector< uint8_t > iv
A key source that uses raw keys for encryption.
static std::unique_ptr< RawKeySource > Create(const RawKeyParams &raw_key)
Status GetKey(const std::string &stream_label, EncryptionKey *key) override
std::vector< uint8_t > pssh
Status FetchKeys(EmeInitDataType init_data_type, const std::vector< uint8_t > &init_data) override