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::{prelude::BASE64_STANDARD, Engine};
17use rand::{thread_rng, Rng};
18use std::{
19 fmt,
20 sync::{atomic::AtomicU32, Arc},
21 time::{SystemTime, UNIX_EPOCH},
22};
23
24const PROTOCOL_VERSION: &str = "1";
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}
149
150#[derive(Debug, Clone)]
152pub struct Session {
153 id: u32,
154 device: Arc<Device>,
155 xml_key: XmlKey,
156}
157
158impl Cdm {
159 pub fn from_device(device: Device) -> Self {
161 let device = Arc::new(device);
162
163 Self { device }
164 }
165
166 pub fn open_session(&self) -> Session {
168 static SESSION_COUNTER: AtomicU32 = AtomicU32::new(0);
169 let id = SESSION_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
170
171 Session::new(id, Arc::clone(&self.device))
172 }
173}
174
175impl Session {
176 fn new(id: u32, device: Arc<Device>) -> Self {
177 let xml_key = XmlKey::new();
178
179 Self {
180 id,
181 device,
182 xml_key,
183 }
184 }
185
186 pub fn id(&self) -> u32 {
188 self.id
189 }
190
191 pub fn get_license_challenge(&self, wrm_header: WrmHeader) -> Result<String, crate::Error> {
198 let nonce = BASE64_STANDARD.encode(thread_rng().gen::<[u8; 16]>());
199 let wmrm_cipher = BASE64_STANDARD.encode(self.key_data());
200 let cert_cipher = BASE64_STANDARD.encode(self.cipher_data()?);
201
202 let la_content_tag = xml_utils::build_digest_content(
203 String::from(PROTOCOL_VERSION),
204 String::from(CLIENT_VERSION),
205 Self::client_time(),
206 wrm_header.into(),
207 nonce,
208 wmrm_cipher,
209 cert_cipher,
210 )?;
211
212 let la_content = xml_utils::render(&la_content_tag)?;
213 let la_hash = BASE64_STANDARD.encode(sha256::hash(&la_content));
214
215 let signed_info_tag = xml_utils::build_signed_info(la_hash)?;
216 let signed_info = xml_utils::render(&signed_info_tag)?;
217
218 let signature = ecc_p256::sign(self.device.signing_key(), &signed_info);
219 let signature = BASE64_STANDARD.encode(signature);
220
221 let public_key = self
222 .device
223 .signing_key()
224 .verifying_key()
225 .as_affine()
226 .to_untagged_bytes();
227 let public_key = BASE64_STANDARD.encode(public_key);
228
229 let challenge_tag = xml_utils::build_license_challenge(
230 la_content_tag,
231 signed_info_tag,
232 signature,
233 public_key,
234 )?;
235
236 let challenge = xml_utils::render(&challenge_tag)?;
237
238 String::from_utf8(challenge).map_err(|e| e.into())
239 }
240
241 pub fn get_keys_from_challenge_response(
243 &self,
244 response: &str,
245 ) -> Result<Vec<KidCk>, crate::Error> {
246 let licenses = xml_utils::parse_challenge_response(response)?;
247 if licenses.is_empty() {
248 return Err(crate::Error::LicenseMissingError);
249 }
250
251 let device_public_key = self
252 .device
253 .encryption_key()
254 .public()
255 .as_element()
256 .to_untagged_bytes();
257
258 let mut decrypted_keys = Vec::<KidCk>::with_capacity(licenses.len());
259
260 for license in licenses {
261 let license = match License::from_b64(license.as_str()) {
262 Ok(license) => license,
263 Err(e) => {
264 log::error!("Failed to create license: {e:?}");
265 continue;
266 }
267 };
268
269 if *license.public_key()? != *device_public_key {
270 return Err(crate::Error::PublicKeyMismatchError("device"));
271 }
272
273 let aux_key = license.auxiliary_key();
274
275 decrypted_keys.extend(license.encrypted_keys().iter().filter_map(|encrypted_key| {
276 let (kid, ck, ci) = self
277 .decrypt_key(encrypted_key, aux_key)
278 .inspect_err(|e| log::error!("Failed to decrypt key: {e:?}"))
279 .ok()?;
280
281 let (msg, signature) = license
282 .cmac_verification_data()
283 .inspect_err(|e| {
284 log::error!(
285 "Failed to get MAC verification data {e:?}. Skipping KID: {kid:?}"
286 )
287 })
288 .ok()?;
289
290 aes::verify_cmac(ci.as_ref(), msg, signature)
291 .inspect_err(|e| log::error!("Signature mismatch {e:?}. Skipping KID: {kid:?}"))
292 .ok()?;
293
294 Some((kid, ck))
295 }));
296 }
297
298 Ok(decrypted_keys)
299 }
300
301 fn decrypt_key(
302 &self,
303 encrypted_key: &(CipherType, &[u8; 16], &[u8]),
304 aux_key: Option<&[u8; 16]>,
305 ) -> Result<KidCkCi, crate::Error> {
306 match encrypted_key.0 {
307 CipherType::Ecc256 | CipherType::Ecc256WithKZ | CipherType::Ecc256ViaSymmetric => (),
308 _ => {
309 return Err(crate::Error::UnsupportedCipherTypeError(encrypted_key.0));
310 }
311 };
312
313 let decrypted = ecc_p256::decrypt(self.device.encryption_key().secret(), encrypted_key.2)?;
314
315 let mut ci = decrypted
316 .get(..16)
317 .ok_or(crate::Error::SliceOutOfBoundsError(
318 "decrypted",
319 decrypted.len(),
320 ))?
321 .to_vec();
322 let mut ck = decrypted
323 .get(16..32)
324 .ok_or(crate::Error::SliceOutOfBoundsError(
325 "decrypted",
326 decrypted.len(),
327 ))?
328 .to_vec();
329
330 if let Some(aux_key) = aux_key {
331 ci = decrypted.iter().copied().step_by(2).take(16).collect();
332 ck = decrypted
333 .iter()
334 .copied()
335 .skip(1)
336 .step_by(2)
337 .take(16)
338 .collect();
339
340 if encrypted_key.0 == CipherType::Ecc256ViaSymmetric {
341 let embedded_root_license =
342 &encrypted_key
343 .2
344 .get(..144)
345 .ok_or(crate::Error::SliceOutOfBoundsError(
346 "encrypted_key",
347 encrypted_key.2.len(),
348 ))?;
349 let embedded_leaf_license =
350 &encrypted_key
351 .2
352 .get(144..)
353 .ok_or(crate::Error::SliceOutOfBoundsError(
354 "encrypted_key",
355 encrypted_key.2.len(),
356 ))?;
357
358 let rgb_key = ck
359 .iter()
360 .zip(RGB_MAGIC_CONSTANT_ZERO)
361 .map(|v| v.0 ^ v.1)
362 .collect::<Vec<_>>();
363
364 let content_key_prime = aes::encrypt_ecb(&ck, &rgb_key)?;
365 let uplink_x_key = aes::encrypt_ecb(&content_key_prime, aux_key)?;
366
367 let secondary_key = aes::encrypt_ecb(
368 &ck,
369 embedded_root_license
370 .get(128..)
371 .ok_or(crate::Error::SliceOutOfBoundsError(
372 "embedded_root_license",
373 embedded_root_license.len(),
374 ))?,
375 )?;
376
377 let embedded_leaf_license = aes::encrypt_ecb(&uplink_x_key, embedded_leaf_license)?;
378 let embedded_leaf_license =
379 aes::encrypt_ecb(&secondary_key, &embedded_leaf_license)?;
380
381 ci = embedded_leaf_license
382 .get(..16)
383 .ok_or(crate::Error::SliceOutOfBoundsError(
384 "embedded_leaf_license",
385 embedded_leaf_license.len(),
386 ))?
387 .to_vec();
388 ck = embedded_leaf_license
389 .get(16..)
390 .ok_or(crate::Error::SliceOutOfBoundsError(
391 "embedded_leaf_license",
392 embedded_leaf_license.len(),
393 ))?
394 .to_vec();
395 }
396 }
397
398 Ok((
399 KeyId::from_uuid(encrypted_key.1),
400 ContentKey::from(ck.into_boxed_slice()),
401 ContentIntegrityKey::from(ci.into_boxed_slice()),
402 ))
403 }
404
405 fn cipher_data(&self) -> Result<Vec<u8>, crate::Error> {
406 let body_tag =
407 xml_utils::build_cipher_data(BASE64_STANDARD.encode(self.device.group_certificate()))?;
408
409 let body = xml_utils::render(&body_tag)?;
410 let ciphertext = aes::encrypt_cbc(self.xml_key.aes_key(), self.xml_key.aes_iv(), &body)?;
411
412 Ok([self.xml_key.aes_iv(), ciphertext.as_slice()].concat())
413 }
414
415 fn key_data(&self) -> Vec<u8> {
416 ecc_p256::encrypt(
417 ecc_p256::wmrm_public_key(),
418 self.xml_key.public_key().as_element(),
419 )
420 }
421
422 fn client_time() -> String {
423 SystemTime::now()
424 .duration_since(UNIX_EPOCH)
425 .unwrap()
426 .as_secs()
427 .to_string()
428 }
429}