blob: 909632f1687c4951742652687902181f4874b54c [file] [log] [blame]
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
}
}
}
}