chore: implement decryption of SDGB

This commit is contained in:
mokurin000
2025-07-29 21:36:19 +08:00
parent 097e332aa7
commit b61a724698
6 changed files with 176 additions and 1 deletions

View File

@@ -17,3 +17,6 @@ nyquest = { version = "0.2.0", features = ["async", "json"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.141"
flate2 = "1.1.2"
cbc = "0.1.2"
aes = "0.8.4"

View File

@@ -0,0 +1,4 @@
pub const SDGB_1_50_KEY: &[u8; 32] = b"a>32bVP7v<63BVLkY[xM>daZ1s9MBP<R";
pub const SDGB_1_50_IV: &[u8; 16] = b"d6xHIKq]1J]Dt^ue";
pub const SDGB_1_40_KEY: &[u8; 32] = b"n7bx6:@Fg_:2;5E89Phy7AyIcpxEQ:R@";
pub const SDGB_1_40_IV: &[u8; 16] = b";;KjR1C3hgB1ovXa";

View File

@@ -0,0 +1,73 @@
use std::io::Read;
use aes::cipher::{BlockDecryptMut, KeyIvInit, block_padding::Pkcs7};
use digest::generic_array::GenericArray;
use flate2::read::ZlibDecoder;
use crate::title::error::ApiError;
pub mod constants;
// type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
pub fn decompress(data: impl AsRef<[u8]>) -> Vec<u8> {
let mut buf = Vec::with_capacity(data.as_ref().len() * 2);
let mut decode = ZlibDecoder::new(data.as_ref());
_ = decode.read_to_end(&mut buf);
buf
}
pub fn decrypt<'ct>(
data: &'ct mut impl AsMut<[u8]>,
key: &[u8; 32],
iv: &[u8; 16],
) -> Result<&'ct [u8], ApiError> {
let key = GenericArray::from_slice(key);
let iv = GenericArray::from_slice(iv);
let decryptor = Aes256CbcDec::new(key, iv);
let result = decryptor.decrypt_padded_mut::<Pkcs7>(data.as_mut())?;
Ok(result)
}
#[cfg(test)]
mod _tests {
use crate::title::encryption::{constants::*, *};
#[test]
fn test_sdgb_140_dec() {
let data = [
120_u8, 156, 171, 77, 91, 233, 184, 108, 2, 71, 125, 142, 118, 135, 112, 181, 85, 217,
239, 243, 159, 153, 248, 98, 159, 185, 63, 43, 173, 106, 221, 115, 104, 105, 221, 107,
0, 241, 176, 16, 37,
];
let mut decompressed = decompress(data);
let data =
decrypt(&mut decompressed, SDGB_1_40_KEY, SDGB_1_40_IV).expect("decryption failed!");
assert_eq!(&data, br#"{"result":"Pong"}"#);
}
#[test]
fn test_sdgb_150_dec() {
let mut data = [
161, 166, 3, 157, 202, 233, 151, 73, 40, 113, 186, 162, 177, 46, 118, 113, 98, 231, 67,
185, 246, 180, 109, 253, 1, 152, 0, 31, 81, 211, 28, 137, 95, 12, 110, 105, 181, 246,
177, 1, 45, 59, 182, 113, 56, 97, 56, 100, 34, 168, 27, 51, 228, 77, 192, 194, 248, 45,
118, 80, 21, 159, 37, 248, 54, 85, 94, 61, 48, 59, 117, 163, 161, 165, 206, 36, 23, 71,
73, 231, 214, 81, 82, 117, 115, 32, 122, 8, 161, 213, 252, 125, 35, 131, 144, 147, 74,
27, 138, 26, 133, 240, 73, 197, 25, 173, 213, 237, 216, 76, 101, 210, 202, 172, 216,
91, 83, 87, 243, 79, 143, 42, 149, 130, 210, 13, 63, 98, 198, 165, 122, 58, 254, 39,
150, 71, 155, 231, 55, 142, 5, 102, 253, 148, 191, 9, 212, 188, 69, 236, 60, 152, 13,
40, 111, 219, 162, 160, 34, 150, 211, 85, 190, 176, 137, 60, 25, 228, 218, 163, 240,
143, 44, 238, 77, 92, 12, 166, 209, 238, 100, 92, 98, 142, 10, 104, 213, 12, 89, 236,
114, 212, 222, 0, 237, 1, 208, 216, 114, 114, 71, 135, 21, 213, 61, 6, 162, 155, 119,
143, 70, 83, 136, 136, 136, 251, 94, 137, 244, 26, 125, 15, 132, 207, 60, 57, 105, 78,
177, 84, 85, 152, 183, 77, 67, 163, 61, 165, 144, 125, 255, 89, 108, 58, 137, 142, 9,
8, 54, 228, 34, 55, 124, 158, 83, 36,
];
let decrypted = decrypt(&mut data, SDGB_1_50_KEY, SDGB_1_50_IV).expect("decryption failed");
let decompressed = decompress(decrypted);
assert_eq!(decompressed, r#"{"userId":10103750,"userName":"舞萌","isLogin":false,"lastGameId":null,"lastRomVersion":"1.01.00","lastDataVersion":"1.05.03","lastLoginDate":"1970-01-01 00:00:00","lastPlayDate":"1970-01-01 00:00:00","playerRating":1024,"nameplateId":0,"iconId":11,"trophyId":0,"isNetMember":1,"isInherit":false,"totalAwake":5,"dispRate":0,"dailyBonusDate":"1970-01-01 09:00:00","headPhoneVolume":null,"banState":0}"#.as_bytes())
}
}

View File

@@ -0,0 +1,14 @@
use aes::cipher::block_padding::UnpadError;
use snafu::Snafu;
#[derive(Debug, Snafu)]
pub enum ApiError {
#[snafu(display("unpad data: {error}"))]
UnpadError { error: UnpadError },
}
impl From<UnpadError> for ApiError {
fn from(error: UnpadError) -> Self {
Self::UnpadError { error }
}
}

View File

@@ -1 +1,2 @@
pub mod encryption;
mod error;