From 31e721b6715ce0a163e4e81ce0252950b3f40a58 Mon Sep 17 00:00:00 2001 From: iHsin Date: Thu, 11 Apr 2024 08:21:49 +0800 Subject: [PATCH] remove boringssl (#364) --- Cargo.lock | 92 +-------- clash_lib/Cargo.toml | 8 +- clash_lib/build.rs | 1 + clash_lib/src/common/crypto.rs | 184 ++++++------------ .../src/proxy/vmess/vmess_impl/header.rs | 49 +++-- .../src/proxy/vmess/vmess_impl/stream.rs | 56 ++---- clash_lib/src/proxy/vmess/vmess_impl/user.rs | 66 ++----- 7 files changed, 135 insertions(+), 321 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6017f5365..40c27aa6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,26 +586,6 @@ dependencies = [ "which", ] -[[package]] -name = "bindgen" -version = "0.68.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" -dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.55", -] - [[package]] name = "bindgen" version = "0.69.4" @@ -739,31 +719,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "boring" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8259fc1ea91894a550190683fbcda307d1ef85f2875d93a2b1ab3cab58b62fea" -dependencies = [ - "bitflags 2.5.0", - "boring-sys", - "foreign-types", - "libc", - "once_cell", -] - -[[package]] -name = "boring-sys" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace69f2e0d89d2c5e0874efe47f46259ff794fe8cbddfca72132c817611ad471" -dependencies = [ - "bindgen 0.68.1", - "cmake", - "fs_extra", - "fslock", -] - [[package]] name = "boringtun" version = "0.6.0" @@ -1072,6 +1027,7 @@ dependencies = [ name = "clash_lib" version = "0.1.15" dependencies = [ + "aead", "aes", "aes-gcm", "anyhow", @@ -1082,8 +1038,6 @@ dependencies = [ "axum-macros", "base64 0.22.0", "bollard", - "boring", - "boring-sys", "boringtun", "brotli", "byteorder", @@ -1092,6 +1046,7 @@ dependencies = [ "chacha20poly1305", "chrono", "console-subscriber", + "const-fnv1a-hash", "crc32fast", "criterion", "ctor", @@ -1132,6 +1087,7 @@ dependencies = [ "rand", "regex", "register-count", + "ring-compat", "rustls 0.21.8", "rustls-pemfile", "security-framework", @@ -1168,15 +1124,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - [[package]] name = "coarsetime" version = "0.1.34" @@ -1253,6 +1200,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const-fnv1a-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" + [[package]] name = "const-oid" version = "0.9.6" @@ -2050,27 +2003,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", -] - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -2109,12 +2041,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "fsevent-sys" version = "4.1.0" diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index faf9e6d71..dfe7a277a 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -35,8 +35,6 @@ foreign-types-shared = "0.3.1" network-interface = "1.1.3" base64 = "0.22" uuid = { version = "1.8.0", features = ["v4", "fast-rng", "macro-diagnostics", "serde"] } -boring = "4.5.0" -boring-sys = "4.5.0" ip_network_table-deps-treebitmap = "0.5.0" once_cell = "1.18.0" @@ -54,11 +52,14 @@ brotli = "4.0.0" hmac = "0.12.1" sha1 = "0.10" sha2 = "0.10.8" -md-5 = "0.10.5" +md-5 = "0.10" chacha20poly1305 = "0.10" +aead = { version = "0.5.2", features = ["std"] } aes = "0.8.4" aes-gcm = "0.10" cfb-mode = "0.8.2" +const-fnv1a-hash = "1" + filetime = "0.2" axum = { version = "0.7", features = ["ws"] } tower-http = { version = "0.5.2", features = ["fs", "trace", "cors"] } @@ -89,6 +90,7 @@ rustls = { version = "0.21", features=["dangerous_configuration", "quic"] } rustls-pemfile = "1.0.4" webpki-roots = "0.25" dhcproto = "0.11" +ring-compat = { version = "0.8", features = ["aead"] } rand = "0.8" diff --git a/clash_lib/build.rs b/clash_lib/build.rs index 4c2fde659..7bc7594bf 100644 --- a/clash_lib/build.rs +++ b/clash_lib/build.rs @@ -1,4 +1,5 @@ fn main() { + println!("cargo:rerun-if-env-changed=CLASH_RS_CI"); if std::env::var("CLASH_RS_CI").is_ok() { println!("cargo::rustc-cfg=ci"); } diff --git a/clash_lib/src/common/crypto.rs b/clash_lib/src/common/crypto.rs index 10b32c640..e1c5e107e 100644 --- a/clash_lib/src/common/crypto.rs +++ b/clash_lib/src/common/crypto.rs @@ -1,10 +1,7 @@ -use std::ffi::CStr; - -use crate::Error; - use aes::cipher::{AsyncStreamCipher, KeyIvInit}; use aes_gcm::aes::cipher::Unsigned; use aes_gcm::{AeadInPlace, KeyInit}; +use anyhow::Ok; pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut [u8]) -> anyhow::Result<()> { match key.len() { @@ -42,126 +39,65 @@ pub fn aes_cfb_decrypt(key: &[u8], iv: &[u8], data: &mut [u8]) -> anyhow::Result } } -pub fn aes_gcm_seal( +pub fn aes_gcm_encrypt( key: &[u8], nonce: &[u8], - data: &[u8], - ad: Option<&[u8]>, + plaintext: &[u8], + associated_data: Option<&[u8]>, ) -> anyhow::Result> { - unsafe { - let ctx = boring_sys::EVP_AEAD_CTX_new( - match key.len() { - 16 => boring_sys::EVP_aead_aes_128_gcm(), - 24 => boring_sys::EVP_aead_aes_192_gcm(), - 32 => boring_sys::EVP_aead_aes_256_gcm(), - _ => anyhow::bail!("invalid key length"), - }, - key.as_ptr(), - key.len(), - boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as _, - ); - - let mut out = vec![0u8; data.len() + boring_sys::EVP_AEAD_MAX_OVERHEAD as usize]; - - let mut out_len = 0; - - let rv = boring_sys::EVP_AEAD_CTX_seal( - ctx, - out.as_mut_ptr(), - &mut out_len, - out.len(), - nonce.as_ptr(), - nonce.len(), - data.as_ptr(), - data.len(), - match ad { - Some(ad) => ad.as_ptr(), - None => std::ptr::null(), - }, - match ad { - Some(ad) => ad.len(), - None => 0, - }, - ); - - boring_sys::EVP_AEAD_CTX_free(ctx); - - return if rv != 1 { - Err(Error::Crypto( - CStr::from_ptr( - boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, - ) - .to_str() - .expect("openssl error string is not utf8") - .to_owned(), - ) - .into()) - } else { - out.truncate(out_len); - Ok(out) - }; + let mut buffer = Vec::with_capacity(plaintext.len() + 16); + buffer.append(&mut plaintext.to_vec()); + match key.len() { + 16 => { + let cipher = ring_compat::aead::Aes128Gcm::new_from_slice(key)?; + cipher.encrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + 32 => { + let cipher = ring_compat::aead::Aes256Gcm::new_from_slice(key)?; + cipher.encrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + _ => return Err(anyhow!("Illegal key size {}", key.len())), } + Ok(buffer) } -pub fn aes_gcm_open( +/// TODO +pub fn aes_gcm_decrypt( key: &[u8], nonce: &[u8], - data: &[u8], - ad: Option<&[u8]>, + ciphertext: &[u8], + associated_data: Option<&[u8]>, ) -> anyhow::Result> { - unsafe { - let ctx = boring_sys::EVP_AEAD_CTX_new( - match key.len() { - 16 => boring_sys::EVP_aead_aes_128_gcm(), - 24 => boring_sys::EVP_aead_aes_192_gcm(), - 32 => boring_sys::EVP_aead_aes_256_gcm(), - _ => anyhow::bail!("invalid key length"), - }, - key.as_ptr(), - key.len(), - boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as _, - ); - - let mut out = vec![0u8; data.len()]; - - let mut out_len = 0; - - let rv = boring_sys::EVP_AEAD_CTX_open( - ctx, - out.as_mut_ptr(), - &mut out_len, - out.len(), - nonce.as_ptr(), - nonce.len(), - data.as_ptr(), - data.len(), - match ad { - Some(ad) => ad.as_ptr(), - None => std::ptr::null(), - }, - match ad { - Some(ad) => ad.len(), - None => 0, - }, - ); - - boring_sys::EVP_AEAD_CTX_free(ctx); - - return if rv != 1 { - Err(Error::Crypto( - CStr::from_ptr( - boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, - ) - .to_str() - .expect("openssl error string is not utf8") - .to_owned(), - ) - .into()) - } else { - out.truncate(out_len); - Ok(out) - }; + let mut buffer = ciphertext.to_vec(); + match key.len() { + 16 => { + let cipher = ring_compat::aead::Aes128Gcm::new_from_slice(key)?; + cipher.decrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + 32 => { + let cipher = ring_compat::aead::Aes256Gcm::new_from_slice(key)?; + cipher.decrypt_in_place( + nonce.into(), + associated_data.unwrap_or_default(), + &mut buffer, + )?; + } + _ => return Err(anyhow!("Illegal key size {}", key.len())), } + buffer.shrink_to_fit(); + Ok(buffer) } pub trait AeadCipherHelper: AeadInPlace { @@ -214,9 +150,9 @@ impl AeadCipherHelper for chacha20poly1305::ChaCha20Poly1305 { #[cfg(test)] mod tests { - use crate::common::{crypto::aes_gcm_open, utils}; + use crate::common::{crypto::aes_gcm_decrypt, utils}; - use super::{aes_cfb_encrypt, aes_gcm_seal}; + use super::{aes_cfb_encrypt, aes_gcm_encrypt}; #[test] fn test_aes_cfb_256() { @@ -242,30 +178,26 @@ mod tests { #[test] fn test_aes_gcm_seal_ok() { let key = "1234567890123456".as_bytes(); - let nonce = "456".as_bytes(); + let nonce = "456456456456".as_bytes(); // it has to be 12 bytes let data = "789".as_bytes(); let ad = "abc".as_bytes(); - let encrypted = aes_gcm_seal(key, nonce, data, Some(ad)).expect("sealed"); + let encrypted = aes_gcm_encrypt(key, nonce, data, Some(ad)).expect("sealed"); - let decrypted = aes_gcm_open(key, nonce, &encrypted, Some(ad)).expect("opened"); + let decrypted = aes_gcm_decrypt(key, nonce, &encrypted, Some(ad)).expect("opened"); assert_eq!(decrypted, data); } #[test] fn test_aes_gcm_seal_fail() { let key = "1234567890123456".as_bytes(); - let nonce = "456".as_bytes(); + let nonce = "456456456456".as_bytes(); // it has to be 12 bytes let data = "789".as_bytes(); let ad = "abc".as_bytes(); - let encrypted = aes_gcm_seal(key, nonce, data, Some(ad)).expect("sealed"); + let encrypted = aes_gcm_encrypt(key, nonce, data, Some(ad)).expect("sealed"); let key2 = "1234567890123457".as_bytes(); - let decrypted = aes_gcm_open(key2, nonce, &encrypted, Some(ad)); + let decrypted = aes_gcm_decrypt(key2, nonce, &encrypted, Some(ad)); assert!(decrypted.is_err()); - assert_eq!( - decrypted.unwrap_err().to_string(), - "crypto error: BAD_DECRYPT" - ); } } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/header.rs b/clash_lib/src/proxy/vmess/vmess_impl/header.rs index 97d944b83..76c553d62 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/header.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/header.rs @@ -1,4 +1,6 @@ -use bytes::{BufMut, BytesMut}; +use aead::{generic_array::GenericArray, KeyInit}; +use aes::cipher::BlockEncrypt; +use bytes::{Buf, BufMut, BytesMut}; use crate::common::{crypto, errors::map_io_error, utils}; @@ -20,14 +22,15 @@ fn create_auth_id(cmd_key: [u8; 16], timestamp: u64) -> [u8; 16] { let zero = crc32fast::hash(buf.as_ref()); buf.put_u32(zero); - let mut aes_key = boring_sys::AES_KEY::default(); let pk = kdf::vmess_kdf_1_one_shot(&cmd_key[..], KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); - unsafe { - boring_sys::AES_set_encrypt_key(pk.as_ptr() as _, 128, &mut aes_key); - boring_sys::AES_encrypt(buf.as_mut_ptr() as _, buf.as_mut_ptr() as _, &aes_key); - } - - buf.freeze()[..16].try_into().unwrap() + let pk: [u8; 16] = pk[..16].try_into().unwrap(); // That's wired + let key = GenericArray::from(pk); + let cipher = aes::Aes128::new(&key); + let mut block = [0u8; 16]; + buf.copy_to_slice(&mut block); + let mut block = GenericArray::from(block); + cipher.encrypt_block(&mut block); + block.as_slice()[..16].try_into().unwrap() } pub(crate) fn seal_vmess_aead_header( @@ -52,7 +55,7 @@ pub(crate) fn seal_vmess_aead_header( &connection_nonce[..], )[..12]; - let header_len_encrypted = crypto::aes_gcm_seal( + let header_len_encrypted = crypto::aes_gcm_encrypt( payload_header_length_aead_key, payload_header_length_aead_nonce, (data.len() as u16).to_be_bytes().as_ref(), @@ -73,7 +76,7 @@ pub(crate) fn seal_vmess_aead_header( &connection_nonce[..], )[..12]; - let payload_encrypted = crypto::aes_gcm_seal( + let payload_encrypted = crypto::aes_gcm_encrypt( payload_header_aead_key, payload_header_aead_nonce, &data, @@ -92,8 +95,6 @@ pub(crate) fn seal_vmess_aead_header( #[cfg(test)] mod tests { - use bytes::{BufMut, BytesMut}; - use crate::{ common::crypto, proxy::vmess::vmess_impl::kdf::{ @@ -104,6 +105,9 @@ mod tests { KDF_SALT_CONST_VMESS_HEADER_PAYLOAD_LENGTH_AEAD_KEY, }, }; + use aead::{generic_array::GenericArray, KeyInit}; + use aes::cipher::BlockEncrypt; + use bytes::{Buf, BufMut, BytesMut}; #[test] fn test_create_auth_id() { @@ -119,15 +123,18 @@ mod tests { buf.put_u32(zero); let cmd_key = "1234567890123456".as_bytes(); - let mut aes_key = boring_sys::AES_KEY::default(); - let pk = kdf::vmess_kdf_1_one_shot(cmd_key, KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); - unsafe { - boring_sys::AES_set_encrypt_key(pk.as_ptr() as _, 128, &mut aes_key); - boring_sys::AES_encrypt(buf.as_mut_ptr() as _, buf.as_mut_ptr() as _, &aes_key); - } + let pk = kdf::vmess_kdf_1_one_shot(&cmd_key[..], KDF_SALT_CONST_AUTH_ID_ENCRYPTION_KEY); + let pk: [u8; 16] = pk[..16].try_into().unwrap(); // That's wired + let key = GenericArray::from(pk); + let cipher = aes::Aes128::new(&key); + let mut block = [0u8; 16]; + buf.copy_to_slice(&mut block); + let mut block = GenericArray::from(block); + cipher.encrypt_block(&mut block); + let block: [u8; 16] = block.as_slice()[..16].try_into().unwrap(); assert_eq!( - buf.freeze()[..16], + block.to_vec(), vec![55, 189, 144, 149, 192, 213, 241, 57, 37, 21, 179, 197, 135, 54, 86, 79] ); } @@ -152,7 +159,7 @@ mod tests { &connection_nonce[..], )[..12]; - let header_len_encrypted = crypto::aes_gcm_seal( + let header_len_encrypted = crypto::aes_gcm_encrypt( payload_header_length_aead_key, payload_header_length_aead_nonce, (data.len() as u16).to_be_bytes().as_ref(), @@ -173,7 +180,7 @@ mod tests { &connection_nonce[..], )[..12]; - let payload_encrypted = crypto::aes_gcm_seal( + let payload_encrypted = crypto::aes_gcm_encrypt( payload_header_aead_key, payload_header_aead_nonce, &data, diff --git a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs index 2fb919098..982b040ce 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs @@ -4,6 +4,8 @@ use aes_gcm::Aes128Gcm; use bytes::{BufMut, BytesMut}; use chacha20poly1305::ChaCha20Poly1305; use futures::ready; + +use md5::Md5; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadBuf}; use crate::{ @@ -23,7 +25,7 @@ use super::{ self, KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_IV, KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_KEY, KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_IV, KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_KEY, }, - user::{ID, ID_BYTES_LEN}, + user::ID, Security, CHUNK_SIZE, COMMAND_TCP, COMMAND_UDP, OPTION_CHUNK_STREAM, SECURITY_AES_128_GCM, SECURITY_CHACHA20_POLY1305, SECURITY_NONE, VERSION, }; @@ -225,6 +227,8 @@ where S: AsyncWrite + Unpin, { async fn send_handshake_request(&mut self) -> std::io::Result<()> { + use hmac::{Hmac, Mac}; + type HmacMd5 = Hmac; let Self { ref mut stream, ref req_body_key, @@ -246,21 +250,10 @@ where let mut mbuf = BytesMut::new(); if !is_aead { - let mut hash = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize]; - let mut out_len: u32 = 0; - - unsafe { - boring_sys::HMAC( - boring_sys::EVP_md5(), - id.uuid.as_bytes().as_ptr() as _, - ID_BYTES_LEN, - now.to_be_bytes().as_mut_ptr() as _, - 8, - &mut hash as _, - &mut out_len as _, - ); - } - mbuf.put_slice(&hash[..out_len as _]) + let mut mac = + HmacMd5::new_from_slice(id.uuid.as_bytes()).expect("key len expected to be 16"); + mac.update(now.to_be_bytes().as_slice()); + mbuf.put_slice(&mac.finalize().into_bytes()); } let mut buf = BytesMut::new(); @@ -289,10 +282,8 @@ where buf.put_slice(&padding); } - unsafe { - let sum = boring_sys::OPENSSL_hash32(buf.as_mut_ptr() as _, buf.len()); - buf.put_slice(sum.to_be_bytes().as_ref()); - } + let sum = const_fnv1a_hash::fnv1a_hash_32(&buf, None); + buf.put_slice(&sum.to_be_bytes()); if !is_aead { let mut data = buf.to_vec(); @@ -363,7 +354,7 @@ where KDF_SALT_CONST_AEAD_RESP_HEADER_LEN_IV, )[..12]; - let decrypted_response_header_len = crypto::aes_gcm_open( + let decrypted_response_header_len = crypto::aes_gcm_decrypt( aead_response_header_length_encryption_key, aead_response_header_length_encryption_iv, this.read_buf.split().as_ref(), @@ -402,7 +393,7 @@ where KDF_SALT_CONST_AEAD_RESP_HEADER_PAYLOAD_IV, )[..12]; - let buf = crypto::aes_gcm_open( + let buf = crypto::aes_gcm_decrypt( aead_response_header_payload_encryption_key, aead_response_header_payload_encryption_iv, this.read_buf.split().as_ref(), @@ -576,17 +567,12 @@ where } fn hash_timestamp(timestamp: u64) -> [u8; 16] { - unsafe { - let mut ctx = boring_sys::MD5_CTX::default(); - boring_sys::MD5_Init(&mut ctx); - - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - boring_sys::MD5_Update(&mut ctx, timestamp.to_be_bytes().as_ptr() as _, 8); - - let mut hash = [0u8; 16]; - boring_sys::MD5_Final(hash.as_mut_ptr() as _, &mut ctx); - hash - } + use md5::Digest; + let mut hasher = md5::Md5::new(); + // TODO Why four times? + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.update(timestamp.to_be_bytes()); + hasher.finalize().into() } diff --git a/clash_lib/src/proxy/vmess/vmess_impl/user.rs b/clash_lib/src/proxy/vmess/vmess_impl/user.rs index b9fa267a0..ae9a0d912 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/user.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/user.rs @@ -1,11 +1,9 @@ -use boring_sys::MD5_DIGEST_LENGTH; - -pub const ID_BYTES_LEN: usize = 16; +use md5::Digest; #[derive(Clone)] pub struct ID { pub uuid: uuid::Uuid, - pub cmd_key: [u8; MD5_DIGEST_LENGTH as _], + pub cmd_key: [u8; 16], } pub fn new_alter_id_list(primary: &ID, alter_id_count: u16) -> Vec { @@ -25,61 +23,23 @@ pub fn new_alter_id_list(primary: &ID, alter_id_count: u16) -> Vec { alter_id_list } +/// TODO docs pub fn new_id(uuid: &uuid::Uuid) -> ID { let uuid = uuid.to_owned(); - let mut cmd_key = [0u8; MD5_DIGEST_LENGTH as _]; - - let mut ctx = boring_sys::MD5_CTX::default(); - unsafe { - boring_sys::MD5_Init(&mut ctx as _); - boring_sys::MD5_Update( - &mut ctx as _, - uuid.as_bytes().as_ptr() as _, - uuid.as_bytes().len(), - ); - boring_sys::MD5_Update( - &mut ctx as _, - b"c48619fe-8f02-49e0-b9e9-edf763e17e21".as_ptr() as _, - 36, - ); - boring_sys::MD5_Final(cmd_key.as_mut_ptr() as _, &mut ctx as _); - } - + let mut hasher = md5::Md5::new(); + hasher.update(uuid.as_bytes()); + hasher.update(b"c48619fe-8f02-49e0-b9e9-edf763e17e21"); // What? + let cmd_key: [u8; 16] = hasher.finalize().into(); ID { uuid, cmd_key } } +/// TODO docs fn next_id(i: &uuid::Uuid) -> uuid::Uuid { - let mut ctx = boring_sys::MD5_CTX::default(); - unsafe { - boring_sys::MD5_Init(&mut ctx as _); - boring_sys::MD5_Update( - &mut ctx as _, - i.as_bytes().as_ptr() as _, - i.as_bytes().len(), - ); - boring_sys::MD5_Update( - &mut ctx as _, - b"16167dc8-16b6-4e6d-b8bb-65dd68113a81".as_ptr() as _, - 36, - ); - let mut buf = [0u8; MD5_DIGEST_LENGTH as _]; - /* - loop { - boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); - if i.as_bytes() != buf.as_slice() { - return uuid::Uuid::from_bytes(buf); - } - - boring_sys::MD5_Update( - &mut ctx as _, - b"533eff8a-4113-4b10-b5ce-0f5d76b98cd2".as_ptr() as _, - 36, - ); - } - */ - boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); - uuid::Uuid::from_bytes(buf) - } + let mut hasher = md5::Md5::new(); + hasher.update(i.as_bytes()); + hasher.update(b"16167dc8-16b6-4e6d-b8bb-65dd68113a81"); // Why? + let buf: [u8; 16] = hasher.finalize().into(); + uuid::Uuid::from_bytes(buf) } #[cfg(test)]