| extern crate base64; |
| extern crate hex; |
| |
| #[cfg(test)] |
| mod tests { |
| #[test] |
| fn it_works() { |
| assert_eq!(2 + 2, 4); |
| } |
| |
| #[test] |
| fn test_key() { |
| let key = "wDp3/3NPEi+R0peokVv010GkDk1mRTp3tUB/lCEVRAA="; |
| let key_buffer = base64::decode_config(key, base64::STANDARD).unwrap(); |
| let s = hex::encode(key_buffer.as_slice()); |
| let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 5, 3)).unwrap(); |
| println!( |
| "key : {}", |
| base64::encode_config(key_string, base64::URL_SAFE) |
| ); |
| } |
| } |
| |
| // use std::ffi::{CStr, CString}; |
| // use std::os::raw::{c_char, c_uchar, c_ulong}; |
| |
| // #[no_mangle] |
| // pub extern "C" fn dlsmk_decode( |
| // key: *const c_uchar, |
| // qrcode: *const c_uchar, |
| // qrlen: c_ulong, |
| // ) -> *mut c_char { |
| // CString::new("Hello ".to_owned()).unwrap().into_raw() |
| // } |
| |
| #[cfg(any(target_family = "unix", target_os = "android"))] |
| #[allow(non_snake_case)] |
| pub mod android { |
| extern crate base64; |
| extern crate jni; |
| |
| use self::jni::objects::{JClass, JMap, JObject, JString}; |
| use self::jni::sys::{jboolean, jint, jlong, jstring, JNI_FALSE, JNI_TRUE}; |
| use self::jni::JNIEnv; |
| use std::ffi::CStr; |
| |
| use log::debug; |
| |
| use dlqrcode::DaliQrCode; |
| |
| fn put_data(env: &JNIEnv, map: &JMap, key: &str, value: &str) { |
| map.put( |
| *env.new_string(key).unwrap(), |
| *env.new_string(value).unwrap(), |
| ) |
| .unwrap(); |
| } |
| |
| #[no_mangle] |
| pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_decode( |
| env: JNIEnv, |
| _: JClass, |
| key_hex: JString, |
| qrcode: JString, |
| offset: jlong, |
| result: JObject, |
| ) -> jboolean { |
| let key = { |
| let s = env |
| .get_string(key_hex) |
| .expect("invalid key string") |
| .as_ptr(); |
| String::from(CStr::from_ptr(s).to_string_lossy()) |
| }; |
| |
| let qrcode = { |
| let s = env |
| .get_string(qrcode) |
| .expect("invalid qrcode string") |
| .as_ptr(); |
| String::from(CStr::from_ptr(s).to_string_lossy()) |
| }; |
| |
| let qrdata = env.get_map(result).expect("invalid qrdata map"); |
| |
| let (key, step, skew) = { |
| let mut k = [0u8; 32]; |
| if let Ok(v) = base64::decode_config(key, base64::URL_SAFE) { |
| if v.len() != 35 { |
| put_data(&env, &qrdata, "error", "key format error"); |
| return JNI_FALSE; |
| } |
| k.clone_from_slice(&v.as_slice()[..32]); |
| let step = ((v[32] as u64) << 8) | (v[33] as u64); |
| let skew = v[34] as u8; |
| (k, step, skew) |
| } else { |
| put_data( |
| &env, |
| &qrdata, |
| "error", |
| "key must be hex format and 64 characters", |
| ); |
| return JNI_FALSE; |
| } |
| }; |
| |
| debug!("TOTP step <{}> , skew <{}>", step, skew); |
| let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) { |
| Ok(d) => d, |
| Err(e) => { |
| let s = format!("invalid input parameter {:?}", e); |
| put_data(&env, &qrdata, "error", &s); |
| return JNI_FALSE; |
| } |
| }; |
| |
| |
| match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) { |
| Ok(d) => { |
| put_data(&env, &qrdata, "cardno", &d.cardno); |
| put_data(&env, &qrdata, "cardtype", &d.cardtype); |
| put_data(&env, &qrdata, "uid", &d.uid); |
| let sign = dlqrcode::transaction_sign(&d); |
| put_data(&env, &qrdata, "sign", &sign); |
| return JNI_TRUE; |
| } |
| Err(e) => { |
| let s = format!("{:?}", e); |
| put_data(&env, &qrdata, "error", &s); |
| return JNI_FALSE; |
| } |
| }; |
| } |
| |
| const VERSION: &'static str = env!("CARGO_PKG_VERSION"); |
| |
| #[no_mangle] |
| pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_version( |
| env: JNIEnv, |
| _: JClass, |
| ) -> jstring { |
| let s = env |
| .new_string(String::from(VERSION)) |
| .expect("would't get version"); |
| s.into_inner() |
| } |
| |
| #[no_mangle] |
| pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac( |
| env: JNIEnv, |
| _: JClass, |
| qrsign: JString, |
| cardno: JString, |
| amount: jint, |
| termDatetime: JString, |
| result: JObject, |
| ) -> jboolean { |
| let qrsign = { |
| let s = env.get_string(qrsign).expect("invalid key string").as_ptr(); |
| String::from(CStr::from_ptr(s).to_string_lossy()) |
| }; |
| let cardno = { |
| let s = env |
| .get_string(cardno) |
| .expect("invalid cardno string") |
| .as_ptr(); |
| String::from(CStr::from_ptr(s).to_string_lossy()) |
| }; |
| |
| let termDatetime = { |
| let s = env |
| .get_string(termDatetime) |
| .expect("invalid datetime") |
| .as_ptr(); |
| String::from(CStr::from_ptr(s).to_string_lossy()) |
| }; |
| |
| let result = env.get_map(result).expect("invalid qrdata map"); |
| |
| if termDatetime.len() != 14 { |
| put_data(&env, &result, "error", "term datetime must be 14 chars"); |
| return JNI_FALSE; |
| } |
| |
| match dlqrcode::transaction_tac( |
| &cardno, |
| amount, |
| &termDatetime, |
| &qrsign |
| ) { |
| Ok(tac) => { |
| put_data(&env, &result, "tac", &tac); |
| JNI_TRUE |
| } |
| Err(e) => { |
| put_data(&env, &result, "error", &format!("{:?}", e)); |
| JNI_FALSE |
| } |
| } |
| } |
| } |