Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 1 | extern crate base64; |
| 2 | extern crate hex; |
| 3 | |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 4 | #[cfg(test)] |
| 5 | mod tests { |
| 6 | #[test] |
| 7 | fn it_works() { |
| 8 | assert_eq!(2 + 2, 4); |
| 9 | } |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 10 | |
| 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 Cheng | b66a4d8 | 2020-11-03 11:17:43 +0800 | [diff] [blame^] | 16 | let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 5, 3)).unwrap(); |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 17 | println!( |
| 18 | "key : {}", |
| 19 | base64::encode_config(key_string, base64::URL_SAFE) |
| 20 | ); |
| 21 | } |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 22 | } |
| 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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 36 | #[cfg(any(target_family = "unix", target_os = "android"))] |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 37 | #[allow(non_snake_case)] |
| 38 | pub mod android { |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 39 | extern crate base64; |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 40 | extern crate jni; |
| 41 | |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 42 | use self::jni::objects::{JClass, JMap, JObject, JString}; |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 43 | use self::jni::sys::{jboolean, jint, jlong, JNI_FALSE, JNI_TRUE}; |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 44 | use self::jni::JNIEnv; |
| 45 | // use super::*; |
| 46 | use libc; |
| 47 | use std::slice; |
| 48 | |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 49 | use log::debug; |
| 50 | |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 51 | use dlqrcode::DaliQrCode; |
| 52 | |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 53 | 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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 61 | #[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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 70 | let key = { |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 71 | 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 Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 94 | let (key, step, skew) = { |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 95 | let mut k = [0u8; 32]; |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 96 | 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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 105 | } else { |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 106 | put_data( |
| 107 | &env, |
| 108 | &qrdata, |
| 109 | "error", |
| 110 | "key must be hex format and 64 characters", |
| 111 | ); |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 112 | return JNI_FALSE; |
| 113 | } |
| 114 | }; |
| 115 | |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 116 | debug!("TOTP step <{}> , skew <{}>", step, skew); |
| 117 | let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) { |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 118 | Ok(d) => d, |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 119 | Err(e) => { |
| 120 | let s = format!("invalid input parameter {:?}", e); |
| 121 | put_data(&env, &qrdata, "error", &s); |
| 122 | return JNI_FALSE; |
| 123 | } |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 124 | }; |
| 125 | |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 126 | match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) { |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 127 | Ok(d) => { |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 128 | 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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 133 | return JNI_TRUE; |
| 134 | } |
| 135 | Err(e) => { |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 136 | let s = format!("{:?}", e); |
| 137 | put_data(&env, &qrdata, "error", &s); |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 138 | return JNI_FALSE; |
Tang Cheng | 8d07250 | 2020-10-31 22:02:25 +0800 | [diff] [blame] | 139 | } |
Tang Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 140 | }; |
| 141 | } |
Tang Cheng | 527387f | 2020-11-03 09:44:55 +0800 | [diff] [blame] | 142 | |
| 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 Cheng | 8864389 | 2020-10-31 22:00:07 +0800 | [diff] [blame] | 194 | } |