blob: 709b24067846ec9100783cd63513f5cacce072cf [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());
16 let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 30, 5)).unwrap();
17 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 Cheng527387f2020-11-03 09:44:55 +080043 use self::jni::sys::{jboolean, jint, jlong, JNI_FALSE, JNI_TRUE};
Tang Cheng88643892020-10-31 22:00:07 +080044 use self::jni::JNIEnv;
45 // use super::*;
46 use libc;
47 use std::slice;
48
Tang Cheng527387f2020-11-03 09:44:55 +080049 use log::debug;
50
Tang Cheng88643892020-10-31 22:00:07 +080051 use dlqrcode::DaliQrCode;
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();
75 let keylen = libc::strlen(s);
76 let mut k = Vec::new();
77 k.extend_from_slice(slice::from_raw_parts(s as *const u8, keylen));
78 k
79 };
80
81 let qrcode = {
82 let s = env
83 .get_string(qrcode)
84 .expect("invalid qrcode string")
85 .as_ptr();
86 let qrlen = libc::strlen(s);
87 let mut q = Vec::new();
88 q.extend_from_slice(slice::from_raw_parts(s as *const u8, qrlen));
89 q
90 };
91
92 let qrdata = env.get_map(result).expect("invalid qrdata map");
93
Tang Cheng527387f2020-11-03 09:44:55 +080094 let (key, step, skew) = {
Tang Cheng8d072502020-10-31 22:02:25 +080095 let mut k = [0u8; 32];
Tang Cheng527387f2020-11-03 09:44:55 +080096 if let Ok(v) = base64::decode_config(key.as_slice(), base64::URL_SAFE) {
97 if v.len() != 35 {
98 put_data(&env, &qrdata, "error", "key format error");
99 return JNI_FALSE;
100 }
101 k.clone_from_slice(&v.as_slice()[..32]);
102 let step = ((v[32] as u64) << 8) | (v[33] as u64);
103 let skew = v[34] as u8;
104 (k, step, skew)
Tang Cheng88643892020-10-31 22:00:07 +0800105 } else {
Tang Cheng8d072502020-10-31 22:02:25 +0800106 put_data(
107 &env,
108 &qrdata,
109 "error",
110 "key must be hex format and 64 characters",
111 );
Tang Cheng88643892020-10-31 22:00:07 +0800112 return JNI_FALSE;
113 }
114 };
115
Tang Cheng527387f2020-11-03 09:44:55 +0800116 debug!("TOTP step <{}> , skew <{}>", step, skew);
117 let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) {
Tang Cheng88643892020-10-31 22:00:07 +0800118 Ok(d) => d,
Tang Cheng8d072502020-10-31 22:02:25 +0800119 Err(e) => {
120 let s = format!("invalid input parameter {:?}", e);
121 put_data(&env, &qrdata, "error", &s);
122 return JNI_FALSE;
123 }
Tang Cheng88643892020-10-31 22:00:07 +0800124 };
125
Tang Cheng527387f2020-11-03 09:44:55 +0800126 match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) {
Tang Cheng88643892020-10-31 22:00:07 +0800127 Ok(d) => {
Tang Cheng527387f2020-11-03 09:44:55 +0800128 put_data(&env, &qrdata, "cardno", &d.cardno);
129 put_data(&env, &qrdata, "cardtype", &d.cardtype);
130 put_data(&env, &qrdata, "uid", &d.uid);
131 let sign = dlqrcode::transaction_sign(&d);
132 put_data(&env, &qrdata, "sign", &sign);
Tang Cheng88643892020-10-31 22:00:07 +0800133 return JNI_TRUE;
134 }
135 Err(e) => {
Tang Cheng8d072502020-10-31 22:02:25 +0800136 let s = format!("{:?}", e);
137 put_data(&env, &qrdata, "error", &s);
Tang Cheng88643892020-10-31 22:00:07 +0800138 return JNI_FALSE;
Tang Cheng8d072502020-10-31 22:02:25 +0800139 }
Tang Cheng88643892020-10-31 22:00:07 +0800140 };
141 }
Tang Cheng527387f2020-11-03 09:44:55 +0800142
143 #[no_mangle]
144 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac(
145 env: JNIEnv,
146 _: JClass,
147 qrsign: JString,
148 cardno: JString,
149 amount: jint,
150 termDatetime: JString,
151 result: JObject,
152 ) -> jboolean {
153 let qrsign = {
154 let s = env.get_string(qrsign).expect("invalid key string").as_ptr();
155 let keylen = libc::strlen(s);
156 String::from_raw_parts(s as *mut u8, keylen, keylen)
157 };
158 let cardno = {
159 let s = env
160 .get_string(cardno)
161 .expect("invalid cardno string")
162 .as_ptr();
163 let len = libc::strlen(s);
164 String::from_raw_parts(s as *mut u8, len, len)
165 };
166
167 let termDatetime = {
168 let s = env
169 .get_string(termDatetime)
170 .expect("invalid datetime")
171 .as_ptr();
172 let len = libc::strlen(s);
173 String::from_raw_parts(s as *mut u8, len, len)
174 };
175
176 let result = env.get_map(result).expect("invalid qrdata map");
177
178 if termDatetime.len() != 14 {
179 put_data(&env, &result, "error", "term datetime must be 14 chars");
180 return JNI_FALSE;
181 }
182
183 match dlqrcode::transaction_tac(&cardno, amount, &termDatetime, &qrsign) {
184 Ok(tac) => {
185 put_data(&env, &result, "tac", &tac);
186 JNI_TRUE
187 }
188 Err(e) => {
189 put_data(&env, &result, "error", &format!("{:?}", e));
190 JNI_FALSE
191 }
192 }
193 }
Tang Cheng88643892020-10-31 22:00:07 +0800194}