feat: implement AuthLite
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1099,9 +1099,9 @@ name = "sdgb-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"block-padding",
|
|
||||||
"cbc",
|
"cbc",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"cipher",
|
||||||
"digest",
|
"digest",
|
||||||
"flate2",
|
"flate2",
|
||||||
"hmac-sha256",
|
"hmac-sha256",
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ license = "GPL-3.0"
|
|||||||
snafu = { workspace = true }
|
snafu = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|
||||||
|
# hashing
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
hmac-sha256 = { version = "1.1.12", features = ["digest010", "traits010"] }
|
hmac-sha256 = { version = "1.1.12", features = ["digest010", "traits010"] }
|
||||||
|
md5 = "0.8.0"
|
||||||
|
|
||||||
# other utils
|
# other utils
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
@@ -22,8 +24,8 @@ nyquest = { version = "0.2.0", features = ["async", "json"] }
|
|||||||
# (de)serialization
|
# (de)serialization
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
|
|
||||||
|
# compression / encryption
|
||||||
flate2 = "1.1.2"
|
flate2 = "1.1.2"
|
||||||
cbc = "0.1.2"
|
cbc = "0.1.2"
|
||||||
aes = "0.8.4"
|
aes = "0.8.4"
|
||||||
md5 = "0.8.0"
|
cipher = { version = "0.4.4", features = ["block-padding"] }
|
||||||
block-padding = "0.3.3"
|
|
||||||
|
|||||||
62
sdgb-api/src/auth_lite/mod.rs
Normal file
62
sdgb-api/src/auth_lite/mod.rs
Normal file
@@ -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<str>,
|
||||||
|
) -> Result<Vec<u8>, 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<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 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::<Pkcs7>(&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::<Pkcs7>(data.as_mut())?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
pub mod title;
|
|
||||||
pub mod all_net;
|
pub mod all_net;
|
||||||
|
pub mod auth_lite;
|
||||||
|
pub mod title;
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
pub use error::ApiError;
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ use digest::generic_array::GenericArray;
|
|||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
use flate2::{Compression, read::ZlibDecoder};
|
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 {
|
impl MaiVersionExt for Sdgb1_40 {
|
||||||
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
fn decode(mut data: impl AsMut<[u8]>) -> Result<Vec<u8>, ApiError> {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ pub mod encryption;
|
|||||||
pub mod methods;
|
pub mod methods;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|
||||||
mod error;
|
use super::ApiError;
|
||||||
pub use error::ApiError;
|
|
||||||
use nyquest::{
|
use nyquest::{
|
||||||
AsyncClient, Body,
|
AsyncClient, Body,
|
||||||
r#async::Request,
|
r#async::Request,
|
||||||
|
|||||||
Reference in New Issue
Block a user