diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f301592..c371dab 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1096,6 +1096,7 @@ dependencies = [ name = "ezpplauncher" version = "3.0.0" dependencies = [ + "base64 0.21.7", "discord-rich-presence", "hardware-id", "md5", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index aa47ab8..1149d8b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,7 +39,8 @@ once_cell = "1.21.3" [target.'cfg(windows)'.dependencies] winreg = "0.55.0" -winapi = { version = "0.3", features = ["winuser"] } +winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] } +base64 = "0.21" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-single-instance = "2.3.0" diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 0d879d0..9979f37 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -307,3 +307,112 @@ pub async fn is_net8_installed() -> bool { Err(_) => false, } } + + +#[cfg(windows)] +pub fn encrypt_password(password: &str) -> Result { + use std::ptr; + use std::slice; + use winapi::shared::minwindef::{BYTE, DWORD, LPVOID}; + use winapi::um::dpapi::{CRYPTPROTECT_UI_FORBIDDEN, CryptProtectData}; + use winapi::um::winbase::LocalFree; + use winapi::um::wincrypt::DATA_BLOB; + use base64::{engine::general_purpose, Engine as _}; + + let password_bytes = password.as_bytes(); + let mut input_blob = DATA_BLOB { + cbData: password_bytes.len() as DWORD, + pbData: password_bytes.as_ptr() as *mut BYTE, + }; + + let mut output_blob = DATA_BLOB { + cbData: 0, + pbData: ptr::null_mut(), + }; + + let result = unsafe { + CryptProtectData( + &mut input_blob, + ptr::null(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + CRYPTPROTECT_UI_FORBIDDEN, + &mut output_blob, + ) + }; + + if result == 0 { + return Err("CryptProtectData failed".to_string()); + } + + let encrypted_data = + unsafe { slice::from_raw_parts(output_blob.pbData, output_blob.cbData as usize).to_vec() }; + + unsafe { + LocalFree(output_blob.pbData as LPVOID); + } + + let base64_string = general_purpose::STANDARD.encode(&encrypted_data); + + Ok(base64_string) +} + +#[cfg(windows)] +pub fn decrypt_password(encrypted_password_base64: &str) -> Result { + use std::ptr; + use std::slice; + use winapi::shared::minwindef::{BYTE, DWORD, LPVOID}; + use winapi::um::dpapi::{CRYPTPROTECT_UI_FORBIDDEN, CryptUnprotectData}; + use winapi::um::winbase::LocalFree; + use winapi::um::wincrypt::DATA_BLOB; + use base64::{engine::general_purpose, Engine as _}; + + // 1. Decode the Base64 string back into raw bytes + let encrypted_password_bytes = general_purpose::STANDARD.decode(encrypted_password_base64) + .map_err(|e| format!("Base64 decoding failed: {}", e))?; + + // 2. Prepare the input data structure + let mut input_blob = DATA_BLOB { + cbData: encrypted_password_bytes.len() as DWORD, + pbData: encrypted_password_bytes.as_ptr() as *mut BYTE, + }; + + // 3. Prepare the output data structure + let mut output_blob = DATA_BLOB { + cbData: 0, + pbData: ptr::null_mut(), + }; + + // 4. Call the Windows API function + let result = unsafe { + CryptUnprotectData( + &mut input_blob, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + CRYPTPROTECT_UI_FORBIDDEN, + &mut output_blob, + ) + }; + + // 5. Check the result + if result == 0 { + return Err("CryptUnprotectData failed".to_string()); + } + + // 6. Copy the decrypted data into a safe Rust Vec + let decrypted_bytes = unsafe { + slice::from_raw_parts(output_blob.pbData, output_blob.cbData as usize).to_vec() + }; + + // 7. Free the memory allocated by the Windows API + unsafe { + LocalFree(output_blob.pbData as LPVOID); + } + + // 8. Convert the decrypted bytes back to a UTF-8 string + String::from_utf8(decrypted_bytes) + .map_err(|e| format!("UTF-8 conversion failed: {}", e)) +}