92 lines
2.6 KiB
Rust
92 lines
2.6 KiB
Rust
use cipher::{
|
|
BlockDecryptMut as _, BlockEncryptMut as _, BlockSizeUser as _, KeyIvInit as _,
|
|
block_padding::Pkcs7, generic_array::GenericArray,
|
|
};
|
|
use nyquest::{
|
|
AsyncClient,
|
|
r#async::{Body, Request},
|
|
header::USER_AGENT,
|
|
};
|
|
|
|
use crate::error::ApiError;
|
|
|
|
const AES_IV: &[u8; 16] = b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
|
|
|
pub trait Delivery {
|
|
const AES_KEY: &[u8; 16];
|
|
const TITLE_ID: &str;
|
|
const USER_AGENT: &str;
|
|
}
|
|
|
|
/// only for fun
|
|
pub struct SDHJ;
|
|
pub struct SDGB;
|
|
|
|
impl Delivery for SDHJ {
|
|
const AES_KEY: &[u8; 16] = b"-a57UX4y9/h(ImAQ";
|
|
const TITLE_ID: &str = "SDHJ";
|
|
const USER_AGENT: &str = "SDHJ;Windows/Lite";
|
|
}
|
|
|
|
impl Delivery for SDGB {
|
|
const AES_KEY: &[u8; 16] = br#"/?jo+"L&\Cr9(=kG"#;
|
|
const TITLE_ID: &str = "SDGB";
|
|
const USER_AGENT: &str = "SDGB;Windows/Lite";
|
|
}
|
|
|
|
pub async fn delivery_raw<D>(
|
|
client: &AsyncClient,
|
|
title_ver: impl AsRef<str>,
|
|
) -> Result<Vec<u8>, ApiError>
|
|
where
|
|
D: Delivery,
|
|
{
|
|
let title_ver = title_ver.as_ref();
|
|
let params = format!(
|
|
"title_id={}&title_ver={title_ver}&client_id=A63E01C2805",
|
|
D::TITLE_ID
|
|
);
|
|
let enc_data = encrypt(params, D::AES_KEY, AES_IV)?;
|
|
|
|
let req = Request::post("http://at.sys-allnet.cn/net/delivery/instruction")
|
|
.with_body(Body::bytes(enc_data, "application/xxx-form-urlencoded"))
|
|
.with_header(USER_AGENT, D::USER_AGENT)
|
|
.with_header("Pragma", "DFI");
|
|
|
|
let mut resp = client.request(req).await?.bytes().await?;
|
|
let dec_len = decrypt(&mut resp, D::AES_KEY, AES_IV)?.len();
|
|
Ok(resp[16..dec_len].to_vec())
|
|
}
|
|
|
|
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
|
|
type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
|
|
|
|
fn encrypt(data: impl AsRef<[u8]>, key: &[u8; 16], iv: &[u8; 16]) -> Result<Vec<u8>, ApiError> {
|
|
let mut headed_data = vec![0u8; 16];
|
|
headed_data.extend_from_slice(data.as_ref());
|
|
|
|
let key = GenericArray::from_slice(key);
|
|
let iv = GenericArray::from_slice(iv);
|
|
let encryptor = Aes128CbcEnc::new(key, iv);
|
|
|
|
let bs = aes::Aes128::block_size();
|
|
let pad_len = bs - headed_data.len() % bs;
|
|
|
|
let mut buf = vec![0; pad_len + headed_data.len()];
|
|
buf[..headed_data.len()].copy_from_slice(&headed_data);
|
|
encryptor.encrypt_padded_mut::<Pkcs7>(&mut buf, headed_data.len())?;
|
|
Ok(buf)
|
|
}
|
|
|
|
fn decrypt<'ct>(
|
|
data: &'ct mut impl AsMut<[u8]>,
|
|
key: &[u8; 16],
|
|
iv: &[u8; 16],
|
|
) -> Result<&'ct [u8], ApiError> {
|
|
let key = GenericArray::from_slice(key);
|
|
let iv = GenericArray::from_slice(iv);
|
|
let decryptor = Aes128CbcDec::new(key, iv);
|
|
let result = decryptor.decrypt_padded_mut::<Pkcs7>(data.as_mut())?;
|
|
Ok(result)
|
|
}
|