1use crate::crypto::SuiteId;
2use crate::error::{QVError, QVResult};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[repr(u8)]
7pub enum TokenType {
8 Access = 0x01,
9 Refresh = 0x02,
10 Service = 0x03,
11}
12
13impl TokenType {
14 pub fn from_byte(b: u8) -> QVResult<Self> {
15 match b {
16 0x01 => Ok(TokenType::Access),
17 0x02 => Ok(TokenType::Refresh),
18 0x03 => Ok(TokenType::Service),
19 _ => Err(QVError::SerializationError(format!("unknown token type {b:#04x}"))),
20 }
21 }
22 pub fn as_byte(self) -> u8 { self as u8 }
23}
24
25pub const MAGIC: u32 = 0x51564C54;
27pub const VERSION: u16 = 0x0300; #[derive(Debug, Clone)]
31pub struct QVTokenHeader {
32 pub suite: SuiteId,
33 pub token_type: TokenType,
34 pub issued_at: u64, pub ttl: u32, pub nonce: [u8; 32],
37 pub device_fp: [u8; 32],
38 pub mutation_ctr: u64,
39}
40
41#[derive(Debug, Clone)]
57pub struct QVRawToken {
58 pub header: QVTokenHeader,
59 pub encrypted_payload: Vec<u8>,
60 pub signature: Vec<u8>,
61}
62
63impl QVRawToken {
64 pub fn to_bytes(&self) -> Vec<u8> {
66 let h = &self.header;
67 let pl = self.encrypted_payload.len() as u32;
68 let mut buf = Vec::with_capacity(96 + self.encrypted_payload.len() + self.signature.len());
69
70 buf.extend_from_slice(&MAGIC.to_be_bytes());
71 buf.extend_from_slice(&VERSION.to_be_bytes());
72 buf.push(h.suite.as_byte());
73 buf.push(h.token_type.as_byte());
74 buf.extend_from_slice(&h.issued_at.to_be_bytes());
75 buf.extend_from_slice(&h.ttl.to_be_bytes());
76 buf.extend_from_slice(&h.nonce);
77 buf.extend_from_slice(&h.device_fp);
78 buf.extend_from_slice(&pl.to_be_bytes());
79 buf.extend_from_slice(&self.encrypted_payload);
80 buf.extend_from_slice(&h.mutation_ctr.to_be_bytes());
81 buf.extend_from_slice(&self.signature);
82 buf
83 }
84
85 pub fn from_bytes(data: &[u8]) -> QVResult<Self> {
87 macro_rules! need {
88 ($n:expr) => {
89 if data.len() < $n {
90 return Err(QVError::BufferTooShort { need: $n, have: data.len() });
91 }
92 };
93 }
94
95 need!(88);
96
97 let magic = u32::from_be_bytes(data[0..4].try_into().unwrap());
98 if magic != MAGIC {
99 return Err(QVError::InvalidMagic);
100 }
101
102 let version = u16::from_be_bytes(data[4..6].try_into().unwrap());
103 if version != VERSION {
104 return Err(QVError::UnsupportedVersion(version));
105 }
106
107 let suite = SuiteId::from_byte(data[6])?;
108 let token_type = TokenType::from_byte(data[7])?;
109 let issued_at = u64::from_be_bytes(data[8..16].try_into().unwrap());
110 let ttl = u32::from_be_bytes(data[16..20].try_into().unwrap());
111 let nonce: [u8; 32] = data[20..52].try_into().unwrap();
112 let device_fp: [u8; 32] = data[52..84].try_into().unwrap();
113 let pl = u32::from_be_bytes(data[84..88].try_into().unwrap()) as usize;
114
115 need!(88 + pl + 8);
116 let encrypted_payload = data[88..88 + pl].to_vec();
117
118 let mc_off = 88 + pl;
119 let mutation_ctr = u64::from_be_bytes(data[mc_off..mc_off + 8].try_into().unwrap());
120
121 let sig_off = mc_off + 8;
122 need!(sig_off + 1);
123 let signature = data[sig_off..].to_vec();
124
125 Ok(QVRawToken {
126 header: QVTokenHeader { suite, token_type, issued_at, ttl, nonce, device_fp, mutation_ctr },
127 encrypted_payload,
128 signature,
129 })
130 }
131
132 pub fn signed_bytes(&self) -> Vec<u8> {
134 let h = &self.header;
135 let pl = self.encrypted_payload.len() as u32;
136 let mut buf = Vec::new();
137 buf.extend_from_slice(&MAGIC.to_be_bytes());
138 buf.extend_from_slice(&VERSION.to_be_bytes());
139 buf.push(h.suite.as_byte());
140 buf.push(h.token_type.as_byte());
141 buf.extend_from_slice(&h.issued_at.to_be_bytes());
142 buf.extend_from_slice(&h.ttl.to_be_bytes());
143 buf.extend_from_slice(&h.nonce);
144 buf.extend_from_slice(&h.device_fp);
145 buf.extend_from_slice(&pl.to_be_bytes());
146 buf.extend_from_slice(&self.encrypted_payload);
147 buf.extend_from_slice(&h.mutation_ctr.to_be_bytes());
148 buf
149 }
150}