7 #include "packager/media/base/playready_key_source.h"
9 #include <openssl/aes.h>
11 #include "packager/base/base64.h"
12 #include "packager/base/logging.h"
13 #include "packager/base/strings/string_number_conversions.h"
14 #include "packager/base/strings/string_util.h"
15 #include "packager/media/base/buffer_writer.h"
16 #include "packager/media/base/http_key_fetcher.h"
23 const uint32_t kHttpFetchTimeout = 60;
24 const std::string kPlayHeaderObject_4_1 =
"<WRMHEADER "
25 "xmlns=\"http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader\" "
26 "version=\"4.1.0.0\"><DATA><PROTECTINFO>"
27 "<KID VALUE=\"$0\" ALGID=\"AESCTR\" CHECKSUM=\"$1\"></KID></PROTECTINFO>"
28 "</DATA></WRMHEADER>";
29 const std::string kPlayHeaderObject_4_0 =
"<WRMHEADER "
30 "xmlns=\"http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader\" "
31 "version=\"4.0.0.0\"><DATA><PROTECTINFO><KEYLEN>16</KEYLEN>"
32 "<ALGID>AESCTR</ALGID></PROTECTINFO><KID>$0</KID><CHECKSUM>$1</CHECKSUM>"
33 "</DATA></WRMHEADER>";
34 const std::string kAcquireLicenseRequest =
35 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
36 "<soap:Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" "
37 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
38 "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
39 "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
41 "<AcquirePackagingData "
42 "xmlns=\"http://schemas.microsoft.com/DRM/2007/03/protocols\">"
44 "xmlns=\"http://schemas.microsoft.com/DRM"
45 "/2007/03/protocols/AcquirePackagingData/v1.0\">"
47 "<ProtectionSystemId>9A04F079-9840-4286-AB92-E65BE0885F95"
48 "</ProtectionSystemId>"
49 "</ProtectionSystems>"
50 "<StreamProtectionRequests>"
52 "<ProgramIdentifier>$0</ProgramIdentifier>"
53 "<OffsetFromProgramStart>P0S</OffsetFromProgramStart>"
54 "</StreamInformation>"
55 "</StreamProtectionRequests>"
57 "</AcquirePackagingData>"
61 bool Base64StringToBytes(
const std::string& base64_string,
62 std::vector<uint8_t>* bytes) {
65 if (!base::Base64Decode(base64_string, &str))
67 bytes->assign(str.begin(), str.end());
72 std::vector<uint8_t> ConvertGuidEndianness(
const std::vector<uint8_t>& input) {
73 std::vector<uint8_t> output = input;
74 if (output.size() > 7) {
93 const std::vector<uint8_t>& key,
94 std::vector<uint8_t>* output) {
96 std::vector<uint8_t> key_id_converted = ConvertGuidEndianness(key_id);
97 std::vector<uint8_t> encrypted_key_id(key_id_converted.size());
98 std::unique_ptr<AES_KEY> aes_key (
new AES_KEY);
99 CHECK_EQ(AES_set_encrypt_key(key.data(), key.size() * 8, aes_key.get()), 0);
100 AES_ecb_encrypt(key_id_converted.data(), encrypted_key_id.data(),
101 aes_key.get(), AES_ENCRYPT);
102 std::string checksum = std::string(encrypted_key_id.begin(),
103 encrypted_key_id.end()).substr(0, 8);
104 std::string base64_checksum;
105 base::Base64Encode(checksum, &base64_checksum);
106 std::string base64_key_id;
107 base::Base64Encode(std::string(key_id_converted.begin(),
108 key_id_converted.end()),
110 std::string playready_header = kPlayHeaderObject_4_0;
111 base::ReplaceFirstSubstringAfterOffset(
112 &playready_header, 0,
"$0", base64_key_id);
113 base::ReplaceFirstSubstringAfterOffset(
114 &playready_header, 0,
"$1", base64_checksum);
119 std::vector<uint16_t> record_value =
120 std::vector<uint16_t>(playready_header.begin(), playready_header.end());
122 uint16_t record_type = 1;
123 uint16_t record_length = record_value.size() * 2;
124 writer_pr_record.AppendInt(static_cast<uint8_t>(record_type & 0xff));
125 writer_pr_record.AppendInt(static_cast<uint8_t>((record_type >> 8) & 0xff));
126 writer_pr_record.AppendInt(static_cast<uint8_t>(record_length & 0xff));
127 writer_pr_record.AppendInt(static_cast<uint8_t>((record_length >> 8) & 0xff));
128 for (
auto record_item: record_value) {
129 writer_pr_record.AppendInt(static_cast<uint8_t>(record_item & 0xff));
130 writer_pr_record.AppendInt(static_cast<uint8_t>((record_item >> 8) & 0xff));
137 uint32_t playready_header_length = writer_pr_record.Size() + 4 + 2;
138 uint16_t record_count = 1;
140 static_cast<uint8_t>(playready_header_length & 0xff));
142 static_cast<uint8_t>((playready_header_length >> 8) & 0xff));
144 static_cast<uint8_t>((playready_header_length >> 16) & 0xff));
146 static_cast<uint8_t>((playready_header_length >> 24) & 0xff));
148 static_cast<uint8_t>(record_count & 0xff));
150 static_cast<uint8_t>((record_count >> 8) & 0xff));
151 writer_pr_header_object.AppendBuffer(writer_pr_record);
152 *output = std::vector<uint8_t>(writer_pr_header_object.
Buffer(),
153 writer_pr_header_object.
Buffer() +
154 writer_pr_header_object.Size());
155 return shaka::media::Status::OK;
161 const std::string& server_url)
163 server_url_(server_url) {
167 const std::string& client_cert_file,
168 const std::string& client_cert_private_key_file,
169 const std::string& client_cert_private_key_password)
171 server_url_(server_url),
172 client_cert_file_(client_cert_file),
173 client_cert_private_key_file_(client_cert_private_key_file),
174 client_cert_private_key_password_(client_cert_private_key_password) {
178 std::unique_ptr<EncryptionKey> encryption_key)
179 : encryption_key_(std::move(encryption_key)) {
182 PlayReadyKeySource::~PlayReadyKeySource() {}
185 const std::string& key_id_hex,
const std::string& key_hex) {
186 std::unique_ptr<EncryptionKey> encryption_key(
new EncryptionKey);
187 if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) {
188 LOG(ERROR) <<
"Cannot parse key_id_hex " << key_id_hex;
189 return std::unique_ptr<PlayReadyKeySource>();
191 std::vector<uint8_t> key;
192 if (!base::HexStringToBytes(key_hex, &encryption_key->key)) {
193 LOG(ERROR) <<
"Cannot parse key_hex " << key_hex;
194 return std::unique_ptr<PlayReadyKeySource>();
196 std::vector<uint8_t> pssh_data;
197 Status status = GeneratePlayReadyPsshData(
198 encryption_key->key_id, encryption_key->key, &pssh_data);
201 return std::unique_ptr<PlayReadyKeySource>();
204 info.add_key_id(encryption_key->key_id);
205 info.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId));
206 info.set_pssh_data(pssh_data);
208 encryption_key->key_system_info.push_back(info);
209 return std::unique_ptr<PlayReadyKeySource>(
213 Status RetrieveTextInXMLElement(
const std::string& element,
214 const std::string& xml,
215 std::string* value) {
216 std::string start_tag =
"<" + element +
">";
217 std::string end_tag =
"</" + element +
">";
218 std::size_t start_pos = xml.find(start_tag);
219 if (start_pos == std::string::npos) {
220 return Status(error::SERVER_ERROR,
221 "Unable to find tag: " + start_tag);
223 start_pos += start_tag.size();
224 std::size_t end_pos = xml.find(end_tag);
225 if (end_pos == std::string::npos) {
226 return Status(error::SERVER_ERROR,
227 "Unable to find tag: " + end_tag);
229 if (start_pos > end_pos) {
230 return Status(error::SERVER_ERROR,
"Invalid positions");
232 std::size_t segment_len = end_pos - start_pos;
233 *value = xml.substr(start_pos, segment_len);
237 Status SetKeyInformationFromServerResponse(
const std::string& response,
238 EncryptionKey* encryption_key) {
243 std::string key_id_hex;
244 Status status = RetrieveTextInXMLElement(
"KeyId", response, &key_id_hex);
249 std::remove(key_id_hex.begin(), key_id_hex.end(),
'-'), key_id_hex.end());
250 std::string key_data_b64;
251 status = RetrieveTextInXMLElement(
"KeyData", response, &key_data_b64);
253 LOG(ERROR) <<
"Key retreiving KeyData";
256 std::string pssh_data_b64;
257 status = RetrieveTextInXMLElement(
"Data", response, &pssh_data_b64);
259 LOG(ERROR) <<
"Key retreiving Data";
262 if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) {
263 LOG(ERROR) <<
"Cannot parse key_id_hex, " << key_id_hex;
264 return Status(error::SERVER_ERROR,
"Cannot parse key_id_hex.");
267 if (!Base64StringToBytes(key_data_b64, &encryption_key->key)) {
268 LOG(ERROR) <<
"Cannot parse key, " << key_data_b64;
269 return Status(error::SERVER_ERROR,
"Cannot parse key.");
271 std::vector<uint8_t> pssh_data;
272 if (!Base64StringToBytes(pssh_data_b64, &pssh_data)) {
273 LOG(ERROR) <<
"Cannot parse pssh data, " << pssh_data_b64;
274 return Status(error::SERVER_ERROR,
"Cannot parse pssh.");
276 ProtectionSystemSpecificInfo info;
277 info.add_key_id(encryption_key->key_id);
278 info.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId));
279 info.set_pssh_data(pssh_data);
280 encryption_key->key_system_info.push_back(info);
284 Status PlayReadyKeySource::FetchKeysWithProgramIdentifier(
285 const std::string& program_identifier) {
286 std::unique_ptr<EncryptionKey> encryption_key(
new EncryptionKey);
287 HttpKeyFetcher key_fetcher(kHttpFetchTimeout);
288 if (!client_cert_file_.empty() && !client_cert_private_key_file_.empty() &&
289 !client_cert_private_key_password_.empty()) {
290 key_fetcher.SetClientCertInfo(client_cert_file_,
291 client_cert_private_key_file_,
292 client_cert_private_key_password_);
294 if (!ca_file_.empty()) {
295 key_fetcher.SetCaFile(ca_file_);
297 std::string acquire_license_request = kAcquireLicenseRequest;
298 base::ReplaceFirstSubstringAfterOffset(
299 &acquire_license_request, 0,
"$0", program_identifier);
300 std::string acquire_license_response;
301 Status status = key_fetcher.FetchKeys(server_url_, acquire_license_request,
302 &acquire_license_response);
304 LOG(ERROR) <<
"Server response: " << acquire_license_response;
307 status = SetKeyInformationFromServerResponse(acquire_license_response,
308 encryption_key.get());
309 encryption_key_ = std::move(encryption_key);
314 const std::vector<uint8_t>& init_data) {
324 DCHECK(encryption_key_);
325 *key = *encryption_key_;
334 DCHECK(encryption_key_);
335 *key = *encryption_key_;
340 TrackType track_type,
343 *key = *encryption_key_;