Shaka Packager SDK
Loading...
Searching...
No Matches
raw_key_source.cc
1// Copyright 2016 Google LLC. 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 <cstdint>
11#include <memory>
12#include <string>
13#include <utility>
14#include <vector>
15
16#include <absl/log/check.h>
17#include <absl/log/log.h>
18#include <absl/strings/escaping.h>
19
20#include <packager/crypto_params.h>
21#include <packager/macros/compiler.h>
22#include <packager/macros/status.h>
23#include <packager/media/base/key_source.h>
24#include <packager/media/base/protection_system_specific_info.h>
25#include <packager/status.h>
26#include <packager/utils/bytes_to_string_view.h>
27
28namespace {
29const char kEmptyDrmLabel[] = "";
30} // namespace
31
32namespace shaka {
33namespace media {
34
35RawKeySource::~RawKeySource() {}
36
37Status RawKeySource::FetchKeys(EmeInitDataType init_data_type,
38 const std::vector<uint8_t>& init_data) {
39 UNUSED(init_data_type);
40 UNUSED(init_data);
41 // Do nothing for raw key encryption/decryption.
42 return Status::OK;
43}
44
45Status RawKeySource::GetKey(const std::string& stream_label,
46 EncryptionKey* key) {
47 DCHECK(key);
48 // Try to find the key with label |stream_label|. If it is not available,
49 // fall back to the default empty label if it is available.
50 auto iter = encryption_key_map_.find(stream_label);
51 if (iter == encryption_key_map_.end()) {
52 iter = encryption_key_map_.find(kEmptyDrmLabel);
53 if (iter == encryption_key_map_.end()) {
54 return Status(error::NOT_FOUND,
55 "Key for '" + stream_label + "' was not found.");
56 }
57 }
58 *key = *iter->second;
59 return Status::OK;
60}
61
62Status RawKeySource::GetKey(const std::vector<uint8_t>& key_id,
63 EncryptionKey* key) {
64 DCHECK(key);
65 for (const auto& pair : encryption_key_map_) {
66 if (pair.second->key_id == key_id) {
67 *key = *pair.second;
68 return Status::OK;
69 }
70 }
71 return Status(error::INTERNAL_ERROR,
72 "Key for key_id=" +
73 absl::BytesToHexString(byte_vector_to_string_view(key_id)) +
74 " was not found.");
75}
76
78 uint32_t crypto_period_index,
79 int32_t crypto_period_duration_in_seconds,
80 const std::string& stream_label,
81 EncryptionKey* key) {
82 UNUSED(crypto_period_duration_in_seconds);
83
84 RETURN_IF_ERROR(GetKey(stream_label, key));
85
86 // A naive key rotation algorithm is implemented here by left rotating the
87 // key, key_id and pssh. Note that this implementation is only intended for
88 // testing purpose. The actual key rotation algorithm can be much more
89 // complicated.
90 LOG(WARNING)
91 << "This naive key rotation algorithm should not be used in production.";
92 std::rotate(key->key_id.begin(),
93 key->key_id.begin() + (crypto_period_index % key->key_id.size()),
94 key->key_id.end());
95 std::rotate(key->key.begin(),
96 key->key.begin() + (crypto_period_index % key->key.size()),
97 key->key.end());
98 key->key_ids.clear();
99 key->key_ids.emplace_back(key->key_id);
100
101 return Status::OK;
102}
103
104std::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 }
114
115 std::vector<std::vector<uint8_t>> key_ids;
116 for (const auto& entry : raw_key.key_map)
117 key_ids.emplace_back(entry.second.key_id);
118
119 EncryptionKeyMap encryption_key_map;
120 for (const auto& entry : raw_key.key_map) {
121 const std::string& drm_label = entry.first;
122 const RawKeyParams::KeyInfo& key_pair = entry.second;
123
124 if (key_pair.key_id.size() != 16) {
125 LOG(ERROR) << "Invalid key ID size '" << key_pair.key_id.size()
126 << "', must be 16 bytes.";
127 return std::unique_ptr<RawKeySource>();
128 }
129 if (key_pair.key.size() != 16) {
130 // CENC only supports AES-128, i.e. 16 bytes.
131 LOG(ERROR) << "Invalid key size '" << key_pair.key.size()
132 << "', must be 16 bytes.";
133 return std::unique_ptr<RawKeySource>();
134 }
135 if (!key_pair.iv.empty() && key_pair.iv.size() != 8 &&
136 key_pair.iv.size() != 16) {
137 LOG(ERROR) << "Invalid IV '" << key_pair.iv.size()
138 << "', must be 8 or 16 bytes.";
139 return std::unique_ptr<RawKeySource>();
140 }
141
142 std::unique_ptr<EncryptionKey> encryption_key(new EncryptionKey);
143 encryption_key->key_id = key_pair.key_id;
144 encryption_key->key_ids = key_ids;
145 encryption_key->key = key_pair.key;
146 encryption_key->iv = (key_pair.iv.empty()) ? raw_key.iv : key_pair.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
155RawKeySource::RawKeySource() {}
156
157RawKeySource::RawKeySource(EncryptionKeyMap&& encryption_key_map)
158 : encryption_key_map_(std::move(encryption_key_map)) {}
159
160} // namespace media
161} // namespace shaka
A key source that uses raw keys for encryption.
Status FetchKeys(EmeInitDataType init_data_type, const std::vector< uint8_t > &init_data) override
Status GetKey(const std::string &stream_label, EncryptionKey *key) override
Status GetCryptoPeriodKey(uint32_t crypto_period_index, int32_t crypto_period_duration_in_seconds, const std::string &stream_label, EncryptionKey *key) override
static std::unique_ptr< RawKeySource > Create(const RawKeyParams &raw_key)
All the methods that are virtual are virtual for mocking.
std::string_view byte_vector_to_string_view(const std::vector< uint8_t > &bytes)
Convert byte vector to string_view.
std::vector< std::vector< uint8_t > > key_ids
The IDs of the other keys to include in PSSH info.
Definition key_source.h:43
std::vector< uint8_t > key_id
The ID of this key.
Definition key_source.h:41
static bool ParseBoxes(const uint8_t *data, size_t data_size, std::vector< ProtectionSystemSpecificInfo > *pssh_boxes)