mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
commit
dac943e3d7
17 changed files with 515 additions and 52 deletions
215
Cargo.lock
generated
215
Cargo.lock
generated
|
@ -8,6 +8,18 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-compression"
|
name = "async-compression"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -64,6 +76,12 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
name = "azalea-auth"
|
name = "azalea-auth"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"cfb8",
|
||||||
|
"num-bigint",
|
||||||
|
"rand",
|
||||||
|
"rsa_public_encrypt_pkcs1",
|
||||||
|
"sha-1",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -84,6 +102,7 @@ dependencies = [
|
||||||
name = "azalea-client"
|
name = "azalea-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"azalea-auth",
|
||||||
"azalea-protocol",
|
"azalea-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -141,6 +160,15 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bot"
|
name = "bot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -189,12 +217,40 @@ dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfb8"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3a4b6c43bf284e617a659ce5dc149676680530a3a4a9bb6b278d1a9ed5b229d"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.34.0"
|
version = "2.34.0"
|
||||||
|
@ -206,6 +262,15 @@ dependencies = [
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -297,6 +362,16 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.1.6"
|
version = "1.1.6"
|
||||||
|
@ -325,6 +400,17 @@ version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
@ -427,6 +513,16 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -648,6 +744,40 @@ dependencies = [
|
||||||
"winapi",
|
"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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"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]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -659,6 +789,39 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"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]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -684,6 +847,12 @@ version = "11.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packet-macros"
|
name = "packet-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -899,6 +1068,17 @@ dependencies = [
|
||||||
"quick-error",
|
"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]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -976,6 +1156,29 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha-1"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"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]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
|
@ -1150,6 +1353,12 @@ dependencies = [
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
|
@ -1201,6 +1410,12 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
|
|
@ -6,4 +6,10 @@ version = "0.1.0"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
aes = "0.7.4"
|
||||||
|
cfb8 = "0.7.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"
|
uuid = "^0.8.2"
|
||||||
|
|
94
azalea-auth/src/encryption.rs
Normal file
94
azalea-auth/src/encryption.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use aes::{
|
||||||
|
cipher::{AsyncStreamCipher, NewCipher},
|
||||||
|
Aes128,
|
||||||
|
};
|
||||||
|
use cfb8::Cfb8;
|
||||||
|
use rand::{rngs::OsRng, RngCore};
|
||||||
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
|
fn generate_secret_key() -> [u8; 16] {
|
||||||
|
let mut key = [0u8; 16];
|
||||||
|
OsRng.fill_bytes(&mut key);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn digest_data(server_id: &[u8], public_key: &[u8], private_key: &[u8]) -> Vec<u8> {
|
||||||
|
let mut digest = Sha1::new();
|
||||||
|
digest.update(server_id);
|
||||||
|
digest.update(public_key);
|
||||||
|
digest.update(private_key);
|
||||||
|
digest.finalize().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hex_digest(digest: &[u8]) -> String {
|
||||||
|
// Note that the Sha1.hexdigest() method used by minecraft is non standard.
|
||||||
|
// It doesn't match the digest method found in most programming languages
|
||||||
|
// and libraries. It works by treating the sha1 output bytes as one large
|
||||||
|
// integer in two's complement and then printing the integer in base 16,
|
||||||
|
// placing a minus sign if the interpreted number is negative.
|
||||||
|
num_bigint::BigInt::from_signed_bytes_be(digest).to_str_radix(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EncryptResult {
|
||||||
|
pub secret_key: [u8; 16],
|
||||||
|
pub encrypted_public_key: Vec<u8>,
|
||||||
|
pub encrypted_nonce: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encrypt(public_key: &[u8], nonce: &[u8]) -> Result<EncryptResult, String> {
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// this.keybytes = Crypt.encryptUsingKey(publicKey, secretKey.getEncoded());
|
||||||
|
// this.nonce = Crypt.encryptUsingKey(publicKey, arrby);
|
||||||
|
let encrypted_public_key: Vec<u8> =
|
||||||
|
rsa_public_encrypt_pkcs1::encrypt(&public_key, &secret_key)?;
|
||||||
|
let encrypted_nonce: Vec<u8> = rsa_public_encrypt_pkcs1::encrypt(&public_key, &nonce)?;
|
||||||
|
|
||||||
|
Ok(EncryptResult {
|
||||||
|
secret_key,
|
||||||
|
encrypted_public_key,
|
||||||
|
encrypted_nonce,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: update the aes and cfb8 crates
|
||||||
|
pub type Aes128Cfb = Cfb8<Aes128>;
|
||||||
|
|
||||||
|
pub fn create_cipher(key: &[u8]) -> Aes128Cfb {
|
||||||
|
Aes128Cfb::new_from_slices(&key, &key).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encrypt_packet(cipher: &mut Aes128Cfb, packet: &mut [u8]) {
|
||||||
|
cipher.encrypt(packet);
|
||||||
|
}
|
||||||
|
pub fn decrypt_packet(cipher: &mut Aes128Cfb, packet: &mut [u8]) {
|
||||||
|
cipher.decrypt(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_secret_key() {
|
||||||
|
let key = generate_secret_key();
|
||||||
|
assert_eq!(key.len(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hex_digest() {
|
||||||
|
let digest = hex_digest(&digest_data(b"Notch", &[], &[]));
|
||||||
|
assert_eq!(digest, "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
|
||||||
|
|
||||||
|
let digest = hex_digest(&digest_data(b"jeb_", &[], &[]));
|
||||||
|
assert_eq!(digest, "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
|
||||||
|
|
||||||
|
let digest = hex_digest(&digest_data(b"simon", &[], &[]));
|
||||||
|
assert_eq!(digest, "88e16a1019277b15d58faf0541e11910eb756f6");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
//! Handle Minecraft authentication.
|
//! Handle Minecraft authentication.
|
||||||
|
|
||||||
pub mod game_profile;
|
pub mod game_profile;
|
||||||
|
pub mod encryption;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,5 @@ version = "0.1.0"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
azalea-auth = {path = "../azalea-auth"}
|
||||||
azalea-protocol = {path = "../azalea-protocol"}
|
azalea-protocol = {path = "../azalea-protocol"}
|
||||||
|
|
|
@ -4,7 +4,10 @@ use azalea_protocol::{
|
||||||
packets::{
|
packets::{
|
||||||
game::GamePacket,
|
game::GamePacket,
|
||||||
handshake::client_intention_packet::ClientIntentionPacket,
|
handshake::client_intention_packet::ClientIntentionPacket,
|
||||||
login::{serverbound_hello_packet::ServerboundHelloPacket, LoginPacket},
|
login::{
|
||||||
|
serverbound_hello_packet::ServerboundHelloPacket,
|
||||||
|
serverbound_key_packet::ServerboundKeyPacket, LoginPacket,
|
||||||
|
},
|
||||||
ConnectionProtocol, PROTOCOL_VERSION,
|
ConnectionProtocol, PROTOCOL_VERSION,
|
||||||
},
|
},
|
||||||
resolver, ServerAddress,
|
resolver, ServerAddress,
|
||||||
|
@ -39,6 +42,20 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
|
||||||
Ok(packet) => match packet {
|
Ok(packet) => match packet {
|
||||||
LoginPacket::ClientboundHelloPacket(p) => {
|
LoginPacket::ClientboundHelloPacket(p) => {
|
||||||
println!("Got encryption request {:?} {:?}", p.nonce, p.public_key);
|
println!("Got encryption request {:?} {:?}", p.nonce, p.public_key);
|
||||||
|
let e = azalea_auth::encryption::encrypt(&p.public_key, &p.nonce).unwrap();
|
||||||
|
|
||||||
|
// TODO: authenticate with the server here (authenticateServer)
|
||||||
|
println!("Sending encryption response {:?}", e);
|
||||||
|
|
||||||
|
conn.write(
|
||||||
|
ServerboundKeyPacket {
|
||||||
|
nonce: e.encrypted_nonce.into(),
|
||||||
|
shared_secret: e.encrypted_public_key.into(),
|
||||||
|
}
|
||||||
|
.get(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
conn.set_encryption_key(e.secret_key);
|
||||||
}
|
}
|
||||||
LoginPacket::ClientboundLoginCompressionPacket(p) => {
|
LoginPacket::ClientboundLoginCompressionPacket(p) => {
|
||||||
println!("Got compression request {:?}", p.compression_threshold);
|
println!("Got compression request {:?}", p.compression_threshold);
|
||||||
|
@ -57,6 +74,7 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
|
||||||
LoginPacket::ClientboundCustomQueryPacket(p) => {
|
LoginPacket::ClientboundCustomQueryPacket(p) => {
|
||||||
println!("Got custom query {:?}", p);
|
println!("Got custom query {:?}", p);
|
||||||
}
|
}
|
||||||
|
LoginPacket::ServerboundKeyPacket(_) => todo!(),
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Error: {:?}", e);
|
panic!("Error: {:?}", e);
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::packets::status::StatusPacket;
|
||||||
use crate::read::read_packet;
|
use crate::read::read_packet;
|
||||||
use crate::write::write_packet;
|
use crate::write::write_packet;
|
||||||
use crate::ServerIpAddress;
|
use crate::ServerIpAddress;
|
||||||
|
use azalea_auth::encryption::Aes128Cfb;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
pub enum PacketFlow {
|
pub enum PacketFlow {
|
||||||
|
@ -25,6 +26,7 @@ pub struct GameConnection {
|
||||||
/// The buffered writer
|
/// The buffered writer
|
||||||
pub stream: TcpStream,
|
pub stream: TcpStream,
|
||||||
pub compression_threshold: Option<u32>,
|
pub compression_threshold: Option<u32>,
|
||||||
|
pub cipher: Option<Aes128Cfb>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StatusConnection {
|
pub struct StatusConnection {
|
||||||
|
@ -38,6 +40,7 @@ pub struct LoginConnection {
|
||||||
/// The buffered writer
|
/// The buffered writer
|
||||||
pub stream: TcpStream,
|
pub stream: TcpStream,
|
||||||
pub compression_threshold: Option<u32>,
|
pub compression_threshold: Option<u32>,
|
||||||
|
pub cipher: Option<Aes128Cfb>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HandshakeConnection {
|
impl HandshakeConnection {
|
||||||
|
@ -65,6 +68,7 @@ impl HandshakeConnection {
|
||||||
flow: self.flow,
|
flow: self.flow,
|
||||||
stream: self.stream,
|
stream: self.stream,
|
||||||
compression_threshold: None,
|
compression_threshold: None,
|
||||||
|
cipher: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,46 +80,69 @@ impl HandshakeConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read(&mut self) -> Result<HandshakePacket, String> {
|
pub async fn read(&mut self) -> Result<HandshakePacket, String> {
|
||||||
read_packet::<HandshakePacket, _>(&self.flow, &mut self.stream, None).await
|
read_packet::<HandshakePacket, _>(&self.flow, &mut self.stream, None, &mut None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a packet to the server
|
/// Write a packet to the server
|
||||||
pub async fn write(&mut self, packet: HandshakePacket) {
|
pub async fn write(&mut self, packet: HandshakePacket) {
|
||||||
write_packet(packet, &mut self.stream, None).await;
|
write_packet(packet, &mut self.stream, None, &mut None).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameConnection {
|
impl GameConnection {
|
||||||
pub async fn read(&mut self) -> Result<GamePacket, String> {
|
pub async fn read(&mut self) -> Result<GamePacket, String> {
|
||||||
read_packet::<GamePacket, _>(&self.flow, &mut self.stream, self.compression_threshold).await
|
read_packet::<GamePacket, _>(
|
||||||
|
&self.flow,
|
||||||
|
&mut self.stream,
|
||||||
|
self.compression_threshold,
|
||||||
|
&mut self.cipher,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a packet to the server
|
/// Write a packet to the server
|
||||||
pub async fn write(&mut self, packet: GamePacket) {
|
pub async fn write(&mut self, packet: GamePacket) {
|
||||||
write_packet(packet, &mut self.stream, self.compression_threshold).await;
|
write_packet(
|
||||||
|
packet,
|
||||||
|
&mut self.stream,
|
||||||
|
self.compression_threshold,
|
||||||
|
&mut self.cipher,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusConnection {
|
impl StatusConnection {
|
||||||
pub async fn read(&mut self) -> Result<StatusPacket, String> {
|
pub async fn read(&mut self) -> Result<StatusPacket, String> {
|
||||||
read_packet::<StatusPacket, _>(&self.flow, &mut self.stream, None).await
|
read_packet::<StatusPacket, _>(&self.flow, &mut self.stream, None, &mut None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a packet to the server
|
/// Write a packet to the server
|
||||||
pub async fn write(&mut self, packet: StatusPacket) {
|
pub async fn write(&mut self, packet: StatusPacket) {
|
||||||
write_packet(packet, &mut self.stream, None).await;
|
write_packet(packet, &mut self.stream, None, &mut None).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginConnection {
|
impl LoginConnection {
|
||||||
pub async fn read(&mut self) -> Result<LoginPacket, String> {
|
pub async fn read(&mut self) -> Result<LoginPacket, String> {
|
||||||
read_packet::<LoginPacket, _>(&self.flow, &mut self.stream, self.compression_threshold)
|
read_packet::<LoginPacket, _>(
|
||||||
.await
|
&self.flow,
|
||||||
|
&mut self.stream,
|
||||||
|
self.compression_threshold,
|
||||||
|
&mut self.cipher,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a packet to the server
|
/// Write a packet to the server
|
||||||
pub async fn write(&mut self, packet: LoginPacket) {
|
pub async fn write(&mut self, packet: LoginPacket) {
|
||||||
write_packet(packet, &mut self.stream, self.compression_threshold).await;
|
write_packet(
|
||||||
|
packet,
|
||||||
|
&mut self.stream,
|
||||||
|
self.compression_threshold,
|
||||||
|
&mut self.cipher,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_compression_threshold(&mut self, threshold: i32) {
|
pub fn set_compression_threshold(&mut self, threshold: i32) {
|
||||||
|
@ -127,11 +154,18 @@ impl LoginConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_encryption_key(&mut self, key: [u8; 16]) {
|
||||||
|
// minecraft has a cipher decoder and encoder, i don't think it matters though?
|
||||||
|
let cipher = azalea_auth::encryption::create_cipher(&key);
|
||||||
|
self.cipher = Some(cipher);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn game(self) -> GameConnection {
|
pub fn game(self) -> GameConnection {
|
||||||
GameConnection {
|
GameConnection {
|
||||||
flow: self.flow,
|
flow: self.flow,
|
||||||
stream: self.stream,
|
stream: self.stream,
|
||||||
compression_threshold: self.compression_threshold,
|
compression_threshold: self.compression_threshold,
|
||||||
|
cipher: self.cipher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,31 @@ mod write;
|
||||||
|
|
||||||
pub use read::{McBufReadable, McBufVarintReadable, Readable};
|
pub use read::{McBufReadable, McBufVarintReadable, Readable};
|
||||||
pub use write::{McBufVarintWritable, McBufWritable, Writable};
|
pub use write::{McBufVarintWritable, McBufWritable, Writable};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
// const DEFAULT_NBT_QUOTA: u32 = 2097152;
|
// const DEFAULT_NBT_QUOTA: u32 = 2097152;
|
||||||
const MAX_STRING_LENGTH: u16 = 32767;
|
const MAX_STRING_LENGTH: u16 = 32767;
|
||||||
// const MAX_COMPONENT_STRING_LENGTH: u32 = 262144;
|
// const MAX_COMPONENT_STRING_LENGTH: u32 = 262144;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ByteArray(Vec<u8>);
|
||||||
|
|
||||||
|
impl Deref for ByteArray {
|
||||||
|
type Target = Vec<u8>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for ByteArray {
|
||||||
|
fn from(vec: Vec<u8>) -> Self {
|
||||||
|
Self(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use azalea_core::{
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
use crate::mc_buf::ByteArray;
|
||||||
|
|
||||||
use super::MAX_STRING_LENGTH;
|
use super::MAX_STRING_LENGTH;
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ pub trait Readable {
|
||||||
async fn read_varint(&mut self) -> Result<i32, String>;
|
async fn read_varint(&mut self) -> Result<i32, String>;
|
||||||
fn get_varint_size(&mut self, value: i32) -> u8;
|
fn get_varint_size(&mut self, value: i32) -> u8;
|
||||||
fn get_varlong_size(&mut self, value: i32) -> u8;
|
fn get_varlong_size(&mut self, value: i32) -> u8;
|
||||||
async fn read_byte_array(&mut self) -> Result<Vec<u8>, String>;
|
async fn read_byte_array(&mut self) -> Result<ByteArray, String>;
|
||||||
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String>;
|
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String>;
|
||||||
async fn read_bytes(&mut self) -> Result<Vec<u8>, String>;
|
async fn read_bytes(&mut self) -> Result<Vec<u8>, String>;
|
||||||
async fn read_utf(&mut self) -> Result<String, String>;
|
async fn read_utf(&mut self) -> Result<String, String>;
|
||||||
|
@ -80,9 +81,9 @@ where
|
||||||
10
|
10
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_byte_array(&mut self) -> Result<Vec<u8>, String> {
|
async fn read_byte_array(&mut self) -> Result<ByteArray, String> {
|
||||||
let length = self.read_varint().await? as usize;
|
let length = self.read_varint().await? as usize;
|
||||||
Ok(self.read_bytes_with_len(length).await?)
|
Ok(ByteArray(self.read_bytes_with_len(length).await?))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String> {
|
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String> {
|
||||||
|
@ -251,6 +252,17 @@ impl McBufReadable for Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McBufReadable for ByteArray {
|
||||||
|
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
where
|
||||||
|
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||||
|
{
|
||||||
|
buf.read_byte_array().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl McBufReadable for String {
|
impl McBufReadable for String {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use super::MAX_STRING_LENGTH;
|
||||||
|
use crate::mc_buf::ByteArray;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use azalea_chat::component::Component;
|
use azalea_chat::component::Component;
|
||||||
use azalea_core::{
|
use azalea_core::{
|
||||||
|
@ -6,8 +8,6 @@ use azalea_core::{
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use super::MAX_STRING_LENGTH;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Writable {
|
pub trait Writable {
|
||||||
fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error>
|
fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error>
|
||||||
|
@ -193,6 +193,12 @@ impl McBufWritable for Vec<u8> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl McBufWritable for ByteArray {
|
||||||
|
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
buf.write_byte_array(&self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
impl McBufWritable for String {
|
impl McBufWritable for String {
|
||||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::mc_buf::Readable;
|
|
||||||
|
|
||||||
use super::LoginPacket;
|
use super::LoginPacket;
|
||||||
|
use crate::mc_buf::{ByteArray, Readable};
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
#[derive(Hash, Clone, Debug)]
|
||||||
pub struct ClientboundHelloPacket {
|
pub struct ClientboundHelloPacket {
|
||||||
pub server_id: String,
|
pub server_id: String,
|
||||||
pub public_key: Vec<u8>,
|
pub public_key: ByteArray,
|
||||||
pub nonce: Vec<u8>,
|
pub nonce: ByteArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientboundHelloPacket {
|
impl ClientboundHelloPacket {
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub mod clientbound_hello_packet;
|
||||||
pub mod clientbound_login_compression_packet;
|
pub mod clientbound_login_compression_packet;
|
||||||
pub mod clientbound_login_disconnect_packet;
|
pub mod clientbound_login_disconnect_packet;
|
||||||
pub mod serverbound_hello_packet;
|
pub mod serverbound_hello_packet;
|
||||||
|
pub mod serverbound_key_packet;
|
||||||
|
|
||||||
use packet_macros::declare_state_packets;
|
use packet_macros::declare_state_packets;
|
||||||
|
|
||||||
|
@ -11,10 +12,13 @@ declare_state_packets!(
|
||||||
LoginPacket,
|
LoginPacket,
|
||||||
Serverbound => {
|
Serverbound => {
|
||||||
0x00: serverbound_hello_packet::ServerboundHelloPacket,
|
0x00: serverbound_hello_packet::ServerboundHelloPacket,
|
||||||
|
0x01: serverbound_key_packet::ServerboundKeyPacket,
|
||||||
},
|
},
|
||||||
Clientbound => {
|
Clientbound => {
|
||||||
// 0x00: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket,
|
0x00: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket,
|
||||||
26: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket,
|
// sometimes this is used for some reason?
|
||||||
|
// 0x1a: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket,
|
||||||
|
|
||||||
0x01: clientbound_hello_packet::ClientboundHelloPacket,
|
0x01: clientbound_hello_packet::ClientboundHelloPacket,
|
||||||
0x02: clientbound_game_profile_packet::ClientboundGameProfilePacket,
|
0x02: clientbound_game_profile_packet::ClientboundGameProfilePacket,
|
||||||
0x03: clientbound_login_compression_packet::ClientboundLoginCompressionPacket,
|
0x03: clientbound_login_compression_packet::ClientboundLoginCompressionPacket,
|
||||||
|
|
|
@ -1,27 +1,7 @@
|
||||||
|
use packet_macros::LoginPacket;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::mc_buf::Writable;
|
#[derive(Hash, Clone, Debug, LoginPacket)]
|
||||||
|
|
||||||
use super::LoginPacket;
|
|
||||||
|
|
||||||
#[derive(Hash, Clone, Debug)]
|
|
||||||
pub struct ServerboundHelloPacket {
|
pub struct ServerboundHelloPacket {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerboundHelloPacket {
|
|
||||||
pub fn get(self) -> LoginPacket {
|
|
||||||
LoginPacket::ServerboundHelloPacket(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
|
||||||
buf.write_utf(&self.username).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>(
|
|
||||||
_buf: &mut T,
|
|
||||||
) -> Result<LoginPacket, String> {
|
|
||||||
Err("ServerboundHelloPacket::read not implemented".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
10
azalea-protocol/src/packets/login/serverbound_key_packet.rs
Normal file
10
azalea-protocol/src/packets/login/serverbound_key_packet.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use super::LoginPacket;
|
||||||
|
use crate::mc_buf::{ByteArray, Writable};
|
||||||
|
use packet_macros::LoginPacket;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
#[derive(Hash, Clone, Debug, LoginPacket)]
|
||||||
|
pub struct ServerboundKeyPacket {
|
||||||
|
pub shared_secret: ByteArray,
|
||||||
|
pub nonce: ByteArray,
|
||||||
|
}
|
|
@ -1,13 +1,17 @@
|
||||||
|
use std::{cell::Cell, pin::Pin};
|
||||||
|
|
||||||
use crate::{connect::PacketFlow, mc_buf::Readable, packets::ProtocolPacket};
|
use crate::{connect::PacketFlow, mc_buf::Readable, packets::ProtocolPacket};
|
||||||
use async_compression::tokio::bufread::ZlibDecoder;
|
use async_compression::tokio::bufread::ZlibDecoder;
|
||||||
|
use azalea_auth::encryption::Aes128Cfb;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
|
||||||
async fn frame_splitter<R>(stream: &mut R) -> Result<Vec<u8>, String>
|
async fn frame_splitter<R: ?Sized>(mut stream: &mut R) -> Result<Vec<u8>, String>
|
||||||
where
|
where
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||||
{
|
{
|
||||||
// Packet Length
|
// Packet Length
|
||||||
let length_result = stream.read_varint().await;
|
let length_result = stream.read_varint().await;
|
||||||
|
println!("length_result: {:?}", length_result);
|
||||||
match length_result {
|
match length_result {
|
||||||
Ok(length) => {
|
Ok(length) => {
|
||||||
let mut buf = vec![0; length as usize];
|
let mut buf = vec![0; length as usize];
|
||||||
|
@ -17,6 +21,8 @@ where
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
println!("buf: {:?}", buf);
|
||||||
|
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
Err(_) => Err("length wider than 21-bit".to_string()),
|
Err(_) => Err("length wider than 21-bit".to_string()),
|
||||||
|
@ -90,15 +96,61 @@ where
|
||||||
Ok(decoded_buf)
|
Ok(decoded_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_packet<P: ProtocolPacket, R>(
|
struct EncryptedStream<'a, R>
|
||||||
flow: &PacketFlow,
|
|
||||||
stream: &mut R,
|
|
||||||
compression_threshold: Option<u32>,
|
|
||||||
) -> Result<P, String>
|
|
||||||
where
|
where
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||||
{
|
{
|
||||||
let mut buf = frame_splitter(stream).await?;
|
cipher: Cell<&'a mut Option<Aes128Cfb>>,
|
||||||
|
stream: &'a mut Pin<&'a mut R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> AsyncRead for EncryptedStream<'_, R>
|
||||||
|
where
|
||||||
|
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||||
|
{
|
||||||
|
fn poll_read(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &mut tokio::io::ReadBuf<'_>,
|
||||||
|
) -> std::task::Poll<std::io::Result<()>> {
|
||||||
|
// i hate this
|
||||||
|
let polled = self.as_mut().stream.as_mut().poll_read(cx, buf);
|
||||||
|
match polled {
|
||||||
|
std::task::Poll::Ready(r) => {
|
||||||
|
println!("encrypted packet {:?}", buf.initialized_mut());
|
||||||
|
if let Some(cipher) = self.as_mut().cipher.get_mut() {
|
||||||
|
azalea_auth::encryption::decrypt_packet(cipher, buf.initialized_mut());
|
||||||
|
println!("decrypted packet {:?}", buf.initialized_mut());
|
||||||
|
}
|
||||||
|
match r {
|
||||||
|
Ok(()) => std::task::Poll::Ready(Ok(())),
|
||||||
|
Err(e) => panic!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::task::Poll::Pending => {
|
||||||
|
return std::task::Poll::Pending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read_packet<'a, P: ProtocolPacket, R>(
|
||||||
|
flow: &PacketFlow,
|
||||||
|
stream: &'a mut R,
|
||||||
|
compression_threshold: Option<u32>,
|
||||||
|
cipher: &mut Option<Aes128Cfb>,
|
||||||
|
) -> Result<P, String>
|
||||||
|
where
|
||||||
|
R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync,
|
||||||
|
{
|
||||||
|
// if we were given a cipher, decrypt the packet
|
||||||
|
let mut encrypted_stream = EncryptedStream {
|
||||||
|
cipher: Cell::new(cipher),
|
||||||
|
stream: &mut Pin::new(stream),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buf = frame_splitter(&mut encrypted_stream).await?;
|
||||||
|
|
||||||
if let Some(compression_threshold) = compression_threshold {
|
if let Some(compression_threshold) = compression_threshold {
|
||||||
buf = compression_decoder(&mut buf.as_slice(), compression_threshold).await?;
|
buf = compression_decoder(&mut buf.as_slice(), compression_threshold).await?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{mc_buf::Writable, packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSED_LENGTH};
|
use crate::{mc_buf::Writable, packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSED_LENGTH};
|
||||||
use async_compression::tokio::bufread::ZlibEncoder;
|
use async_compression::tokio::bufread::ZlibEncoder;
|
||||||
|
use azalea_auth::encryption::Aes128Cfb;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
|
@ -50,14 +51,22 @@ async fn compression_encoder(data: &[u8], compression_threshold: u32) -> Result<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write_packet<P>(packet: P, stream: &mut TcpStream, compression_threshold: Option<u32>)
|
pub async fn write_packet<P>(
|
||||||
where
|
packet: P,
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
compression_threshold: Option<u32>,
|
||||||
|
cipher: &mut Option<Aes128Cfb>,
|
||||||
|
) where
|
||||||
P: ProtocolPacket + std::fmt::Debug,
|
P: ProtocolPacket + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let mut buf = packet_encoder(&packet).unwrap();
|
let mut buf = packet_encoder(&packet).unwrap();
|
||||||
if let Some(threshold) = compression_threshold {
|
if let Some(threshold) = compression_threshold {
|
||||||
buf = compression_encoder(&buf, threshold).await.unwrap();
|
buf = compression_encoder(&buf, threshold).await.unwrap();
|
||||||
}
|
}
|
||||||
|
// if we were given a cipher, encrypt the packet
|
||||||
|
if let Some(cipher) = cipher {
|
||||||
|
azalea_auth::encryption::encrypt_packet(cipher, &mut buf);
|
||||||
|
}
|
||||||
buf = frame_prepender(&mut buf).unwrap();
|
buf = frame_prepender(&mut buf).unwrap();
|
||||||
stream.write_all(&buf).await.unwrap();
|
stream.write_all(&buf).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
0
bot/src/main.rs
Executable file → Normal file
0
bot/src/main.rs
Executable file → Normal file
Loading…
Add table
Reference in a new issue