From 82e30c020d56c000b2d737bf7a4408087447c19c Mon Sep 17 00:00:00 2001 From: mokurin000 <1348292515a@gmail.com> Date: Wed, 30 Jul 2025 12:18:17 +0800 Subject: [PATCH] feat: implement AuthLite --- Cargo.lock | 2 +- sdgb-api/Cargo.toml | 6 +- sdgb-api/src/auth_lite/mod.rs | 62 +++++++++++++++++++ sdgb-api/src/{title/error/mod.rs => error.rs} | 0 sdgb-api/src/lib.rs | 6 +- sdgb-api/src/title/encryption/mod.rs | 3 +- sdgb-api/src/title/mod.rs | 4 +- 7 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 sdgb-api/src/auth_lite/mod.rs rename sdgb-api/src/{title/error/mod.rs => error.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index ed731e7..5ce5009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1099,9 +1099,9 @@ name = "sdgb-api" version = "0.1.0" dependencies = [ "aes", - "block-padding", "cbc", "chrono", + "cipher", "digest", "flate2", "hmac-sha256", diff --git a/sdgb-api/Cargo.toml b/sdgb-api/Cargo.toml index 31ec8f0..caa6afb 100644 --- a/sdgb-api/Cargo.toml +++ b/sdgb-api/Cargo.toml @@ -9,8 +9,10 @@ license = "GPL-3.0" snafu = { workspace = true } serde_json = { workspace = true } +# hashing digest = "0.10.7" hmac-sha256 = { version = "1.1.12", features = ["digest010", "traits010"] } +md5 = "0.8.0" # other utils chrono = "0.4.41" @@ -22,8 +24,8 @@ nyquest = { version = "0.2.0", features = ["async", "json"] } # (de)serialization serde = { version = "1.0.219", features = ["derive"] } +# compression / encryption flate2 = "1.1.2" cbc = "0.1.2" aes = "0.8.4" -md5 = "0.8.0" -block-padding = "0.3.3" +cipher = { version = "0.4.4", features = ["block-padding"] } diff --git a/sdgb-api/src/auth_lite/mod.rs b/sdgb-api/src/auth_lite/mod.rs new file mode 100644 index 0000000..72dc52e --- /dev/null +++ b/sdgb-api/src/auth_lite/mod.rs @@ -0,0 +1,62 @@ +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_KEY: &[u8; 16] = br#"/?jo+"L&\Cr9(=kG"#; +const AES_IV: &[u8; 16] = b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + +pub async fn delivery_raw( + client: &AsyncClient, + title_ver: impl AsRef, +) -> Result, ApiError> { + let title_ver = title_ver.as_ref(); + let params = format!("title_id=SDGB&title_ver={title_ver}&client_id=A63E01C2805"); + let enc_data = encrypt(params, 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, "SDGB;Windows/Lite") + .with_header("Pragma", "DFI"); + + let mut resp = client.request(req).await?.bytes().await?; + let dec_len = decrypt(&mut resp, AES_KEY, AES_IV)?.len(); + resp.truncate(dec_len); + Ok(resp) +} + +type Aes128CbcEnc = cbc::Encryptor; +type Aes128CbcDec = cbc::Decryptor; + +fn encrypt(data: impl AsRef<[u8]>, key: &[u8; 16], iv: &[u8; 16]) -> Result, ApiError> { + let key = GenericArray::from_slice(key); + let iv = GenericArray::from_slice(iv); + let encryptor = Aes128CbcEnc::new(key, iv); + let data = data.as_ref(); + let bs = aes::Aes256::block_size(); + let pad_len = bs - data.len() % bs; + + let mut buf = vec![0; pad_len + data.len()]; + buf[..data.len()].copy_from_slice(&data); + encryptor.encrypt_padded_mut::(&mut buf, 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::(data.as_mut())?; + Ok(result) +} diff --git a/sdgb-api/src/title/error/mod.rs b/sdgb-api/src/error.rs similarity index 100% rename from sdgb-api/src/title/error/mod.rs rename to sdgb-api/src/error.rs diff --git a/sdgb-api/src/lib.rs b/sdgb-api/src/lib.rs index fda4883..1277dd6 100644 --- a/sdgb-api/src/lib.rs +++ b/sdgb-api/src/lib.rs @@ -1,2 +1,6 @@ -pub mod title; pub mod all_net; +pub mod auth_lite; +pub mod title; + +mod error; +pub use error::ApiError; diff --git a/sdgb-api/src/title/encryption/mod.rs b/sdgb-api/src/title/encryption/mod.rs index d9b39e2..530219c 100644 --- a/sdgb-api/src/title/encryption/mod.rs +++ b/sdgb-api/src/title/encryption/mod.rs @@ -8,7 +8,8 @@ use digest::generic_array::GenericArray; use flate2::write::ZlibEncoder; use flate2::{Compression, read::ZlibDecoder}; -use crate::title::{MaiVersion, MaiVersionExt, Sdgb1_40, Sdgb1_50, error::ApiError}; +use crate::error::ApiError; +use crate::title::{MaiVersion, MaiVersionExt, Sdgb1_40, Sdgb1_50}; impl MaiVersionExt for Sdgb1_40 { fn decode(mut data: impl AsMut<[u8]>) -> Result, ApiError> { diff --git a/sdgb-api/src/title/mod.rs b/sdgb-api/src/title/mod.rs index d965393..eee5efd 100644 --- a/sdgb-api/src/title/mod.rs +++ b/sdgb-api/src/title/mod.rs @@ -6,8 +6,8 @@ pub mod encryption; pub mod methods; pub mod model; -mod error; -pub use error::ApiError; +use super::ApiError; + use nyquest::{ AsyncClient, Body, r#async::Request,