blob: c8b6cba4aad63177001a064e59e77c271e4274dd [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 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 Cheng527387f2020-11-03 09:44:55 +0800118 match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) {
Tang Cheng88643892020-10-31 22:00:07 +0800119 Ok(d) => {
Tang Cheng527387f2020-11-03 09:44:55 +0800120 put_data(&env, &qrdata, "cardno", &d.cardno);
121 put_data(&env, &qrdata, "cardtype", &d.cardtype);
122 put_data(&env, &qrdata, "uid", &d.uid);
123 let sign = dlqrcode::transaction_sign(&d);
124 put_data(&env, &qrdata, "sign", &sign);
Tang Cheng88643892020-10-31 22:00:07 +0800125 return JNI_TRUE;
126 }
127 Err(e) => {
Tang Cheng8d072502020-10-31 22:02:25 +0800128 let s = format!("{:?}", e);
129 put_data(&env, &qrdata, "error", &s);
Tang Cheng88643892020-10-31 22:00:07 +0800130 return JNI_FALSE;
Tang Cheng8d072502020-10-31 22:02:25 +0800131 }
Tang Cheng88643892020-10-31 22:00:07 +0800132 };
133 }
Tang Cheng527387f2020-11-03 09:44:55 +0800134
Tang Cheng0691adc2020-11-03 11:43:58 +0800135 const VERSION: &'static str = env!("CARGO_PKG_VERSION");
136
137 #[no_mangle]
Tang Cheng333dedb2020-11-03 12:27:37 +0800138 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_version(
139 env: JNIEnv,
140 _: JClass,
141 ) -> jstring {
142 let s = env
143 .new_string(String::from(VERSION))
144 .expect("would't get version");
Tang Cheng0691adc2020-11-03 11:43:58 +0800145 s.into_inner()
146 }
147
Tang Cheng527387f2020-11-03 09:44:55 +0800148 #[no_mangle]
149 pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac(
150 env: JNIEnv,
151 _: JClass,
152 qrsign: JString,
153 cardno: JString,
154 amount: jint,
155 termDatetime: JString,
156 result: JObject,
157 ) -> jboolean {
158 let qrsign = {
159 let s = env.get_string(qrsign).expect("invalid key string").as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800160 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800161 };
162 let cardno = {
163 let s = env
164 .get_string(cardno)
165 .expect("invalid cardno string")
166 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800167 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800168 };
169
170 let termDatetime = {
171 let s = env
172 .get_string(termDatetime)
173 .expect("invalid datetime")
174 .as_ptr();
Tang Cheng333dedb2020-11-03 12:27:37 +0800175 String::from(CStr::from_ptr(s).to_string_lossy())
Tang Cheng527387f2020-11-03 09:44:55 +0800176 };
177
178 let result = env.get_map(result).expect("invalid qrdata map");
179
180 if termDatetime.len() != 14 {
181 put_data(&env, &result, "error", "term datetime must be 14 chars");
182 return JNI_FALSE;
183 }
184
Tang Cheng065db892020-11-03 13:24:46 +0800185 match dlqrcode::transaction_tac(&cardno, amount, &termDatetime, &qrsign) {
Tang Cheng527387f2020-11-03 09:44:55 +0800186 Ok(tac) => {
187 put_data(&env, &result, "tac", &tac);
188 JNI_TRUE
189 }
190 Err(e) => {
191 put_data(&env, &result, "error", &format!("{:?}", e));
192 JNI_FALSE
193 }
194 }
195 }
Tang Cheng88643892020-10-31 22:00:07 +0800196}