blob: 909632f1687c4951742652687902181f4874b54c [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 Chengb66a4d82020-11-03 11:17:43 +080016 let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 5, 3)).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 Cheng8d072502020-10-31 22:02:25 +080051 fn put_data(env: &JNIEnv, map: &JMap, key: &str, value: &str) {
52 map.put(
53 *env.new_string(key).unwrap(),
54 *env.new_string(value).unwrap(),
55 )
56 .unwrap();
57 }
58
Tang Cheng88643892020-10-31 22:00:07 +080059 #[no_mangle]
60 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_decode(
61 env: JNIEnv,
62 _: JClass,
63 key_hex: JString,
64 qrcode: JString,
65 offset: jlong,
66 result: JObject,
67 ) -> jboolean {
Tang Cheng88643892020-10-31 22:00:07 +080068 let key = {
Tang Cheng8d072502020-10-31 22:02:25 +080069 let s = env
70 .get_string(key_hex)
71 .expect("invalid key string")
72 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +080073 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng8d072502020-10-31 22:02:25 +080074 };
75
76 let qrcode = {
77 let s = env
78 .get_string(qrcode)
79 .expect("invalid qrcode string")
80 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +080081 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng8d072502020-10-31 22:02:25 +080082 };
83
84 let qrdata = env.get_map(result).expect("invalid qrdata map");
85
Tang Cheng527387f2020-11-03 09:44:55 +080086 let (key, step, skew) = {
Tang Cheng8d072502020-10-31 22:02:25 +080087 let mut k = [0u8; 32];
Tang Cheng333dedb2020-11-03 12:27:37 +080088 if let Ok(v) = base64::decode_config(key, base64::URL_SAFE) {
Tang Cheng527387f2020-11-03 09:44:55 +080089 if v.len() != 35 {
90 put_data(&env, &qrdata, "error", "key format error");
91 return JNI_FALSE;
92 }
93 k.clone_from_slice(&v.as_slice()[..32]);
94 let step = ((v[32] as u64) << 8) | (v[33] as u64);
95 let skew = v[34] as u8;
96 (k, step, skew)
Tang Cheng88643892020-10-31 22:00:07 +080097 } else {
Tang Cheng8d072502020-10-31 22:02:25 +080098 put_data(
99 &env,
100 &qrdata,
101 "error",
102 "key must be hex format and 64 characters",
103 );
Tang Cheng88643892020-10-31 22:00:07 +0800104 return JNI_FALSE;
105 }
106 };
107
Tang Cheng527387f2020-11-03 09:44:55 +0800108 debug!("TOTP step <{}> , skew <{}>", step, skew);
109 let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) {
Tang Cheng88643892020-10-31 22:00:07 +0800110 Ok(d) => d,
Tang Cheng8d072502020-10-31 22:02:25 +0800111 Err(e) => {
112 let s = format!("invalid input parameter {:?}", e);
113 put_data(&env, &qrdata, "error", &s);
114 return JNI_FALSE;
115 }
Tang Cheng88643892020-10-31 22:00:07 +0800116 };
117
Tang Cheng333dedb2020-11-03 12:27:37 +0800118
Tang Cheng527387f2020-11-03 09:44:55 +0800119 match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) {
Tang Cheng88643892020-10-31 22:00:07 +0800120 Ok(d) => {
Tang Cheng527387f2020-11-03 09:44:55 +0800121 put_data(&env, &qrdata, "cardno", &d.cardno);
122 put_data(&env, &qrdata, "cardtype", &d.cardtype);
123 put_data(&env, &qrdata, "uid", &d.uid);
124 let sign = dlqrcode::transaction_sign(&d);
125 put_data(&env, &qrdata, "sign", &sign);
Tang Cheng88643892020-10-31 22:00:07 +0800126 return JNI_TRUE;
127 }
128 Err(e) => {
Tang Cheng8d072502020-10-31 22:02:25 +0800129 let s = format!("{:?}", e);
130 put_data(&env, &qrdata, "error", &s);
Tang Cheng88643892020-10-31 22:00:07 +0800131 return JNI_FALSE;
Tang Cheng8d072502020-10-31 22:02:25 +0800132 }
Tang Cheng88643892020-10-31 22:00:07 +0800133 };
134 }
Tang Cheng527387f2020-11-03 09:44:55 +0800135
Tang Cheng0691adc2020-11-03 11:43:58 +0800136 const VERSION: &'static str = env!("CARGO_PKG_VERSION");
137
138 #[no_mangle]
Tang Cheng333dedb2020-11-03 12:27:37 +0800139 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_version(
140 env: JNIEnv,
141 _: JClass,
142 ) -> jstring {
143 let s = env
144 .new_string(String::from(VERSION))
145 .expect("would't get version");
Tang Cheng0691adc2020-11-03 11:43:58 +0800146 s.into_inner()
147 }
148
Tang Cheng527387f2020-11-03 09:44:55 +0800149 #[no_mangle]
150 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac(
151 env: JNIEnv,
152 _: JClass,
153 qrsign: JString,
154 cardno: JString,
155 amount: jint,
156 termDatetime: JString,
157 result: JObject,
158 ) -> jboolean {
159 let qrsign = {
160 let s = env.get_string(qrsign).expect("invalid key string").as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800161 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800162 };
163 let cardno = {
164 let s = env
165 .get_string(cardno)
166 .expect("invalid cardno string")
167 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800168 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800169 };
170
171 let termDatetime = {
172 let s = env
173 .get_string(termDatetime)
174 .expect("invalid datetime")
175 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800176 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800177 };
178
179 let result = env.get_map(result).expect("invalid qrdata map");
180
181 if termDatetime.len() != 14 {
182 put_data(&env, &result, "error", "term datetime must be 14 chars");
183 return JNI_FALSE;
184 }
185
Tang Cheng333dedb2020-11-03 12:27:37 +0800186 match dlqrcode::transaction_tac(
187 &cardno,
188 amount,
189 &termDatetime,
190 &qrsign
191 ) {
Tang Cheng527387f2020-11-03 09:44:55 +0800192 Ok(tac) => {
193 put_data(&env, &result, "tac", &tac);
194 JNI_TRUE
195 }
196 Err(e) => {
197 put_data(&env, &result, "error", &format!("{:?}", e));
198 JNI_FALSE
199 }
200 }
201 }
Tang Cheng88643892020-10-31 22:00:07 +0800202}