termusiclib/songtag/
encrypt.rsuse anyhow::Result;
use base64::{engine::general_purpose, Engine};
use libaes::Cipher;
use md5::compute;
use num_bigint::BigUint;
use rand::{rngs::OsRng, Rng, RngCore};
use std::convert::TryFrom;
const IV: &[u8] = b"0102030405060708";
const PRESET_KEY: &[u8] = b"0CoJUm6Qyw8W8jud";
const LINUX_API_KEY: &[u8] = b"rFgB&h#%2?^eDg:Q";
const BASE62: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const EAPIKEY: &[u8] = b"e82ckenh8dichen8";
const MODULUS: &[u8] = b"e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7";
const PUBKEY: &[u8] = b"010001";
#[allow(non_snake_case)]
pub struct Crypto;
#[allow(dead_code)]
impl Crypto {
pub fn hex_random_bytes(n: usize) -> String {
let mut data: Vec<u8> = Vec::with_capacity(n);
OsRng.fill_bytes(&mut data);
hex::encode(data)
}
pub fn alpha_lowercase_random_bytes(n: usize) -> String {
const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz0123456789";
let mut rng = rand::thread_rng();
let rand_string: String = (0..n)
.map(|_| {
let idx = rng.gen_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect();
rand_string
}
pub fn eapi(url: &str, text: &str) -> Result<String> {
let message = format!("nobody{url}use{text}md5forencrypt");
let hash = compute(message.as_bytes());
let digest = hex::encode(hash.as_ref());
let data = format!("{url}-36cd479b6b5-{text}-36cd479b6b5-{digest}");
let params = Self::aes_encrypt(&data, EAPIKEY, Some(IV))?;
let params = hex::encode_upper(params);
let p_value = Self::escape(¶ms);
let result = format!("params={p_value}&");
Ok(result)
}
pub fn weapi(text: &str) -> Result<String> {
let mut secret_key = [0_u8; 16];
OsRng.fill_bytes(&mut secret_key);
let key: Vec<u8> = secret_key
.iter()
.map(|i| BASE62[(i % 62) as usize])
.collect();
let params1 = Self::aes_encrypt(text, PRESET_KEY, Some(IV))?;
let params = Self::aes_encrypt(¶ms1, &key, Some(IV))?;
let key_string = key.iter().map(|&c| c as char).collect::<String>();
let enc_sec_key = Self::rsa(&key_string);
let p_value = Self::escape(¶ms);
let enc_value = Self::escape(&enc_sec_key);
Ok(format!("params={p_value}&encSecKey={enc_value}&"))
}
pub fn linuxapi(text: &str) -> Result<String> {
let params = Self::aes_encrypt(text, LINUX_API_KEY, None)?;
let params = hex::encode(params).to_uppercase();
let e_value = Self::escape(¶ms);
Ok(format!("eparams={e_value}&"))
}
pub fn aes_encrypt(data: &str, key: &[u8], iv: Option<&[u8]>) -> Result<String> {
let mut iv_real: Vec<u8> = vec![0_u8; 16];
if let Some(i) = iv {
iv_real = i.to_vec();
}
let key_16 = <&[u8; 16]>::try_from(key)?;
let cipher = Cipher::new_128(key_16);
let encrypted = cipher.cbc_encrypt(&iv_real, data.as_bytes());
Ok(general_purpose::URL_SAFE.encode(encrypted))
}
fn rsa(text: &str) -> String {
let text = text.chars().rev().collect::<String>();
let text = BigUint::parse_bytes(hex::encode(text).as_bytes(), 16).unwrap();
let pubkey = BigUint::parse_bytes(PUBKEY, 16).unwrap();
let modulus = BigUint::parse_bytes(MODULUS, 16).unwrap();
let pow = text.modpow(&pubkey, &modulus);
pow.to_str_radix(16)
}
pub fn encrypt_id(id: &str) -> String {
let magic = b"3go8&$8*3*3h0k(2)2";
let magic_len = magic.len();
let mut song_id = id.to_string().into_bytes();
id.as_bytes().iter().enumerate().for_each(|(i, sid)| {
song_id[i] = *sid ^ magic[i % magic_len];
});
general_purpose::URL_SAFE
.encode(compute(&song_id).as_ref())
.replace('/', "_")
.replace('+', "-")
}
fn escape(str: &str) -> String {
let mut enc = Vec::<u8>::new();
for ch in str.as_bytes() {
if Self::keep_as(*ch) {
enc.push(*ch);
} else {
enc.push(0x25);
let n1 = (*ch >> 4) & 0xf;
let n2 = *ch & 0xf;
enc.push(Self::to_dec_ascii(n1));
enc.push(Self::to_dec_ascii(n2));
}
}
String::from_utf8(enc).unwrap()
}
const fn keep_as(n: u8) -> bool {
n.is_ascii_alphanumeric()
|| n == b'*'
|| n == b'-'
|| n == b'.'
|| n == b'_'
|| n == b'\''
|| n == b'~'
|| n == b'!'
|| n == b'('
|| n == b')'
}
const fn to_dec_ascii(n: u8) -> u8 {
match n {
0 => 48,
1 => 49,
2 => 50,
3 => 51,
4 => 52,
5 => 53,
6 => 54,
7 => 55,
8 => 56,
9 => 57,
10 => b'A',
11 => b'B',
12 => b'C',
13 => b'D',
14 => b'E',
15 => b'F',
_ => 127,
}
}
}