mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-24 11:23:33 +00:00
Implement seed exchange algorithm for 2.7.50+
This commit is contained in:
parent
88657e7d11
commit
9dace4f236
@ -1,5 +1,10 @@
|
|||||||
|
use openssl::hash::MessageDigest;
|
||||||
|
use openssl::pkey::PKey;
|
||||||
|
use openssl::rsa::Padding;
|
||||||
|
use openssl::sign::Signer;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
|
|
||||||
@ -8,6 +13,7 @@ use crate::server::IpcMessage;
|
|||||||
use packet_processor_macro::*;
|
use packet_processor_macro::*;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
use packet_processor::*;
|
use packet_processor::*;
|
||||||
|
use crate::DispatchServer;
|
||||||
|
|
||||||
#[packet_processor(GetPlayerTokenReq)]
|
#[packet_processor(GetPlayerTokenReq)]
|
||||||
pub struct AuthManager {
|
pub struct AuthManager {
|
||||||
@ -33,15 +39,77 @@ impl AuthManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_get_player_token(&mut self, conv: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerTokenReq, rsp: &mut proto::GetPlayerTokenRsp) {
|
pub fn process_get_player_token(&mut self, conv: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerTokenReq, rsp: &mut proto::GetPlayerTokenRsp) {
|
||||||
let seed: u64 = 0x123456789ABCDEF0; // TODO: use real value!
|
let seed: u64 = 0xBABECAFEF00D; // TODO: use real value!
|
||||||
|
let client_hardcoded_seed: u64 = 0x12345678;
|
||||||
let uid = self.get_uid_by_account_id(req.account_uid.parse().unwrap());
|
let uid = self.get_uid_by_account_id(req.account_uid.parse().unwrap());
|
||||||
|
|
||||||
rsp.account_type = req.account_type;
|
rsp.account_type = req.account_type;
|
||||||
rsp.account_uid = req.account_uid.clone();
|
rsp.account_uid = req.account_uid.clone();
|
||||||
rsp.token = req.account_token.clone();
|
rsp.token = req.account_token.clone();
|
||||||
rsp.secret_key_seed = 0;//seed; // TODO: temporary workaround!
|
rsp.secret_key_seed = seed; // TODO: temporary workaround!
|
||||||
rsp.uid = uid;
|
rsp.uid = uid;
|
||||||
|
|
||||||
|
if req.unk4 > 0 { // TODO: detect client version properly!
|
||||||
|
// Versions 2.7.5x+ use different algorithm for key initialization
|
||||||
|
|
||||||
|
// TODO: as of now (2022-05-16) this algorithm here is more of a PoC, because we can't really sign the data
|
||||||
|
// or decrypt the client seed we're getting from the client.
|
||||||
|
//
|
||||||
|
// Connecting to our server still requires patching the client to disable signature verification and hardcoding
|
||||||
|
// some known client seed value. This will allow the patched client to connect to official servers (beware of
|
||||||
|
// the ban for modding the client!)
|
||||||
|
//
|
||||||
|
// An alternative approach to hardcoding the client seed would be to employ RCE in WindSeedClientNotify to extract
|
||||||
|
// the seed from the client itself. That still would require patching the client though (to allow invalid signatures),
|
||||||
|
// so it's of a very little difference to us.
|
||||||
|
//
|
||||||
|
// Another alternative is to replace keys inside global-metadata.dat file, but that requires writing an encryption
|
||||||
|
// tool. While still possible, it's tiresome, and won't allow patched client to connect to official server without
|
||||||
|
// switching back and forth between two versions of global-metadata.dat file.
|
||||||
|
|
||||||
|
let key_id = req.unk4 as u8;
|
||||||
|
|
||||||
|
let rsa_key_collection = DispatchServer::load_rsa_keys("RSAConfig");
|
||||||
|
let keys = match rsa_key_collection.get(&key_id) {
|
||||||
|
Some(keys) => keys,
|
||||||
|
None => panic!("Unknown key ID {}!", key_id),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decrypt received client seed
|
||||||
|
|
||||||
|
let client_seed_encrypted = base64::decode(&req.unk3).unwrap();
|
||||||
|
|
||||||
|
let mut dec_buf: Vec<u8> = vec![0; 256];
|
||||||
|
|
||||||
|
let client_seed = match keys.signing_key.private_decrypt(&client_seed_encrypted, &mut dec_buf, Padding::PKCS1) {
|
||||||
|
Ok(seed_size) => {
|
||||||
|
// Note: from_be_bytes here, because client seems to swap order of bytes for the seed
|
||||||
|
u64::from_be_bytes(dec_buf[0..seed_size].try_into().unwrap())
|
||||||
|
},
|
||||||
|
Err(e) => { // TODO: must panic here!
|
||||||
|
println!("Error decrypting client seed: {}", e);
|
||||||
|
client_hardcoded_seed // TODO: temporary workaround!
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encrypt server seed which we'll use in negotiating with the client
|
||||||
|
|
||||||
|
let mut enc_buf: Vec<u8> = vec![0; 256];
|
||||||
|
|
||||||
|
// Note: to_be_bytes here, because client seems to swap order of bytes for the seed
|
||||||
|
let seed_bytes = (seed ^ client_seed).to_be_bytes();
|
||||||
|
|
||||||
|
let len = keys.encrypt_key.public_encrypt(&seed_bytes, &mut enc_buf, Padding::PKCS1).unwrap();
|
||||||
|
|
||||||
|
// Sign it
|
||||||
|
let keypair = PKey::from_rsa(keys.signing_key.clone()).unwrap();
|
||||||
|
let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap();
|
||||||
|
let signature = signer.sign_oneshot_to_vec(&seed_bytes).unwrap();
|
||||||
|
|
||||||
|
rsp.unk5 = base64::encode(&enc_buf);
|
||||||
|
rsp.unk6 = base64::encode(&signature);
|
||||||
|
}
|
||||||
|
|
||||||
self.conv_to_user.insert(conv, uid);
|
self.conv_to_user.insert(conv, uid);
|
||||||
self.user_to_conv.insert(uid, conv);
|
self.user_to_conv.insert(uid, conv);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user