use crypto::md5::Md5;
use crypto::digest::Digest;
use std::time::SystemTime;
pub struct Md5mix<'a>{
sign_str: &'a str,
}
impl<'a> Md5mix<'a> {
pub fn new(s: &'a str) -> Md5mix {
Self { sign_str: s }
}
pub fn decode(&self, s: &str) -> Result<i32, String> {
let string = s.replace("-", "+").replace("_", "/").replace(".", "=");
let ckey_length = 4;
let ( keya, _keyb) = self.create_key();
let keyc = &string[..ckey_length];
let mut hasher = Md5::new();
let keyacstr = format!("{}{}", keya, keyc);
hasher.input_str(&keyacstr);
let keyac = hasher.result_str();
let cryptkey = format!("{}{}", &keya, &keyac);
let string = match base64::decode(&string[ckey_length..]){
Ok(s) => s,
Err(e) => {
return Err(format!("base64.decode err:{:?}", e))
}
};
let buf = Self::mix(&cryptkey, &string);
let result = match std::str::from_utf8(&buf){
Ok(s) => s,
Err(e) => {
return Err(format!("from_utf8 err:{:?}", e))
}
};
let number = &result[26..];
match number.parse(){
Ok(s) => Ok(s),
Err(e) => Err(format!("number parse err:{:?}", e)),
}
}
fn mix(cryptkey: &str, string: &[u8]) -> Vec<u8>{
let key_length = cryptkey.len();
let mut randkey: Vec<i32> = Vec::new();
for i in 0..256 {
let index = i % key_length;
let chars = &cryptkey[index..index+1];
let ascii = chars.as_bytes();
let ascii = ascii.to_ascii_lowercase();
randkey.push(ascii[0] as i32);
}
let mut box_vec: Vec<i32> = Vec::new();
for i in 0..256 {
box_vec.push(i);
}
let mut j: i32 = 0;
for i in 0..256 {
j = (j + box_vec[i] + randkey[i]) % 256;
let tmp = box_vec[i];
box_vec[i] = box_vec[j as usize];
box_vec[j as usize] = tmp;
}
let mut a = 0;
let mut j = 0;
let mut buf: Vec<u8> = vec![];
for &item in string.into_iter(){
a = (a + 1) % 256;
j = (j + box_vec[a]) %256;
let tmp = box_vec[a];
box_vec[a] = box_vec[j as usize];
box_vec[j as usize] = tmp;
let stringord = item as i32;
let b = (box_vec[a] + box_vec[j as usize]) % 256;
let chr_num = stringord ^ box_vec[b as usize];
buf.push(chr_num as u8);
};
buf
}
fn create_key(&self) -> (String, String) {
let mut hasher = Md5::new();
hasher.input_str(self.sign_str);
let key = hasher.result_str();
let mut hasher = Md5::new();
hasher.input_str(&key[..16]);
let keya = hasher.result_str();
let mut hasher = Md5::new();
hasher.input_str(&key[16..]);
let keyb = hasher.result_str();
(keya, keyb)
}
pub fn encode(&self, id: i32) -> Result<String, String> {
let ckey_length = 4;
let (keya, keyb) = self.create_key();
let mut hasher = Md5::new();
let now = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH){
Ok(s) => s,
Err(e) => {
let err = format!("SystemTime::now() err {:?}", e);
return Err(err);
}
};
hasher.input_str(&now.as_secs().to_string());
let keyc = hasher.result_str();
let keyc = &keyc[..];
let keycstart = keyc.len() - ckey_length;
let keyc = &keyc[keycstart..];
let mut hasher = Md5::new();
let keyacstr = format!("{}{}", keya, keyc);
hasher.input_str(&keyacstr);
let keyac = hasher.result_str();
let cryptkey = format!("{}{}", &keya, &keyac);
let mut hasher = Md5::new();
let string = format!("{}{}", id, keyb);
hasher.input_str(&string);
let string = hasher.result_str();
let string: &str = &string[..];
let string = format!("0000000000{}{}", &string[0..16], id);
let buf = Self::mix(&cryptkey, &string.as_bytes());
let bs = &base64::encode(buf);
let rs = bs.replace("=", "");
let rs = format!("{}{}", keyc, rs);
let rs = rs.replace("+", "-").replace("/", "_").replace("=", ".");
Ok(rs)
}
}