Skip to content

Commit

Permalink
g3proxy: use libcrypt to verify user password
Browse files Browse the repository at this point in the history
  • Loading branch information
zh-jq committed Nov 29, 2024
1 parent 8151ea2 commit 1ac2c68
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 229 deletions.
35 changes: 5 additions & 30 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,7 @@ bitflags = "2.4"
lru = { version = "0.12", default-features = false }
#
digest = "0.10.7"
md-5 = "0.10.0"
sha2 = "0.10.0"
sha-1 = "0.10.0"
blake3 = { version = "1.5", default-features = false }
hex = "0.4.2"
hex-literal = "0.4"
Expand Down Expand Up @@ -228,7 +226,7 @@ g3-tls-cert = { version = "0.5", path = "lib/g3-tls-cert" }
g3-tls-ticket = { version = "0.1", path = "lib/g3-tls-ticket" }
g3-types = { version = "0.5", path = "lib/g3-types" }
g3-udpdump = { version = "0.1", path = "lib/g3-udpdump" }
g3-xcrypt = { version = "0.1", path = "lib/g3-xcrypt" }
g3-xcrypt = { version = "0.2", path = "lib/g3-xcrypt" }
g3-yaml = { version = "0.5.0", path = "lib/g3-yaml" }

[profile.release-lto]
Expand Down
4 changes: 2 additions & 2 deletions g3proxy/src/config/auth/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ impl UserConfig {
match &self.password_token {
PasswordToken::Forbidden => false,
PasswordToken::SkipVerify => true,
PasswordToken::FastHash(fast_hash) => fast_hash.verify(password),
PasswordToken::XCrypt(xcrypt_hash) => xcrypt_hash.verify(password.as_bytes()),
PasswordToken::FastHash(fast_hash) => fast_hash.verify(password).unwrap(),
PasswordToken::XCrypt(xcrypt_hash) => xcrypt_hash.verify(password.as_bytes()).unwrap(),
}
}

Expand Down
5 changes: 1 addition & 4 deletions lib/g3-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ num-traits.workspace = true
arc-swap.workspace = true
fastrand = { workspace = true, optional = true }
governor = { workspace = true, features = ["std", "jitter"] }
digest = { workspace = true, optional = true }
md-5 = { workspace = true, optional = true }
sha-1 = { workspace = true, optional = true }
blake3 = { workspace = true, optional = true }
hex = { workspace = true, optional = true }
ip_network = { workspace = true, optional = true }
Expand All @@ -56,7 +53,7 @@ brotli = { version = "7.0", optional = true, default-features = false, features
[features]
default = []
quic = []
auth-crypt = ["dep:digest", "dep:md-5", "dep:sha-1", "dep:blake3", "dep:hex"]
auth-crypt = ["dep:openssl", "dep:blake3", "dep:hex"]
resolve = ["dep:radix_trie", "dep:fastrand"]
quinn = ["dep:quinn", "quic"]
rustls = ["dep:rustls", "dep:rustls-pki-types", "dep:webpki-roots", "dep:rustls-native-certs", "dep:lru"]
Expand Down
35 changes: 22 additions & 13 deletions lib/g3-types/src/auth/crypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
use std::cell::RefCell;

use anyhow::anyhow;
use digest::Digest;
use md5::Md5;
use sha1::Sha1;
use constant_time_eq::{constant_time_eq_16, constant_time_eq_n};
use openssl::error::ErrorStack;
use openssl::md::Md;
use openssl::md_ctx::MdCtx;

const SALT_LENGTH: usize = 8;
const MD5_LENGTH: usize = 16;
Expand All @@ -37,19 +38,27 @@ enum HashValue {
}

impl HashValue {
fn hash_match(&self, buf: &[u8]) -> bool {
fn hash_match(&self, buf: &[u8]) -> Result<bool, ErrorStack> {
match self {
HashValue::Md5(v) => {
let md5 = Md5::digest(buf);
v.eq(md5.as_slice())
let mut md = MdCtx::new()?;
md.digest_init(Md::md5())?;
md.digest_update(v)?;
let mut hash = [0; MD5_LENGTH];
md.digest_final(&mut hash)?;
Ok(constant_time_eq_16(v, &hash))
}
HashValue::Sha1(v) => {
let sha1 = Sha1::digest(buf);
v.eq(sha1.as_slice())
let mut md = MdCtx::new()?;
md.digest_init(Md::sha1())?;
md.digest_update(v)?;
let mut hash = [0; SHA1_LENGTH];
md.digest_final(&mut hash)?;
Ok(constant_time_eq_n(v, &hash))
}
HashValue::Blake3(v) => {
let b3 = blake3::hash(buf);
v.eq(&b3)
Ok(v.eq(&b3))
}
}
}
Expand Down Expand Up @@ -115,20 +124,20 @@ impl FastHashedPassPhrase {
Ok(())
}

pub fn verify(&self, pass: &str) -> bool {
pub fn verify(&self, pass: &str) -> Result<bool, ErrorStack> {
HASH_TL_BUF.with_borrow_mut(|buf| {
buf.extend_from_slice(pass.as_bytes());
buf.extend_from_slice(&self.salt);

let mut all_verified = true;
for hv in self.values.iter() {
if !hv.hash_match(buf.as_slice()) {
if !hv.hash_match(buf.as_slice())? {
all_verified = false;
break;
}
}
buf.clear();
all_verified
Ok(all_verified)
})
}

Expand All @@ -152,6 +161,6 @@ mod tests {
p.push_sha1("0b39e984b59251425245e81241aebf7dbe197cc3")
.unwrap();

assert!(p.verify("IQ5ZhanWaop2cw"));
assert!(p.verify("IQ5ZhanWaop2cw").unwrap());
}
}
7 changes: 3 additions & 4 deletions lib/g3-xcrypt/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "g3-xcrypt"
version = "0.1.0"
version = "0.2.0"
license.workspace = true
edition.workspace = true

Expand All @@ -9,6 +9,5 @@ edition.workspace = true
[dependencies]
thiserror.workspace = true
memchr.workspace = true
digest.workspace = true
md-5.workspace = true
sha2.workspace = true
openssl.workspace = true
constant_time_eq.workspace = true
11 changes: 7 additions & 4 deletions lib/g3-xcrypt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
* limitations under the License.
*/

use openssl::error::ErrorStack;

mod b64;

pub(crate) use b64::B64CryptDecoder;
pub use b64::B64CryptEncoder;

Expand Down Expand Up @@ -48,7 +51,7 @@ impl XCryptHash {
}
}

pub fn verify(&self, phrase: &[u8]) -> bool {
pub fn verify(&self, phrase: &[u8]) -> Result<bool, ErrorStack> {
match self {
XCryptHash::Md5(this) => this.verify(phrase),
XCryptHash::Sha256(this) => this.verify(phrase),
Expand All @@ -64,22 +67,22 @@ mod tests {
#[test]
fn md5() {
let crypt = XCryptHash::parse("$1$DDiGYGte$K/SAC4VvllDonGcP1EfaY1").unwrap();
assert!(crypt.verify("123456".as_bytes()));
assert!(crypt.verify("123456".as_bytes()).unwrap());
}

#[test]
fn sha256() {
let crypt =
XCryptHash::parse("$5$W9wFmTCpBILzJn18$X496nPJHVQ895fwotE3WPBLmxgxGD8ivpUhfmoKbtb7")
.unwrap();
assert!(crypt.verify("123456".as_bytes()));
assert!(crypt.verify("123456".as_bytes()).unwrap());
}

#[test]
fn sha512() {
let s = "$6$yeDpErl4xq9E2vKP$\
.reNyfNzRJyAJrlh38J1XGx/5QTfBy3IedVNdTqfWqSeZFPAbXzV85uNK9fdmXvGCxizHVcAiIoQ4uXMJWuB6/";
let crypt = XCryptHash::parse(s).unwrap();
assert!(crypt.verify("123456".as_bytes()));
assert!(crypt.verify("123456".as_bytes()).unwrap());
}
}
Loading

0 comments on commit 1ac2c68

Please sign in to comment.