blob: 9a0c320c2d3bd94eac1fc70bbab6fa24a24b5208 [file] [log] [blame]
Tang Cheng527387f2020-11-03 09:44:55 +08001extern crate base64;
2extern crate hex;
3
Tang Cheng88643892020-10-31 22:00:07 +08004#[cfg(test)]
5mod tests {
6 #[test]
7 fn it_works() {
8 assert_eq!(2 + 2, 4);
9 }
Tang Cheng527387f2020-11-03 09:44:55 +080010
11 #[test]
12 fn test_key() {
13 let key = "wDp3/3NPEi+R0peokVv010GkDk1mRTp3tUB/lCEVRAA=";
14 let key_buffer = base64::decode_config(key, base64::STANDARD).unwrap();
15 let s = hex::encode(key_buffer.as_slice());
Tang Cheng065db892020-11-03 13:24:46 +080016 let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 5, 10)).unwrap();
Tang Cheng527387f2020-11-03 09:44:55 +080017 println!(
18 "key : {}",
19 base64::encode_config(key_string, base64::URL_SAFE)
20 );
21 }
Tang Cheng88643892020-10-31 22:00:07 +080022}
23
24// use std::ffi::{CStr, CString};
25// use std::os::raw::{c_char, c_uchar, c_ulong};
26
27// #[no_mangle]
28// pub extern "C" fn dlsmk_decode(
29// key: *const c_uchar,
30// qrcode: *const c_uchar,
31// qrlen: c_ulong,
32// ) -> *mut c_char {
33// CString::new("Hello ".to_owned()).unwrap().into_raw()
34// }
35
Tang Cheng88643892020-10-31 22:00:07 +080036#[cfg(any(target_family = "unix", target_os = "android"))]
Tang Cheng88643892020-10-31 22:00:07 +080037#[allow(non_snake_case)]
38pub mod android {
Tang Cheng527387f2020-11-03 09:44:55 +080039 extern crate base64;
Tang Cheng88643892020-10-31 22:00:07 +080040 extern crate jni;
41
Tang Cheng8d072502020-10-31 22:02:25 +080042 use self::jni::objects::{JClass, JMap, JObject, JString};
Tang Cheng0691adc2020-11-03 11:43:58 +080043 use self::jni::sys::{jboolean, jint, jlong, jstring, JNI_FALSE, JNI_TRUE};
Tang Cheng88643892020-10-31 22:00:07 +080044 use self::jni::JNIEnv;
Tang Cheng333dedb2020-11-03 12:27:37 +080045 use std::ffi::CStr;
Tang Cheng88643892020-10-31 22:00:07 +080046
Tang Cheng527387f2020-11-03 09:44:55 +080047 use log::debug;
48
Tang Cheng88643892020-10-31 22:00:07 +080049 use dlqrcode::DaliQrCode;
50
Tang Chengdf5861b2020-11-05 09:54:23 +080051 static QR_PREFIX : &str = "DLSMK_";
52
Tang Cheng8d072502020-10-31 22:02:25 +080053 fn put_data(env: &JNIEnv, map: &JMap, key: &str, value: &str) {
54 map.put(
55 *env.new_string(key).unwrap(),
56 *env.new_string(value).unwrap(),
57 )
58 .unwrap();
59 }
60
Tang Cheng88643892020-10-31 22:00:07 +080061 #[no_mangle]
62 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_decode(
63 env: JNIEnv,
64 _: JClass,
65 key_hex: JString,
66 qrcode: JString,
67 offset: jlong,
68 result: JObject,
69 ) -> jboolean {
Tang Cheng88643892020-10-31 22:00:07 +080070 let key = {
Tang Cheng8d072502020-10-31 22:02:25 +080071 let s = env
72 .get_string(key_hex)
73 .expect("invalid key string")
74 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +080075 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng8d072502020-10-31 22:02:25 +080076 };
77
78 let qrcode = {
79 let s = env
80 .get_string(qrcode)
81 .expect("invalid qrcode string")
82 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +080083 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng8d072502020-10-31 22:02:25 +080084 };
85
86 let qrdata = env.get_map(result).expect("invalid qrdata map");
87
Tang Cheng527387f2020-11-03 09:44:55 +080088 let (key, step, skew) = {
Tang Cheng8d072502020-10-31 22:02:25 +080089 let mut k = [0u8; 32];
Tang Cheng333dedb2020-11-03 12:27:37 +080090 if let Ok(v) = base64::decode_config(key, base64::URL_SAFE) {
Tang Cheng527387f2020-11-03 09:44:55 +080091 if v.len() != 35 {
92 put_data(&env, &qrdata, "error", "key format error");
93 return JNI_FALSE;
94 }
95 k.clone_from_slice(&v.as_slice()[..32]);
96 let step = ((v[32] as u64) << 8) | (v[33] as u64);
97 let skew = v[34] as u8;
98 (k, step, skew)
Tang Cheng88643892020-10-31 22:00:07 +080099 } else {
Tang Cheng8d072502020-10-31 22:02:25 +0800100 put_data(
101 &env,
102 &qrdata,
103 "error",
104 "key must be hex format and 64 characters",
105 );
Tang Cheng88643892020-10-31 22:00:07 +0800106 return JNI_FALSE;
107 }
108 };
109
Tang Chengdf5861b2020-11-05 09:54:23 +0800110 if !qrcode.starts_with(QR_PREFIX) {
111 put_data(&env, &qrdata, "error", "qrcode prefix error");
112 return JNI_FALSE;
113 }
114 let qrcode = match qrcode.strip_prefix(QR_PREFIX) {
115 Some(q) => String::from(q),
116 None => {
117 put_data(&env, &qrdata, "error", "qrcode prefix error");
118 return JNI_FALSE;
119 }
120 };
121
Tang Cheng527387f2020-11-03 09:44:55 +0800122 debug!("TOTP step <{}> , skew <{}>", step, skew);
123 let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) {
Tang Cheng88643892020-10-31 22:00:07 +0800124 Ok(d) => d,
Tang Cheng8d072502020-10-31 22:02:25 +0800125 Err(e) => {
126 let s = format!("invalid input parameter {:?}", e);
127 put_data(&env, &qrdata, "error", &s);
128 return JNI_FALSE;
129 }
Tang Cheng88643892020-10-31 22:00:07 +0800130 };
131
Tang Cheng527387f2020-11-03 09:44:55 +0800132 match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) {
Tang Cheng88643892020-10-31 22:00:07 +0800133 Ok(d) => {
Tang Cheng527387f2020-11-03 09:44:55 +0800134 put_data(&env, &qrdata, "cardno", &d.cardno);
135 put_data(&env, &qrdata, "cardtype", &d.cardtype);
136 put_data(&env, &qrdata, "uid", &d.uid);
137 let sign = dlqrcode::transaction_sign(&d);
138 put_data(&env, &qrdata, "sign", &sign);
Tang Cheng88643892020-10-31 22:00:07 +0800139 return JNI_TRUE;
140 }
141 Err(e) => {
Tang Cheng8d072502020-10-31 22:02:25 +0800142 let s = format!("{:?}", e);
143 put_data(&env, &qrdata, "error", &s);
Tang Cheng88643892020-10-31 22:00:07 +0800144 return JNI_FALSE;
Tang Cheng8d072502020-10-31 22:02:25 +0800145 }
Tang Cheng88643892020-10-31 22:00:07 +0800146 };
147 }
Tang Cheng527387f2020-11-03 09:44:55 +0800148
Tang Cheng0691adc2020-11-03 11:43:58 +0800149 const VERSION: &'static str = env!("CARGO_PKG_VERSION");
150
151 #[no_mangle]
Tang Cheng333dedb2020-11-03 12:27:37 +0800152 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_version(
153 env: JNIEnv,
154 _: JClass,
155 ) -> jstring {
156 let s = env
157 .new_string(String::from(VERSION))
158 .expect("would't get version");
Tang Cheng0691adc2020-11-03 11:43:58 +0800159 s.into_inner()
160 }
161
Tang Cheng527387f2020-11-03 09:44:55 +0800162 #[no_mangle]
163 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac(
164 env: JNIEnv,
165 _: JClass,
166 qrsign: JString,
167 cardno: JString,
168 amount: jint,
169 termDatetime: JString,
170 result: JObject,
171 ) -> jboolean {
172 let qrsign = {
173 let s = env.get_string(qrsign).expect("invalid key string").as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800174 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800175 };
176 let cardno = {
177 let s = env
178 .get_string(cardno)
179 .expect("invalid cardno string")
180 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800181 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800182 };
183
184 let termDatetime = {
185 let s = env
186 .get_string(termDatetime)
187 .expect("invalid datetime")
188 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800189 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800190 };
191
192 let result = env.get_map(result).expect("invalid qrdata map");
193
194 if termDatetime.len() != 14 {
195 put_data(&env, &result, "error", "term datetime must be 14 chars");
196 return JNI_FALSE;
197 }
198
Tang Cheng065db892020-11-03 13:24:46 +0800199 match dlqrcode::transaction_tac(&cardno, amount, &termDatetime, &qrsign) {
Tang Cheng527387f2020-11-03 09:44:55 +0800200 Ok(tac) => {
201 put_data(&env, &result, "tac", &tac);
202 JNI_TRUE
203 }
204 Err(e) => {
205 put_data(&env, &result, "error", &format!("{:?}", e));
206 JNI_FALSE
207 }
208 }
209 }
Tang Cheng88643892020-10-31 22:00:07 +0800210}