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::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use prost::Message;
|
||||
|
||||
@ -8,6 +13,7 @@ use crate::server::IpcMessage;
|
||||
use packet_processor_macro::*;
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
use crate::DispatchServer;
|
||||
|
||||
#[packet_processor(GetPlayerTokenReq)]
|
||||
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) {
|
||||
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());
|
||||
|
||||
rsp.account_type = req.account_type;
|
||||
rsp.account_uid = req.account_uid.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;
|
||||
|
||||
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.user_to_conv.insert(uid, conv);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user