mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 01:46:44 +08:00
fix(official): 修正官方 hash 校验算法
This commit is contained in:
@@ -77,8 +77,12 @@ fn parse_legacy_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainConfig,
|
||||
}
|
||||
|
||||
fn parse_game_main_config_json(value: &str) -> Result<YostarJpGameMainConfig, String> {
|
||||
serde_json::from_str(value)
|
||||
.map_err(|error| format!("Failed to parse decrypted GameMainConfig JSON: {error}"))
|
||||
let config: YostarJpGameMainConfig = serde_json::from_str(value)
|
||||
.map_err(|error| format!("Failed to parse decrypted GameMainConfig JSON: {error}"))?;
|
||||
if !game_main_config_has_known_field(&config) {
|
||||
return Err("Decrypted GameMainConfig JSON did not contain any known fields".to_string());
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn parse_obfuscated_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainConfig, String> {
|
||||
@@ -113,6 +117,13 @@ fn parse_obfuscated_game_main_config(bytes: &[u8]) -> Result<YostarJpGameMainCon
|
||||
})
|
||||
}
|
||||
|
||||
fn game_main_config_has_known_field(config: &YostarJpGameMainConfig) -> bool {
|
||||
config.skip_tutorial.is_some()
|
||||
|| config.language.is_some()
|
||||
|| config.default_connection_group.is_some()
|
||||
|| config.server_info_data_url.is_some()
|
||||
}
|
||||
|
||||
fn decrypt_inferred_ascii_json(bytes: &[u8]) -> Result<String, String> {
|
||||
if !bytes.len().is_multiple_of(2) {
|
||||
return Err("Obfuscated GameMainConfig byte length is not UTF-16LE aligned".to_string());
|
||||
@@ -362,9 +373,9 @@ fn round(acc: u32, input: u32) -> u32 {
|
||||
|
||||
fn avalanche(mut hash: u32) -> u32 {
|
||||
hash ^= hash >> 15;
|
||||
hash = hash.wrapping_mul(0x85EB_CA6B);
|
||||
hash = hash.wrapping_mul(0x85EB_CA77);
|
||||
hash ^= hash >> 13;
|
||||
hash = hash.wrapping_mul(0xC2B2_AE35);
|
||||
hash = hash.wrapping_mul(0xC2B2_AE3D);
|
||||
hash ^= hash >> 16;
|
||||
hash
|
||||
}
|
||||
@@ -616,6 +627,18 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_legacy_json_without_known_fields() {
|
||||
let error = parse_game_main_config_json(r#"{"unknown":"value"}"#).unwrap_err();
|
||||
|
||||
assert!(error.contains("did not contain any known fields"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uses_standard_xxhash32_seed_for_game_main_config_key() {
|
||||
assert_eq!(xxhash32(b"GameMainConfig"), 2131083068);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn extracts_game_main_config_bytes_from_serialized_assets() {
|
||||
|
||||
@@ -1684,9 +1684,9 @@ fn xxhash32_round(acc: u32, input: u32) -> u32 {
|
||||
|
||||
fn xxhash32_avalanche(mut hash: u32) -> u32 {
|
||||
hash ^= hash >> 15;
|
||||
hash = hash.wrapping_mul(0x85EB_CA6B);
|
||||
hash = hash.wrapping_mul(0x85EB_CA77);
|
||||
hash ^= hash >> 13;
|
||||
hash = hash.wrapping_mul(0xC2B2_AE35);
|
||||
hash = hash.wrapping_mul(0xC2B2_AE3D);
|
||||
hash ^= hash >> 16;
|
||||
hash
|
||||
}
|
||||
@@ -2148,8 +2148,8 @@ exit 22
|
||||
report.verified_hashes[0].algorithm,
|
||||
OfficialResourceHashAlgorithm::XxHash32Decimal
|
||||
);
|
||||
assert_eq!(report.verified_hashes[0].expected, "3223500437");
|
||||
assert_eq!(report.verified_hashes[0].actual, "3223500437");
|
||||
assert_eq!(report.verified_hashes[0].expected, "2044170421");
|
||||
assert_eq!(report.verified_hashes[0].actual, "2044170421");
|
||||
|
||||
let manifest = service.read_download_manifest().unwrap();
|
||||
assert_eq!(manifest.version, DOWNLOAD_MANIFEST_VERSION);
|
||||
@@ -2328,7 +2328,7 @@ exit 22
|
||||
let bytes = if url.ends_with("/TableBundles/TableCatalog.bytes") {
|
||||
b"ExcelDB.db".to_vec()
|
||||
} else if url.ends_with("/TableBundles/TableCatalog.hash") {
|
||||
b"3223500437".to_vec()
|
||||
b"2044170421".to_vec()
|
||||
} else if url.ends_with(".zip") {
|
||||
one_file_zip(b"fixture.txt", b"ok")
|
||||
} else {
|
||||
@@ -2514,9 +2514,11 @@ exit 22
|
||||
|
||||
#[test]
|
||||
fn verifies_known_real_seed_catalog_hash_samples() {
|
||||
assert_eq!(xxhash32(b"ExcelDB.db"), 3223500437);
|
||||
assert_eq!(xxhash32(b"FullPatch_000.zip"), 3628251239);
|
||||
assert_eq!(xxhash32(b"JP_Airi_Win.zip"), 876690720);
|
||||
assert_eq!(xxhash32(b""), 46947589);
|
||||
assert_eq!(xxhash32(b"ExcelDB.db"), 2044170421);
|
||||
assert_eq!(xxhash32(b"FullPatch_000.zip"), 4038880697);
|
||||
assert_eq!(xxhash32(b"JP_Airi_Win.zip"), 1416778215);
|
||||
assert_eq!(xxhash32(b"ExcelDB.db ExcelDB.db"), 2147704569);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -787,9 +787,9 @@ fn round(acc: u32, input: u32) -> u32 {
|
||||
|
||||
fn avalanche(mut hash: u32) -> u32 {
|
||||
hash ^= hash >> 15;
|
||||
hash = hash.wrapping_mul(0x85EB_CA6B);
|
||||
hash = hash.wrapping_mul(0x85EB_CA77);
|
||||
hash ^= hash >> 13;
|
||||
hash = hash.wrapping_mul(0xC2B2_AE35);
|
||||
hash = hash.wrapping_mul(0xC2B2_AE3D);
|
||||
hash ^= hash >> 16;
|
||||
hash
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user