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

80
Cargo.lock generated
View File

@@ -17,6 +17,17 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aligned-array"
version = "1.0.1"
@@ -101,6 +112,15 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
dependencies = [
"generic-array",
]
[[package]]
name = "block2"
version = "0.6.1"
@@ -122,6 +142,15 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]]
name = "cc"
version = "1.2.30"
@@ -157,6 +186,16 @@ dependencies = [
"windows-link",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "compio"
version = "0.15.0"
@@ -316,6 +355,24 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.15"
@@ -426,6 +483,16 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "flate2"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
@@ -574,6 +641,16 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "is-terminal"
version = "0.4.16"
@@ -1015,8 +1092,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
name = "sdgb-api"
version = "0.1.0"
dependencies = [
"aes",
"cbc",
"chrono",
"digest",
"flate2",
"hmac-sha256",
"nyquest",
"serde",

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;