diff --git a/Cargo.lock b/Cargo.lock index 430c72a6..6c5ebad7 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "async-compression" version = "0.3.8" @@ -64,8 +75,11 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" name = "azalea-auth" version = "0.1.0" dependencies = [ + "aes", + "cfb8", "num-bigint", "rand", + "rsa_public_encrypt_pkcs1", "sha-1", "uuid", ] @@ -87,6 +101,7 @@ dependencies = [ name = "azalea-client" version = "0.1.0" dependencies = [ + "azalea-auth", "azalea-protocol", ] @@ -201,12 +216,41 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "cfb8" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "014c0a0e1ad0dae6a86c082db2f9bd7fe8c2c734227047d0d8b4d4a3a094a1e1" +dependencies = [ + "cipher", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "2.34.0" @@ -320,11 +364,12 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array", + "typenum", ] [[package]] @@ -535,6 +580,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -699,6 +753,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.3" @@ -710,6 +778,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -731,6 +808,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -971,6 +1071,17 @@ dependencies = [ "quick-error", ] +[[package]] +name = "rsa_public_encrypt_pkcs1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e9243a1f8b312c5535c09de102cc061416515201b194ee4f0a9a76da20ebf4" +dependencies = [ + "num", + "rand", + "simple_asn1", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -1059,6 +1170,18 @@ dependencies = [ "digest", ] +[[package]] +name = "simple_asn1" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" +dependencies = [ + "chrono", + "num-bigint", + "num-traits", + "thiserror", +] + [[package]] name = "slab" version = "0.4.5" diff --git a/azalea-auth/Cargo.toml b/azalea-auth/Cargo.toml index cb807776..5f62991b 100755 --- a/azalea-auth/Cargo.toml +++ b/azalea-auth/Cargo.toml @@ -6,7 +6,10 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +aes = "0.8.1" +cfb8 = "0.8.1" num-bigint = "^0.4.3" rand = {version = "^0.8.4", features = ["getrandom"]} +rsa_public_encrypt_pkcs1 = "0.4.0" sha-1 = "^0.10.0" uuid = "^0.8.2" diff --git a/azalea-auth/src/encryption.rs b/azalea-auth/src/encryption.rs index 334d8cb3..72739620 100644 --- a/azalea-auth/src/encryption.rs +++ b/azalea-auth/src/encryption.rs @@ -24,9 +24,28 @@ fn hex_digest(digest: &[u8]) -> String { num_bigint::BigInt::from_signed_bytes_be(digest).to_str_radix(16) } -fn encrypt(public_key: &[u8], server_id: String, nonce: &[u8]) { +pub struct EncryptResult { + pub encrypted_public_key: Vec, + pub encrypted_nonce: Vec, +} + +pub fn encrypt(public_key: &[u8], nonce: &[u8]) -> Result { + // On receipt of a Encryption Request from the server, the client will + // generate a random 16-byte shared secret, to be used with the AES/CFB8 + // stream cipher. let secret_key = generate_secret_key(); - let hash = hex_digest(&digest_data(server_id.as_bytes(), public_key, &secret_key)); + // let hash = hex_digest(&digest_data(server_id.as_bytes(), public_key, &secret_key)); + + // this.keybytes = Crypt.encryptUsingKey(publicKey, secretKey.getEncoded()); + // this.nonce = Crypt.encryptUsingKey(publicKey, arrby); + let encrypted_public_key: Vec = + rsa_public_encrypt_pkcs1::encrypt(&public_key, &secret_key)?; + let encrypted_nonce: Vec = rsa_public_encrypt_pkcs1::encrypt(&public_key, &nonce)?; + + Ok(EncryptResult { + encrypted_public_key, + encrypted_nonce, + }) } #[cfg(test)] diff --git a/azalea-client/Cargo.toml b/azalea-client/Cargo.toml index 7e22f727..5769f289 100755 --- a/azalea-client/Cargo.toml +++ b/azalea-client/Cargo.toml @@ -6,4 +6,5 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +azalea-auth = {path = "../azalea-auth"} azalea-protocol = {path = "../azalea-protocol"} diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs index 884648b4..b402200a 100755 --- a/azalea-client/src/connect.rs +++ b/azalea-client/src/connect.rs @@ -4,7 +4,10 @@ use azalea_protocol::{ packets::{ game::GamePacket, handshake::client_intention_packet::ClientIntentionPacket, - login::{serverbound_hello_packet::ServerboundHelloPacket, LoginPacket}, + login::{ + serverbound_hello_packet::ServerboundHelloPacket, + serverbound_key_packet::ServerboundKeyPacket, LoginPacket, + }, ConnectionProtocol, PROTOCOL_VERSION, }, resolver, ServerAddress, @@ -39,7 +42,15 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> { Ok(packet) => match packet { LoginPacket::ClientboundHelloPacket(p) => { println!("Got encryption request {:?} {:?}", p.nonce, p.public_key); - panic!(""); + let e = azalea_auth::encryption::encrypt(&p.public_key, &p.nonce).unwrap(); + conn.write( + ServerboundKeyPacket { + nonce: e.encrypted_nonce, + shared_secret: e.encrypted_public_key, + } + .get(), + ) + .await; } LoginPacket::ClientboundLoginCompressionPacket(p) => { println!("Got compression request {:?}", p.compression_threshold); @@ -58,6 +69,7 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> { LoginPacket::ClientboundCustomQueryPacket(p) => { println!("Got custom query {:?}", p); } + LoginPacket::ServerboundKeyPacket(_) => todo!(), }, Err(e) => { panic!("Error: {:?}", e); diff --git a/azalea-protocol/src/packets/login/mod.rs b/azalea-protocol/src/packets/login/mod.rs index ab68518c..93c1200f 100755 --- a/azalea-protocol/src/packets/login/mod.rs +++ b/azalea-protocol/src/packets/login/mod.rs @@ -4,6 +4,7 @@ pub mod clientbound_hello_packet; pub mod clientbound_login_compression_packet; pub mod clientbound_login_disconnect_packet; pub mod serverbound_hello_packet; +pub mod serverbound_key_packet; use packet_macros::declare_state_packets; @@ -11,10 +12,13 @@ declare_state_packets!( LoginPacket, Serverbound => { 0x00: serverbound_hello_packet::ServerboundHelloPacket, + 0x01: serverbound_key_packet::ServerboundKeyPacket, }, Clientbound => { // 0x00: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, - 26: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, + // for some reason this is used instead of 0x00?? + 0x1a: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, + 0x01: clientbound_hello_packet::ClientboundHelloPacket, 0x02: clientbound_game_profile_packet::ClientboundGameProfilePacket, 0x03: clientbound_login_compression_packet::ClientboundLoginCompressionPacket, diff --git a/azalea-protocol/src/packets/login/serverbound_hello_packet.rs b/azalea-protocol/src/packets/login/serverbound_hello_packet.rs index a72480f2..eb6a4065 100755 --- a/azalea-protocol/src/packets/login/serverbound_hello_packet.rs +++ b/azalea-protocol/src/packets/login/serverbound_hello_packet.rs @@ -1,27 +1,7 @@ +use packet_macros::LoginPacket; use std::hash::Hash; -use crate::mc_buf::Writable; - -use super::LoginPacket; - -#[derive(Hash, Clone, Debug)] +#[derive(Hash, Clone, Debug, LoginPacket)] pub struct ServerboundHelloPacket { pub username: String, } - -impl ServerboundHelloPacket { - pub fn get(self) -> LoginPacket { - LoginPacket::ServerboundHelloPacket(self) - } - - pub fn write(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - buf.write_utf(&self.username).unwrap(); - Ok(()) - } - - pub async fn read( - _buf: &mut T, - ) -> Result { - Err("ServerboundHelloPacket::read not implemented".to_string()) - } -} diff --git a/azalea-protocol/src/packets/login/serverbound_key_packet.rs b/azalea-protocol/src/packets/login/serverbound_key_packet.rs new file mode 100644 index 00000000..f402d357 --- /dev/null +++ b/azalea-protocol/src/packets/login/serverbound_key_packet.rs @@ -0,0 +1,10 @@ +use super::LoginPacket; +use crate::mc_buf::Writable; +use packet_macros::LoginPacket; +use std::hash::Hash; + +#[derive(Hash, Clone, Debug, LoginPacket)] +pub struct ServerboundKeyPacket { + pub shared_secret: Vec, + pub nonce: Vec, +}