1use crate::{
4 binary_format::xmr_license::CipherType,
5 crypto::{
6 aes,
7 ecc_p256::{self, ToUntaggedBytes},
8 sha256,
9 },
10 device::Device,
11 license::License,
12 pssh::WrmHeader,
13 revocation_list::{RevocationListInfos, RevocationLists},
14 xml_key::XmlKey,
15 xml_utils,
16};
17use base64::{Engine, prelude::BASE64_STANDARD};
18use rand::{RngExt, rng};
19use std::{
20 fmt,
21 sync::{Arc, RwLock},
22 time::{SystemTime, UNIX_EPOCH},
23};
24
25const CLIENT_VERSION: &str = "10.0.16384.10011";
26const RGB_MAGIC_CONSTANT_ZERO: [u8; 16] = [
27 0x7e, 0xe9, 0xed, 0x4a, 0xf7, 0x73, 0x22, 0x4f, 0x00, 0xb8, 0xea, 0x7e, 0xfb, 0x02, 0x7c, 0xbb,
28];
29
30#[derive(Clone)]
32pub struct KeyId([u8; 16]);
33
34impl KeyId {
35 fn from_uuid(u: &[u8; 16]) -> Self {
36 Self([
37 u[3], u[2], u[1], u[0], u[5], u[4], u[7], u[6], u[8], u[9], u[10], u[11], u[12], u[13],
38 u[14], u[15],
39 ])
40 }
41}
42
43impl From<[u8; 16]> for KeyId {
44 fn from(value: [u8; 16]) -> Self {
45 KeyId(value)
46 }
47}
48
49impl From<KeyId> for [u8; 16] {
50 fn from(value: KeyId) -> Self {
51 value.0
52 }
53}
54
55impl AsRef<[u8]> for KeyId {
56 fn as_ref(&self) -> &[u8] {
57 &self.0
58 }
59}
60
61impl fmt::Debug for KeyId {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 f.write_str(hex::encode(self.0).as_str())
64 }
65}
66
67impl fmt::Display for KeyId {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.write_str(hex::encode(self.0).as_str())
70 }
71}
72
73#[derive(Clone)]
75pub struct ContentKey(Box<[u8]>);
76
77impl From<Box<[u8]>> for ContentKey {
78 fn from(value: Box<[u8]>) -> Self {
79 ContentKey(value)
80 }
81}
82
83impl From<ContentKey> for Box<[u8]> {
84 fn from(value: ContentKey) -> Self {
85 value.0
86 }
87}
88
89impl AsRef<[u8]> for ContentKey {
90 fn as_ref(&self) -> &[u8] {
91 &self.0
92 }
93}
94
95impl fmt::Debug for ContentKey {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.write_str(hex::encode(&self.0).as_str())
98 }
99}
100
101impl fmt::Display for ContentKey {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.write_str(hex::encode(&self.0).as_str())
104 }
105}
106
107struct ContentIntegrityKey(Box<[u8]>);
108
109impl From<Box<[u8]>> for ContentIntegrityKey {
110 fn from(value: Box<[u8]>) -> Self {
111 ContentIntegrityKey(value)
112 }
113}
114
115impl From<ContentIntegrityKey> for Box<[u8]> {
116 fn from(value: ContentIntegrityKey) -> Self {
117 value.0
118 }
119}
120
121impl AsRef<[u8]> for ContentIntegrityKey {
122 fn as_ref(&self) -> &[u8] {
123 &self.0
124 }
125}
126
127impl fmt::Debug for ContentIntegrityKey {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 f.write_str(hex::encode(&self.0).as_str())
130 }
131}
132
133impl fmt::Display for ContentIntegrityKey {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.write_str(hex::encode(&self.0).as_str())
136 }
137}
138
139type KidCkCi = (KeyId, ContentKey, ContentIntegrityKey);
140type KidCk = (KeyId, ContentKey);
141
142#[derive(Debug, Clone)]
146pub struct Cdm {
147 device: Arc<Device>,
148 rev_list_infos: Arc<RwLock<Option<RevocationListInfos>>>,
149}
150
151impl Cdm {
152 pub fn from_device(device: Device) -> Self {
154 Self {
155 device: Arc::new(device),
156 rev_list_infos: Arc::new(RwLock::new(None)),
157 }
158 }
159
160 pub fn with_initial_revocation_list_infos(
162 mut self,
163 rev_list_infos: RevocationListInfos,
164 ) -> Self {
165 self.rev_list_infos = Arc::new(RwLock::new(Some(rev_list_infos)));
166 self
167 }
168
169 pub fn get_current_revocation_list_infos(&self) -> Option<RevocationListInfos> {
171 self.rev_list_infos.read().unwrap().clone()
172 }
173
174 pub fn get_license_challenge(
182 &self,
183 wrm_header: WrmHeader,
184 custom_data: Option<String>,
185 ) -> Result<String, crate::Error> {
186 let nonce = BASE64_STANDARD.encode(rng().random::<[u8; 16]>());
187 let xml_key = XmlKey::new();
188 let wmrm_cipher = BASE64_STANDARD.encode(Self::key_data(&xml_key));
189 let cert_cipher = BASE64_STANDARD.encode(self.cipher_data(&xml_key)?);
190
191 let protocol_version = match wrm_header.version() {
192 [4, 3, 0, 0] => "5",
193 [4, 2, 0, 0] => "4",
194 _ => "1",
195 };
196
197 let la_content_tag = xml_utils::build_digest_content(
198 String::from(protocol_version),
199 String::from(CLIENT_VERSION),
200 Self::client_time(),
201 wrm_header.into(),
202 nonce,
203 wmrm_cipher,
204 cert_cipher,
205 self.rev_list_infos.read().unwrap().as_ref(),
206 custom_data,
207 )?;
208
209 let la_content = xml_utils::render(&la_content_tag)?;
210 let la_hash = BASE64_STANDARD.encode(sha256::hash(&la_content));
211
212 let signed_info_tag = xml_utils::build_signed_info(la_hash)?;
213 let signed_info = xml_utils::render(&signed_info_tag)?;
214
215 let signature = ecc_p256::sign(self.device.signing_key(), &signed_info);
216 let signature = BASE64_STANDARD.encode(signature);
217
218 let public_key = self
219 .device
220 .signing_key()
221 .verifying_key()
222 .as_affine()
223 .to_untagged_bytes();
224 let public_key = BASE64_STANDARD.encode(public_key);
225
226 let challenge_tag = xml_utils::build_license_challenge(
227 la_content_tag,
228 signed_info_tag,
229 signature,
230 public_key,
231 )?;
232
233 let challenge = xml_utils::render(&challenge_tag)?;
234
235 String::from_utf8(challenge).map_err(|e| e.into())
236 }
237
238 pub fn get_keys_from_challenge_response(
240 &self,
241 response: &str,
242 ) -> Result<Vec<KidCk>, crate::Error> {
243 let licenses = xml_utils::parse_challenge_response(response)?;
244 if licenses.is_empty() {
245 return Err(crate::Error::LicenseMissingError);
246 }
247
248 let device_public_key = self
249 .device
250 .encryption_key()
251 .public()
252 .as_element()
253 .to_untagged_bytes();
254
255 let mut decrypted_keys = Vec::<KidCk>::with_capacity(licenses.len());
256
257 for license in licenses {
258 let license = match License::from_b64(license.as_str()) {
259 Ok(license) => license,
260 Err(e) => {
261 log::error!("Failed to create license: {e:?}");
262 continue;
263 }
264 };
265
266 if *license.public_key()? != *device_public_key {
267 return Err(crate::Error::PublicKeyMismatchError("device"));
268 }
269
270 let aux_key = license.auxiliary_key();
271
272 decrypted_keys.extend(license.encrypted_keys().iter().filter_map(|encrypted_key| {
273 let (kid, ck, ci) = self
274 .decrypt_key(encrypted_key, aux_key)
275 .inspect_err(|e| log::error!("Failed to decrypt key: {e:?}"))
276 .ok()?;
277
278 let (msg, signature) = license
279 .cmac_verification_data()
280 .inspect_err(|e| {
281 log::error!(
282 "Failed to get MAC verification data {e:?}. Skipping KID: {kid:?}"
283 )
284 })
285 .ok()?;
286
287 aes::verify_cmac(ci.as_ref(), msg, signature)
288 .inspect_err(|e| log::error!("Signature mismatch {e:?}. Skipping KID: {kid:?}"))
289 .ok()?;
290
291 Some((kid, ck))
292 }));
293 }
294 let rev_lists_update = RevocationLists::from_xml_str(response)
295 .inspect_err(|e| log::error!("Failed to parse revocation lists {e:?}"));
296
297 if let Ok(rev_lists_update) = rev_lists_update
298 && !rev_lists_update.is_empty()
299 {
300 let rev_list_infos_update =
301 RevocationListInfos::from_revocation_lists(&rev_lists_update);
302
303 let mut rev_list_infos = self.rev_list_infos.write().unwrap();
304 match rev_list_infos.as_mut() {
305 Some(r) => {
306 let _ = r.update(&rev_list_infos_update);
307 }
308 None => {
309 let _ = rev_list_infos.insert(rev_list_infos_update);
310 }
311 };
312 }
313
314 Ok(decrypted_keys)
315 }
316
317 fn decrypt_key(
318 &self,
319 encrypted_key: &(CipherType, &[u8; 16], &[u8]),
320 aux_key: Option<&[u8; 16]>,
321 ) -> Result<KidCkCi, crate::Error> {
322 if !matches!(
323 encrypted_key.0,
324 CipherType::Ecc256 | CipherType::Ecc256WithKZ | CipherType::Ecc256ViaSymmetric
325 ) {
326 return Err(crate::Error::UnsupportedCipherTypeError(encrypted_key.0));
327 }
328
329 let decrypted = ecc_p256::decrypt(self.device.encryption_key().secret(), encrypted_key.2)?;
330
331 let (ci, ck) =
332 match aux_key {
333 None => {
334 let ci = decrypted
335 .get(..16)
336 .ok_or(crate::Error::SliceOutOfBoundsError(
337 "decrypted",
338 decrypted.len(),
339 ))?
340 .to_vec();
341 let ck = decrypted
342 .get(16..32)
343 .ok_or(crate::Error::SliceOutOfBoundsError(
344 "decrypted",
345 decrypted.len(),
346 ))?
347 .to_vec();
348
349 (ci, ck)
350 }
351 Some(aux_key) => {
352 let ck = decrypted
353 .iter()
354 .copied()
355 .skip(1)
356 .step_by(2)
357 .take(16)
358 .collect::<Vec<_>>();
359
360 if encrypted_key.0 != CipherType::Ecc256ViaSymmetric {
361 let ci = decrypted
362 .iter()
363 .copied()
364 .step_by(2)
365 .take(16)
366 .collect::<Vec<_>>();
367
368 (ci, ck)
369 } else {
370 let embedded_root_license = encrypted_key.2.get(..144).ok_or(
371 crate::Error::SliceOutOfBoundsError(
372 "encrypted_key",
373 encrypted_key.2.len(),
374 ),
375 )?;
376 let embedded_leaf_license = encrypted_key.2.get(144..).ok_or(
377 crate::Error::SliceOutOfBoundsError(
378 "encrypted_key",
379 encrypted_key.2.len(),
380 ),
381 )?;
382
383 let rgb_key = ck
384 .iter()
385 .zip(RGB_MAGIC_CONSTANT_ZERO)
386 .map(|v| v.0 ^ v.1)
387 .collect::<Vec<_>>();
388
389 let content_key_prime = aes::encrypt_ecb(&ck, &rgb_key)?;
390 let uplink_x_key = aes::encrypt_ecb(&content_key_prime, aux_key)?;
391
392 let secondary_key = aes::encrypt_ecb(
393 &ck,
394 embedded_root_license.get(128..).ok_or(
395 crate::Error::SliceOutOfBoundsError(
396 "embedded_root_license",
397 embedded_root_license.len(),
398 ),
399 )?,
400 )?;
401
402 let embedded_leaf_license =
403 aes::encrypt_ecb(&uplink_x_key, embedded_leaf_license)?;
404 let embedded_leaf_license =
405 aes::encrypt_ecb(&secondary_key, &embedded_leaf_license)?;
406
407 let ci = embedded_leaf_license
408 .get(..16)
409 .ok_or(crate::Error::SliceOutOfBoundsError(
410 "embedded_leaf_license",
411 embedded_leaf_license.len(),
412 ))?
413 .to_vec();
414 let ck = embedded_leaf_license
415 .get(16..)
416 .ok_or(crate::Error::SliceOutOfBoundsError(
417 "embedded_leaf_license",
418 embedded_leaf_license.len(),
419 ))?
420 .to_vec();
421
422 (ci, ck)
423 }
424 }
425 };
426
427 Ok((
428 KeyId::from_uuid(encrypted_key.1),
429 ContentKey::from(ck.into_boxed_slice()),
430 ContentIntegrityKey::from(ci.into_boxed_slice()),
431 ))
432 }
433
434 fn cipher_data(&self, xml_key: &XmlKey) -> Result<Vec<u8>, crate::Error> {
435 let body_tag = xml_utils::build_cipher_data(
436 BASE64_STANDARD.encode(self.device.certificate_chain().raw()),
437 )?;
438
439 let body = xml_utils::render(&body_tag)?;
440 let ciphertext = aes::encrypt_cbc(xml_key.aes_key(), xml_key.aes_iv(), &body)?;
441
442 Ok([xml_key.aes_iv(), ciphertext.as_slice()].concat())
443 }
444
445 fn key_data(xml_key: &XmlKey) -> Vec<u8> {
446 ecc_p256::encrypt(
447 ecc_p256::wmrm_public_key(),
448 xml_key.public_key().as_element(),
449 )
450 }
451
452 fn client_time() -> String {
453 SystemTime::now()
454 .duration_since(UNIX_EPOCH)
455 .unwrap()
456 .as_secs()
457 .to_string()
458 }
459}