rust_rcs_core/security/aka/
mod.rs1extern crate base64;
16
17use base64::{engine::general_purpose, Engine as _};
18use data_encoding::HEXUPPER;
19use libc::{c_int, c_void, size_t};
20
21use crate::ffi::icc::IccChannel;
22
23use crate::ffi::log::platform_log;
24use crate::util::raw_string::{FromRawStr, StrFind};
25
26#[cfg(any(
27 all(feature = "android", target_os = "android"),
28 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
29))]
30const PLATFORM_SUPPORT_DIRECT_AKA: bool = true;
31
32#[cfg(not(any(
33 all(feature = "android", target_os = "android"),
34 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
35)))]
36const PLATFORM_SUPPORT_DIRECT_AKA: bool = false;
37
38const LOG_TAG: &str = "aka";
39
40#[cfg(any(
41 all(feature = "android", target_os = "android"),
42 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
43))]
44extern "C" {
45 fn platform_perform_aka(
46 subscription_id: c_int,
47 in_data: *const c_void,
48 in_size: size_t,
49 out_size: *mut size_t,
50 ) -> *mut c_void;
51}
52
53#[cfg(any(
54 all(feature = "android", target_os = "android"),
55 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
56))]
57fn perform_aka(challenge_data: &[u8], subscription_id: i32) -> Result<Vec<u8>, ErrorKind> {
58 let mut out_size: size_t = 0;
59 let out_data;
60
61 unsafe {
62 out_data = platform_perform_aka(
63 subscription_id,
64 challenge_data.as_ptr() as *const c_void,
65 challenge_data.len(),
66 &mut out_size,
67 );
68
69 if out_size <= 0 || out_data.is_null() {
70 return Err(ErrorKind::FFI);
71 }
72
73 let mut data: Vec<u8> = Vec::with_capacity(out_size);
74
75 std::ptr::copy_nonoverlapping(out_data as *const u8, data.as_mut_ptr(), out_size);
76
77 libc::free(out_data);
78
79 data.set_len(out_size);
80
81 return Ok(data);
82 }
83}
84
85#[cfg(not(any(
86 all(feature = "android", target_os = "android"),
87 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
88)))]
89fn perform_aka(challenge_data: &[u8], subscription_id: i32) -> Result<Vec<u8>, ErrorKind> {
90 Err(ErrorKind::FFI)
91}
92
93pub struct AkaAlgorithm<'a> {
94 pub version: i16,
95 pub algorithm: &'a [u8],
96}
97
98pub trait AsAkaAlgorithm<'a> {
99 type Target;
100 type Err;
101 fn as_aka_algorithm(&'a self) -> Result<Self::Target, Self::Err>;
102}
103
104impl<'a> AsAkaAlgorithm<'a> for [u8] {
105 type Target = AkaAlgorithm<'a>;
106 type Err = ();
107 fn as_aka_algorithm(&'a self) -> Result<AkaAlgorithm<'a>, ()> {
108 let mut iter = self.into_iter();
109
110 if let Some(5) = iter.position(|c| *c == b'-') {
111 if self.start_with(b"AKAv1") {
112 return Ok(AkaAlgorithm {
113 version: 1,
114 algorithm: &self[6..],
115 });
116 }
117 }
118
119 Err(())
120 }
121}
122
123pub struct AkaChallenge {
124 pub rand: [u8; 16],
125 pub autn: [u8; 16],
126}
127
128impl FromRawStr for AkaChallenge {
129 type Err = ();
130 fn from_raw_str(s: &[u8]) -> Result<AkaChallenge, ()> {
131 if let Ok(s) = general_purpose::STANDARD.decode(s) {
132 if s.len() >= 32 {
133 let mut aka_challenge = AkaChallenge {
134 rand: [0; 16],
135 autn: [0; 16],
136 };
137
138 unsafe {
139 std::ptr::copy_nonoverlapping(
140 s[..16].as_ptr(),
141 aka_challenge.rand.as_mut_ptr(),
142 16,
143 );
144 std::ptr::copy_nonoverlapping(
145 s[16..32].as_ptr(),
146 aka_challenge.autn.as_mut_ptr(),
147 16,
148 );
149 }
150
151 return Ok(aka_challenge);
152 }
153 }
154
155 Err(())
156 }
157}
158
159pub enum AkaResponse {
160 Successful(Vec<u8>, Option<(Vec<u8>, Vec<u8>)>),
161 SyncFailure(Vec<u8>),
162}
163
164fn aka_decode_response(data: Vec<u8>) -> Result<AkaResponse, ErrorKind> {
165 if data.len() >= 2 {
166 let tag = data[0];
167 if tag == 0xDB {
168 let res_length = data[1] as usize;
169 platform_log(LOG_TAG, format!("res_length:{}", res_length));
170 if data.len() >= 2 + res_length {
171 let mut res = Vec::with_capacity(res_length);
172 res.extend_from_slice(&data[2..2 + res_length]);
173 platform_log(LOG_TAG, format!("res:{}", &HEXUPPER.encode(&res)));
174 if data.len() > 2 + res_length {
175 let ck_length = data[2 + res_length] as usize;
176 platform_log(LOG_TAG, format!("ck_length:{}", res_length));
177 if data.len() >= 2 + res_length + 1 + ck_length {
178 let mut ck = Vec::with_capacity(ck_length);
179 ck.extend_from_slice(
180 &data[2 + res_length + 1..2 + res_length + 1 + ck_length],
181 );
182 platform_log(LOG_TAG, format!("ck:{}", &HEXUPPER.encode(&ck)));
183 if data.len() > 2 + res_length + 1 + ck_length {
184 let ik_length = data[2 + res_length + 1 + ck_length] as usize;
185 platform_log(LOG_TAG, format!("ik_length:{}", ik_length));
186 if data.len() >= 2 + res_length + 1 + ck_length + 1 + ik_length {
187 let mut ik = Vec::with_capacity(ik_length);
188 ik.extend_from_slice(
189 &data[2 + res_length + 1 + ck_length + 1
190 ..2 + res_length + 1 + ck_length + 1 + ik_length],
191 );
192 platform_log(LOG_TAG, format!("ik:{}", &HEXUPPER.encode(&ik)));
193 return Ok(AkaResponse::Successful(res, Some((ck, ik))));
194 }
195 }
196 }
197 }
198
199 return Ok(AkaResponse::Successful(res, None));
200 }
201 } else if tag == 0xDC {
202 let auts_length = data[1] as usize;
203 platform_log(LOG_TAG, format!("auts_length:{}", auts_length));
204 if data.len() >= 2 + auts_length {
205 let mut auts = Vec::with_capacity(auts_length);
206 auts.extend_from_slice(&data[2..2 + auts_length]);
207 platform_log(LOG_TAG, format!("auts:{}", &HEXUPPER.encode(&auts)));
208 return Ok(AkaResponse::SyncFailure(auts));
209 }
210 }
211 }
212
213 Err(ErrorKind::BadFormat)
214}
215
216pub fn aka_do_challenge(
217 challenge: &AkaChallenge,
218 subscription_id: i32,
219) -> Result<AkaResponse, ErrorKind> {
220 let mut challenge_data: [u8; 34] = [0; 34];
221
222 challenge_data[0] = 16;
223 challenge_data[17] = 16;
224
225 unsafe {
226 std::ptr::copy_nonoverlapping(
227 challenge.rand.as_ptr(),
228 challenge_data[1..17].as_mut_ptr(),
229 16,
230 );
231 std::ptr::copy_nonoverlapping(
232 challenge.autn.as_ptr(),
233 challenge_data[18..].as_mut_ptr(),
234 16,
235 );
236 }
237
238 if PLATFORM_SUPPORT_DIRECT_AKA {
239 if let Ok(data) = perform_aka(&challenge_data, subscription_id) {
240 return aka_decode_response(data);
241 }
242 } else {
243 let aid_bytes: [u8; 7] = [0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x02];
244
245 if let Some(channel) = IccChannel::new(&aid_bytes) {
246 let cla = 0x00;
247 let ins = 0x88;
248 let p1 = 0x00;
249 let p2 = 0x81;
250 let lc = 0x22;
251 let _le = 0x00;
252
253 if let Ok(data) = channel.icc_exchange_apdu(cla, ins, p1, p2, lc, &challenge_data) {
268 return aka_decode_response(data);
269 }
270 }
271 }
272
273 Err(ErrorKind::FFI)
274}
275
276pub enum ErrorKind {
277 BadFormat,
278 FFI,
279 UnknownParameter,
280}