feat: add ekey

This commit is contained in:
鲁树人 2024-09-06 00:51:56 +01:00
parent e92dc08964
commit c4249226a2
2 changed files with 77 additions and 3 deletions

View File

@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2021"
[dependencies]
base64 = "0.22.1"
itertools = "0.13.0"
anyhow = "1.0.86"
thiserror = "1.0.63"
byteorder = "1.5.0"
itertools = "0.13.0"
tc_tea = "0.1.4"
thiserror = "1.0.63"
umc_utils = { path = "../utils" }

73
um_crypto/qmc/src/ekey.rs Normal file
View File

@ -0,0 +1,73 @@
use anyhow::Result;
use itertools::Itertools;
use std::ops::Mul;
use thiserror::Error;
use umc_utils::base64;
/// Base64 encoded prefix: "QQMusic EncV2,Key:"
const EKEY_V2_PREFIX: &[u8; 24] = b"UVFNdXNpYyBFbmNWMixLZXk6";
const EKEY_V2_KEY1: [u8; 16] = [
0x33, 0x38, 0x36, 0x5A, 0x4A, 0x59, 0x21, 0x40, 0x23, 0x2A, 0x24, 0x25, 0x5E, 0x26, 0x29, 0x28,
];
const EKEY_V2_KEY2: [u8; 16] = [
0x2A, 0x2A, 0x23, 0x21, 0x28, 0x23, 0x24, 0x25, 0x26, 0x5E, 0x61, 0x31, 0x63, 0x5A, 0x2C, 0x54,
];
#[derive(Debug, Clone, PartialEq, Error)]
pub enum EKeyDecryptError {
#[error("EKey is too short for decryption")]
EKeyTooShort,
#[error("Error when decrypting ekey v1")]
FailDecryptV1,
#[error("Error when decrypting ekey v2")]
FailDecryptV2,
}
fn make_simple_key<const N: usize>() -> [u8; N] {
let mut result = [0u8; N];
for (i, v) in result.iter_mut().enumerate() {
let i = i as f32;
let value = 106.0 + i * 0.1;
let value = value.tan().abs().mul(100.0);
*v = value as u8;
}
result
}
pub fn decrypt_v1(ekey: &[u8]) -> Result<Box<[u8]>> {
if ekey.len() < 12 {
Err(EKeyDecryptError::EKeyTooShort)?;
}
let ekey = base64::decode(ekey)?;
let (header, cipher) = ekey.split_at(8);
let simple_key = make_simple_key::<8>();
let tea_key = simple_key
.iter()
.zip(header)
.flat_map(|(&simple_part, &header_part)| [simple_part, header_part])
.collect::<Vec<_>>();
let plaintext = tc_tea::decrypt(cipher, tea_key).ok_or(EKeyDecryptError::FailDecryptV1)?;
Ok([header, &plaintext].concat().into())
}
pub fn decrypt_v2(ekey: &[u8]) -> Result<Box<[u8]>> {
let ekey = base64::decode(ekey)?;
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY1).ok_or(EKeyDecryptError::FailDecryptV2)?;
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY2).ok_or(EKeyDecryptError::FailDecryptV2)?;
let ekey = ekey.iter().take_while(|&&b| b != 0).copied().collect_vec();
decrypt_v1(&ekey)
}
pub fn decrypt<T: AsRef<[u8]>>(ekey: T) -> Result<Box<[u8]>> {
let ekey = ekey.as_ref();
match ekey.strip_prefix(EKEY_V2_PREFIX) {
Some(v2_ekey) => decrypt_v2(v2_ekey),
None => decrypt_v1(ekey),
}
}