extract authentication client v2
This commit is contained in:
parent
f9bf750b65
commit
e7fc40632d
@ -1,7 +1,6 @@
|
||||
use std::{collections::HashMap, net::IpAddr, sync::Arc};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use num_bigint::BigInt;
|
||||
use pumpkin_config::{auth::TextureConfig, ADVANCED_CONFIG};
|
||||
use pumpkin_core::ProfileAction;
|
||||
use pumpkin_protocol::Property;
|
||||
@ -93,15 +92,10 @@ pub fn unpack_textures(property: Property, config: &TextureConfig) -> Result<(),
|
||||
for texture in textures.textures {
|
||||
let url =
|
||||
Url::parse(&texture.1.url).map_err(|e| TextureError::InvalidURL(e.to_string()))?;
|
||||
is_texture_url_valid(url, config)?
|
||||
}
|
||||
is_texture_url_valid(url, config)? }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn auth_digest(bytes: &[u8]) -> String {
|
||||
BigInt::from_signed_bytes_be(bytes).to_str_radix(16)
|
||||
}
|
||||
|
||||
pub fn is_texture_url_valid(url: Url, config: &TextureConfig) -> Result<(), TextureError> {
|
||||
let scheme = url.scheme();
|
||||
if !config.allowed_url_schemes.contains(&scheme.to_string()) {
|
||||
|
||||
@ -6,7 +6,7 @@ use pumpkin_core::text::TextComponent;
|
||||
use pumpkin_protocol::{
|
||||
client::{
|
||||
config::{CConfigAddResourcePack, CFinishConfig, CKnownPacks, CRegistryData},
|
||||
login::{CEncryptionRequest, CLoginSuccess, CSetCompression},
|
||||
login::{CLoginSuccess, CSetCompression},
|
||||
status::{CPingResponse, CStatusResponse},
|
||||
},
|
||||
server::{
|
||||
@ -17,8 +17,6 @@ use pumpkin_protocol::{
|
||||
},
|
||||
ConnectionState, KnownPack, CURRENT_MC_PROTOCOL,
|
||||
};
|
||||
use rsa::Pkcs1v15Encrypt;
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
use crate::{
|
||||
client::authentication::{self, GameProfile},
|
||||
@ -27,10 +25,7 @@ use crate::{
|
||||
server::{Server, CURRENT_MC_VERSION},
|
||||
};
|
||||
|
||||
use super::{
|
||||
authentication::{auth_digest, unpack_textures},
|
||||
Client, EncryptionError, PlayerConfig,
|
||||
};
|
||||
use super::{authentication::unpack_textures, Client, PlayerConfig};
|
||||
|
||||
/// Processes incoming Packets from the Client to the Server
|
||||
/// Implements the `Client` Packets
|
||||
@ -101,14 +96,7 @@ impl Client {
|
||||
|
||||
// TODO: check config for encryption
|
||||
let verify_token: [u8; 4] = rand::random();
|
||||
let public_key_der = &server.public_key_der;
|
||||
let packet = CEncryptionRequest::new(
|
||||
"",
|
||||
public_key_der,
|
||||
&verify_token,
|
||||
BASIC_CONFIG.online_mode, // TODO
|
||||
);
|
||||
self.send_packet(&packet);
|
||||
self.send_packet(&server.encryption_request(&verify_token, BASIC_CONFIG.online_mode));
|
||||
}
|
||||
|
||||
pub async fn handle_encryption_response(
|
||||
@ -116,22 +104,15 @@ impl Client {
|
||||
server: &Arc<Server>,
|
||||
encryption_response: SEncryptionResponse,
|
||||
) {
|
||||
let shared_secret = server
|
||||
.private_key
|
||||
.decrypt(Pkcs1v15Encrypt, &encryption_response.shared_secret)
|
||||
.map_err(|_| EncryptionError::FailedDecrypt)
|
||||
.unwrap();
|
||||
let shared_secret = server.decrypt(&encryption_response.shared_secret).unwrap();
|
||||
|
||||
self.enable_encryption(&shared_secret)
|
||||
.unwrap_or_else(|e| self.kick(&e.to_string()));
|
||||
|
||||
let mut gameprofile = self.gameprofile.lock();
|
||||
|
||||
if BASIC_CONFIG.online_mode {
|
||||
let hash = Sha1::new()
|
||||
.chain_update(&shared_secret)
|
||||
.chain_update(&server.public_key_der)
|
||||
.finalize();
|
||||
let hash = auth_digest(&hash);
|
||||
let hash = server.digest_secret(&shared_secret);
|
||||
let ip = self.address.lock().ip();
|
||||
match authentication::authenticate(
|
||||
&gameprofile.as_ref().unwrap().name,
|
||||
@ -231,7 +212,7 @@ impl Client {
|
||||
id: "core",
|
||||
version: "1.21",
|
||||
}]));
|
||||
dbg!("login achnowlaged");
|
||||
dbg!("login acknowledged");
|
||||
}
|
||||
pub fn handle_client_information_config(
|
||||
&self,
|
||||
|
||||
74
pumpkin/src/server/bikeshed_key_store.rs
Normal file
74
pumpkin/src/server/bikeshed_key_store.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use num_bigint::BigInt;
|
||||
use pumpkin_protocol::client::login::CEncryptionRequest;
|
||||
use rsa::{traits::PublicKeyParts as _, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
|
||||
use sha1::Sha1;
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::client::EncryptionError;
|
||||
|
||||
pub struct BikeShedKeyStore {
|
||||
pub _public_key: RsaPublicKey,
|
||||
pub private_key: RsaPrivateKey,
|
||||
pub public_key_der: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl BikeShedKeyStore {
|
||||
pub fn new() -> Self {
|
||||
log::debug!("Creating encryption keys...");
|
||||
let (public_key, private_key) = Self::generate_keys();
|
||||
|
||||
let public_key_der = rsa_der::public_key_to_der(
|
||||
&private_key.n().to_bytes_be(),
|
||||
&private_key.e().to_bytes_be(),
|
||||
)
|
||||
.into_boxed_slice();
|
||||
BikeShedKeyStore {
|
||||
_public_key: public_key,
|
||||
private_key,
|
||||
public_key_der,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_keys() -> (RsaPublicKey, RsaPrivateKey) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let priv_key = RsaPrivateKey::new(&mut rng, 1024).expect("failed to generate a key");
|
||||
let pub_key = RsaPublicKey::from(&priv_key);
|
||||
(pub_key, priv_key)
|
||||
}
|
||||
|
||||
pub fn encryption_request<'a>(
|
||||
&'a self,
|
||||
server_id: &'a str,
|
||||
verification_token: &'a [u8; 4],
|
||||
should_authenticate: bool,
|
||||
) -> CEncryptionRequest<'_> {
|
||||
CEncryptionRequest::new(
|
||||
server_id,
|
||||
&self.public_key_der,
|
||||
verification_token,
|
||||
should_authenticate,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, EncryptionError> {
|
||||
let decrypted = self
|
||||
.private_key
|
||||
.decrypt(Pkcs1v15Encrypt, data)
|
||||
.map_err(|_| EncryptionError::FailedDecrypt)?;
|
||||
Ok(decrypted)
|
||||
}
|
||||
|
||||
pub fn get_digest(&self, secret: &[u8]) -> String {
|
||||
auth_digest(
|
||||
&Sha1::new()
|
||||
.chain_update(secret)
|
||||
.chain_update(&self.public_key_der)
|
||||
.finalize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auth_digest(bytes: &[u8]) -> String {
|
||||
BigInt::from_signed_bytes_be(bytes).to_str_radix(16)
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use bikeshed_key_store::BikeShedKeyStore;
|
||||
use image::GenericImageView;
|
||||
use mio::Token;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
@ -6,6 +7,7 @@ use pumpkin_config::{BasicConfiguration, BASIC_CONFIG};
|
||||
use pumpkin_core::GameMode;
|
||||
use pumpkin_entity::EntityId;
|
||||
use pumpkin_plugin::PluginLoader;
|
||||
use pumpkin_protocol::client::login::CEncryptionRequest;
|
||||
use pumpkin_protocol::{
|
||||
client::config::CPluginMessage, ClientPacket, Players, Sample, StatusResponse, VarInt, Version,
|
||||
CURRENT_MC_PROTOCOL,
|
||||
@ -25,8 +27,8 @@ use std::{
|
||||
use pumpkin_inventory::drag_handler::DragHandler;
|
||||
use pumpkin_inventory::{Container, OpenContainer};
|
||||
use pumpkin_registry::Registry;
|
||||
use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
use crate::client::EncryptionError;
|
||||
use crate::{
|
||||
client::Client,
|
||||
commands::{default_dispatcher, dispatcher::CommandDispatcher},
|
||||
@ -34,13 +36,11 @@ use crate::{
|
||||
world::World,
|
||||
};
|
||||
|
||||
mod bikeshed_key_store;
|
||||
pub const CURRENT_MC_VERSION: &str = "1.21.1";
|
||||
|
||||
pub struct Server {
|
||||
pub public_key: RsaPublicKey,
|
||||
pub private_key: RsaPrivateKey,
|
||||
pub public_key_der: Box<[u8]>,
|
||||
|
||||
key_store: BikeShedKeyStore,
|
||||
pub plugin_loader: PluginLoader,
|
||||
|
||||
pub command_dispatcher: Arc<CommandDispatcher<'static>>,
|
||||
@ -74,14 +74,7 @@ impl Server {
|
||||
let cached_server_brand = Self::build_brand();
|
||||
|
||||
// TODO: only create when needed
|
||||
log::debug!("Creating encryption keys...");
|
||||
let (public_key, private_key) = Self::generate_keys();
|
||||
|
||||
let public_key_der = rsa_der::public_key_to_der(
|
||||
&private_key.n().to_bytes_be(),
|
||||
&private_key.e().to_bytes_be(),
|
||||
)
|
||||
.into_boxed_slice();
|
||||
let key_store = BikeShedKeyStore::new();
|
||||
let auth_client = if BASIC_CONFIG.online_mode {
|
||||
Some(
|
||||
reqwest::Client::builder()
|
||||
@ -110,14 +103,12 @@ impl Server {
|
||||
// 0 is invalid
|
||||
entity_id: 2.into(),
|
||||
worlds: vec![Arc::new(world)],
|
||||
public_key,
|
||||
cached_server_brand,
|
||||
private_key,
|
||||
command_dispatcher: Arc::new(command_dispatcher),
|
||||
auth_client,
|
||||
key_store,
|
||||
status_response,
|
||||
status_response_json,
|
||||
public_key_der,
|
||||
auth_client,
|
||||
cached_server_brand,
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,6 +165,23 @@ impl Server {
|
||||
self.entity_id.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn encryption_request<'a>(
|
||||
&'a self,
|
||||
verification_token: &'a [u8; 4],
|
||||
should_authenticate: bool,
|
||||
) -> CEncryptionRequest<'_> {
|
||||
self.key_store
|
||||
.encryption_request("", verification_token, should_authenticate)
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, EncryptionError> {
|
||||
self.key_store.decrypt(data)
|
||||
}
|
||||
|
||||
pub fn digest_secret(&self, secret: &[u8]) -> String {
|
||||
self.key_store.get_digest(secret)
|
||||
}
|
||||
|
||||
pub fn build_brand() -> Vec<u8> {
|
||||
let brand = "Pumpkin";
|
||||
let mut buf = vec![];
|
||||
@ -233,12 +241,4 @@ impl Server {
|
||||
general_purpose::STANDARD.encode_string(image, &mut result);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn generate_keys() -> (RsaPublicKey, RsaPrivateKey) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let priv_key = RsaPrivateKey::new(&mut rng, 1024).expect("failed to generate a key");
|
||||
let pub_key = RsaPublicKey::from(&priv_key);
|
||||
(pub_key, priv_key)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user