chore: implement decryption of SDGB
This commit is contained in:
80
Cargo.lock
generated
80
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
4
sdgb-api/src/title/encryption/constants/mod.rs
Normal file
4
sdgb-api/src/title/encryption/constants/mod.rs
Normal 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";
|
||||
73
sdgb-api/src/title/encryption/mod.rs
Normal file
73
sdgb-api/src/title/encryption/mod.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
14
sdgb-api/src/title/error/mod.rs
Normal file
14
sdgb-api/src/title/error/mod.rs
Normal 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 }
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
pub mod encryption;
|
||||
mod error;
|
||||
|
||||
Reference in New Issue
Block a user