From faafbcb7372c7ee9b7a54ff593b99966a3d579c3 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:04:42 +0000 Subject: [PATCH 1/4] Implement blake3 cryptographic hash verification for query string. --- Cargo.lock | 27 +++++++++++++++++++++++++++ Cargo.toml | 5 ++++- src/main.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fac439d..b701b52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,6 +256,12 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "arrayvec" version = "0.7.4" @@ -349,6 +355,20 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02bef9e74b5908bed0360844109a55b62b07cc973274c11d3a577bda8cc1cf60" +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "rayon", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -465,6 +485,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "convert_case" version = "0.4.0" @@ -1380,6 +1406,7 @@ name = "piped-proxy" version = "0.1.0" dependencies = [ "actix-web", + "blake3", "image", "libwebp-sys", "mimalloc", diff --git a/Cargo.toml b/Cargo.toml index 9eb7f35..4b9c254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,10 @@ rgb = { version = "0.8.37", optional = true } once_cell = "1.18.0" regex = "1.10.2" +blake3 = { version = "1.5.0", features = ["rayon"], optional = true } [features] -default = ["webp", "mimalloc", "reqwest-rustls"] +default = ["webp", "mimalloc", "reqwest-rustls", "qhash"] reqwest-rustls = ["reqwest/rustls-tls"] reqwest-native-tls = ["reqwest/default-tls"] @@ -37,5 +38,7 @@ mimalloc = ["dep:mimalloc"] optimized = ["libwebp-sys?/sse41", "libwebp-sys?/avx2", "libwebp-sys?/neon"] +qhash = ["blake3"] + [profile.release] lto = true diff --git a/src/main.rs b/src/main.rs index 3e50b9e..e6c879a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,6 +137,53 @@ async fn index(req: HttpRequest) -> Result> { // parse query string let query = QString::from(req.query_string()); + #[cfg(feature = "qhash")] + { + use std::collections::BTreeSet; + + let secret = env::var("HASH_SECRET"); + if let Ok(secret) = secret { + let qhash = query.get("qhash"); + + if qhash.is_none() { + return Err("No qhash provided".into()); + } + + let qhash = qhash.unwrap(); + + // check that qhash is valid + if qhash.len() != 8 { + return Err("Invalid qhash provided".into()); + } + + // store sorted key-value pairs + let mut set = BTreeSet::new(); + + query.to_pairs().iter().for_each(|(key, value)| { + if matches!(*key, "qhash" | "range" | "rewrite") { + return; + } + set.insert((key.as_bytes(), value.as_bytes())); + }); + + let mut hasher = blake3::Hasher::new(); + + for (key, value) in set { + hasher.update(key); + hasher.update(value); + } + + hasher.update(secret.as_bytes()); + + let hash = hasher.finalize().to_hex(); + let hash = &hash[..8]; + + if hash != qhash { + return Err("Invalid qhash provided".into()); + } + } + } + let res = query.get("host"); let res = res.map(|s| s.to_string()); From 2abd43bfb2805affce18c955934f489deb5f64b3 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:04:35 +0000 Subject: [PATCH 2/4] Make the hashing run on spawn_blocking. --- src/main.rs | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index e6c879a..94748ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -151,32 +151,39 @@ async fn index(req: HttpRequest) -> Result> { let qhash = qhash.unwrap(); - // check that qhash is valid if qhash.len() != 8 { return Err("Invalid qhash provided".into()); } - // store sorted key-value pairs + // Store sorted key-value pairs let mut set = BTreeSet::new(); - - query.to_pairs().iter().for_each(|(key, value)| { - if matches!(*key, "qhash" | "range" | "rewrite") { - return; + { + let pairs = query.to_pairs(); + for (key, value) in &pairs { + if matches!(*key, "qhash" | "range" | "rewrite") { + continue; + } + set.insert((key.as_bytes().to_owned(), value.as_bytes().to_owned())); } - set.insert((key.as_bytes(), value.as_bytes())); - }); - - let mut hasher = blake3::Hasher::new(); - - for (key, value) in set { - hasher.update(key); - hasher.update(value); } - hasher.update(secret.as_bytes()); + let (tx, rx) = oneshot::channel::(); + spawn_blocking(move || { + let mut hasher = blake3::Hasher::new(); - let hash = hasher.finalize().to_hex(); - let hash = &hash[..8]; + for (key, value) in set { + hasher.update(&key); + hasher.update(&value); + } + + hasher.update(secret.as_bytes()); + + let hash = hasher.finalize().to_hex(); + let hash = hash[..8].to_owned(); + tx.send(hash).unwrap(); + }); + + let hash = rx.await.unwrap(); if hash != qhash { return Err("Invalid qhash provided".into()); From 830363ca6400ea239410e72b520fc58e992f5958 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:14:26 +0000 Subject: [PATCH 3/4] Remove rayon feature. --- Cargo.lock | 1 - Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b701b52..8e400ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,7 +366,6 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "rayon", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4b9c254..1c14ffe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ rgb = { version = "0.8.37", optional = true } once_cell = "1.18.0" regex = "1.10.2" -blake3 = { version = "1.5.0", features = ["rayon"], optional = true } +blake3 = { version = "1.5.0", optional = true } [features] default = ["webp", "mimalloc", "reqwest-rustls", "qhash"] From 2aa3053d34881d767e3a4498e3da1bebf7f64da5 Mon Sep 17 00:00:00 2001 From: Kavin <20838718+FireMasterK@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:20:35 +0000 Subject: [PATCH 4/4] Remove use of channel. --- src/main.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 94748ef..7ab9180 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,8 +167,7 @@ async fn index(req: HttpRequest) -> Result> { } } - let (tx, rx) = oneshot::channel::(); - spawn_blocking(move || { + let hash = spawn_blocking(move || { let mut hasher = blake3::Hasher::new(); for (key, value) in set { @@ -180,10 +179,8 @@ async fn index(req: HttpRequest) -> Result> { let hash = hasher.finalize().to_hex(); let hash = hash[..8].to_owned(); - tx.send(hash).unwrap(); - }); - - let hash = rx.await.unwrap(); + hash + }).await.unwrap(); if hash != qhash { return Err("Invalid qhash provided".into());