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